Tiling window manager——平铺式窗口管理器,不同于浮动式那样以层的形式管理窗口,平铺式将所有窗口平铺开来,窗口之间无缝对接,这有助于同时查看多个窗口的内容,对于程序员来说这尤其有用。
平铺式窗口管理器有很多,比较有名的像awesome,i3等等,不过awesome是以lua语言写的,我没用过,对此不做介绍。而qtile是以纯Python写的,作为一个Python迷(虽然海是菜鸟中的菜鸟),我自然选择qtile。
Qtile的官网:http://www.qtile.org
Qtile的图形对象(object graph)共七个部分:layouts、windows、screen、groups、bars、widgets还有一个root。
layouts:布局,以什么方式来分布窗口,包括Max(单窗口占据整个屏幕)、Tiling(按比例分配窗口)、Floationg(浮动窗口)、MonadTall(模拟XMonad的平铺式窗口)、Slice、Stack(将屏幕分成多个栈),TreeTab、Zoomy
groups:相当于其他桌面环境的工作区。
screens:物理屏幕
bar:栏,可以理解为任务栏
widget:小工具,组件,包括很多,像是时间,天气,邮件查看,任务列表,groupbox等等。。。
安装qtile的方法可以参考官网,不过我当时照着官网编译的时候提示错误,是一个ImportError,好像是说缺少某个模块,不过这个模块我没有找到。。。后来在google了一番后,找到如下的解决方法:
pip install cffi pip install xcffib git clone -b xcb https://github.com/flacjacket/cairocffi.git cd cairocffi && sudo python setup.py install git clone git://github.com/qtile/qtile.git cd qtile sudo python setup.py install
貌似是作者把几个模块编译到了一起。。。
关于配置文件的写法官网上提供了很多,既有默认配置,也有其他用户写的配置,可以借鉴后使用。之后我会给出我的配置,不过就是并不好。
详细的内容可以看官方文档,不过官方文档并不全面,很多配置都未提到。尤其是关于windows(窗口对象)方面的,除了官方默认配置外,其他用户的配置都用到了windows方面的内容。我谷歌、度娘了半天,一无所获(也可能是我查的方式不对)。看来可能要直接看源代码了。。。
刚才传了一下,好像不怎么好上传,现直接贴出配置文件:
#!/usr/bin/env python #-*-coding:utf-8-*- import os from libqtile import layout,widget,bar,manager,hook from libqtile.widget import base from libqtile.manager import Screen,Drag from libqtile.command import lazy try: from libqtile.manager import Key,Group except ImportError: from libqtile.config import Key,Group sup=‘mod4‘ alt=‘mod1‘ #键位映射 keys=[ #Layout Key([sup],‘Down‘,lazy.layout.down()), Key([sup],‘Up‘,lazy.layout.up()), Key([alt],‘Tab‘,lazy.layout.next()), Key([alt,‘shift‘],‘Tab‘,lazy.layout.previous()), Key([sup],‘space‘,lazy.nextlayout()), Key([sup],‘k‘,lazy.layout.increase_ratio()), Key([sup],‘j‘,lazy.layout.decrease_ratio()), Key([sup],‘l‘,lazy.layout.increase_nmaster()), Key([sup],‘h‘,lazy.layout.decrease_nmaster()), #Window Key([alt],‘F4‘,lazy.window.kill()), Key([alt],‘F10‘,lazy.window.toggle_maximize()), #Group Key([sup],‘Left‘,lazy.group.prevgroup()), Key([sup],‘Right‘,lazy.group.nextgroup()), #Application launchers Key([sup],‘Return‘,lazy.spawn(‘sakura‘)), Key([sup],‘f‘,lazy.spawn(‘firefox‘)), Key([sup],‘m‘,lazy.spawn(‘vlc‘)), Key([sup],‘v‘,lazy.spawn(‘virtualbox‘)), Key([sup],‘t‘,lazy.spawn(‘Thunar‘)), Key([sup],‘q‘,lazy.spawn(‘QQ‘)), Key([sup],‘z‘,lazy.spawn(‘zim‘)), #Audio Key([sup],‘F8‘,lazy.spawn(‘amixer --quiet set Master mute‘)), Key([sup],‘F9‘,lazy.spawn(‘amixer --quiet set Master unmute‘)), Key([alt],‘minus‘,lazy.spawn(‘amixer --quiet set Master 2dB-‘)), Key([alt,‘shift‘],‘equal‘,lazy.spawn(‘amixer --quiet set Master 2dB+‘)), #restart qtile Key([sup],‘r‘,lazy.restart()), #shutdown Key([sup,‘shift‘],‘q‘,lazy.spawn(‘shutdown -h now‘)), #interact with prompts: Key([sup],‘s‘,lazy.spawncmd()), ] mouse=[ Drag([sup],"Button1",lazy.window.set_position_floating(), start=lazy.window.get_position()), Drag([sup],"Button3",lazy.window.set_size_floating(), start=lazy.window.get_size()), ] #建立groups group_names=[ ("code1",{‘layout‘:‘tile‘}), ("code2",{"layout":‘tile‘}), ("web",{"layout":"max"}), ("vbox",{"layout":"max"}), (‘music‘,{‘layout‘:‘max‘}), (‘doc‘,{‘layout‘:‘max‘}), (‘chat‘,{‘layout‘:‘max‘}) ] groups=[Group(name,**kwargs) for name,kwargs in group_names] for i , (name,kwargs) in enumerate(group_names,1): keys.append(Key([sup],str(i),lazy.group[name].toscreen())) keys.append(Key([sup,‘shift‘],str(i),lazy.window.togroup(name))) #建立layouts layouts=[ layout.Tile(border_focus=‘#196ff2‘,border_width=1), layout.Max() ] font=‘WenQuanYi Micro Hei‘ fontsize=16 foreground=‘#FFFFFF‘ background=‘#000000‘ def humanize_bytes(value): suff=[‘B‘,‘K‘,‘M‘,‘G‘,‘T‘] while value > 1024. and len(suff)>1: value/=1024. suff.pop(0) return "% 3s%s" %(‘%.3s‘%value,suff[0]) #本来这个是用来显示CPU、Mem、Net的情况,后来不知为何无法显示 class Metrics(base._TextBox): defaults=[ (‘font‘,‘Arial‘,‘Metrics font‘), (‘fontsize‘,None,‘Metircs pixel size‘), (‘pading‘,None,‘Metrics padding‘), (‘background‘,‘00000‘,‘background color‘), (‘foreground‘,‘ffffff‘,‘foreground color‘) ] def __init__(self,**kwargs): base._TextBox.__init__(self,**kwargs) self.cpu_usage,self.cpu_total=self.get_cpu_stat() self.interfaces={} self.idle_ifaces={} def _configure(self,qtile,bar): base._TextBox._configure(self,qtile,bar) self.timeout_add(0,self._update) def get_cpu_stat(self): stat=[int(i) for i in open(‘/proc/stat‘).readline().split()[1:]] return sum(stat[:3]),sum(stat) def get_cpu_usage(self): new_cpu_usage,new_cput_total=self.get_cpu_stat() cput_usage=new_cpu_usage-self.cpu_usage cpu_total=new_cpu_total-self.cpu_total self.cpu_usage=new_cpu_usage self.cpu_tptal=new_cpu_total return ‘Cpu: %d%%‘ % (float(cpu_usage)/float(cpu_total)*100.) def get_mem_usage(self): info={} for line in open(‘/proc/meminfo‘): key,val=line.split(‘:‘) info[key]=int(val.spilt()[0]) mem=info[‘MemTotal‘] mem-=info[‘MemFree‘] mem-=info[‘Buffers‘] mem-=info[‘Cached‘] return ‘Mem: %d%%‘ % (float(mem)/float(info[‘MemTotal‘])*100) def get_net_usage(self): interfaces=[] basedir=‘/sys/class/net‘ for iface in os.listdir(basedir): j=os.path.join ifacedir=j(basedir,iface) statdir=j(ifacedir,‘statistics‘) idle=iface in self.idle_ifaces try: if int(open(j(ifacedir, ‘carrier‘)).read()): rx = int(open(j(statdir, ‘rx_bytes‘)).read()) tx = int(open(j(statdir, ‘tx_bytes‘)).read()) if iface not in self.interfaces: self.interfaces[iface] = (rx, tx) old_rx, old_tx = self.interfaces[iface] self.interfaces[iface] = (rx, tx) rx = rx - old_rx tx = tx - old_tx if rx or tx: idle = False self.idle_ifaces[iface] = 0 rx = humanize_bytes(rx) tx = humanize_bytes(tx) interfaces.append(‘%s: %s / %s‘ % (iface, rx, tx)) except: pass if idle: interfaces.append(‘%s: %-11s‘ % (iface, ("%ds idle" % self.idle_ifaces[iface])) ) self.idle_ifaces[iface] += 1 if self.idle_ifaces[iface] > 30: del self.idle_ifaces[iface] return " | ".join(interfaces) def _update(self): self.update() self.timeout_add(1, self.update) return False def update(self): stat = [self.get_cpu_usage(), self.get_mem_usage()] net = self.get_net_usage() if net: stat.append(net) self.text = " | ".join(stat) self.bar.draw() return True screens=[ Screen(top=bar.Bar([ widget.TextBox(text=‘◤ ‘,fontsize=40,foreground=‘#323335‘,padding=0), widget.GroupBox(font=font,fontsize=fontsize,active=foreground,inactive="#808080",borderwidth=3), widget.Prompt(font=font,fontsize=fontsize), widget.CurrentLayout(font=font,foreground=foreground,fontsize=fontsize), widget.Sep(foreground=background,linewidth=3), widget.WindowName(font=font,fontsize=fontsize,foreground=foreground), widget.Notify(font=font,fontsize=fontsize), Metrics(font=font,fontsize=fontsize,foreground=foreground), widget.Volume(foreground="#70ff70"), widget.BatteryIcon(), widget.Systray(icon_size=18), widget.Clock(font=font,fontsize=fontsize,foreground=foreground,fmt=‘%Y-%m-%d %a %H:%M‘), ],30)) ] @hook.subscribe.client_new def dialogs(window): if(window.window.get_wm_type() == ‘dialog‘ or window.window.get_wm_transient_for()): window.floating = True