wmiirc.py (11618B)
1 import datetime 2 import operator 3 import os 4 import re 5 import sys 6 import traceback 7 from threading import Thread, Timer 8 9 import pygmi 10 from pygmi import * 11 from pygmi import event 12 13 identity = lambda k: k 14 15 # Begin Configuration 16 # 17 # Note: This file loads ~/.wmii/wmiirc_local.py if it exists. 18 # Configuration should be placed in that file, and this file 19 # left unmodified, if possible. wmiirc_local should import 20 # wmiirc or any other modules it needs. 21 # 22 # Do *not* copy this file to wmiirc_local.py lest you want it 23 # executed twice. 24 25 # Keys 26 keys.defs = dict( 27 mod='Mod4', 28 left='h', 29 down='j', 30 up='k', 31 right='l') 32 33 # Bars 34 noticetimeout=5 35 noticebar=('right', '!notice') 36 37 # Theme 38 background = '#333333' 39 floatbackground='#222222' 40 41 wmii['font'] = 'drift,-*-fixed-*-*-*-*-9-*-*-*-*-*-*-*' 42 wmii['normcolors'] = '#000000', '#c1c48b', '#81654f' 43 wmii['focuscolors'] = '#000000', '#81654f', '#000000' 44 wmii['grabmod'] = keys.defs['mod'] 45 wmii['border'] = 2 46 47 def setbackground(color): 48 call('xsetroot', '-solid', color, background=True) 49 setbackground(background) 50 51 terminal = 'wmiir', 'setsid', '@TERMINAL@' 52 pygmi.shell = os.environ.get('SHELL', 'sh') 53 tray = 'witray', 54 55 @defmonitor 56 def load(self): 57 return wmii.cache['normcolors'], re.sub(r'^.*: ', '', call('uptime')).replace(', ', ' ') 58 @defmonitor 59 def time(self): 60 return wmii.cache['focuscolors'], datetime.datetime.now().strftime('%c') 61 62 wmii.rules = ( 63 # Apps with system tray icons like to their main windows 64 # Give them permission. 65 (ur'^Pidgin:', dict(allow='+activate')), 66 67 # MPlayer and VLC don't float by default, but should. 68 (ur'MPlayer|VLC', dict(floating=True)), 69 70 # ROX puts all of its windows in the same group, so they open 71 # with the same tags. Disable grouping for ROX Filer. 72 (ur'^ROX-Filer:', dict(group=0)), 73 ) 74 75 def unresponsive_client(client): 76 msg = 'The following client is not responding. What would you like to do?' 77 resp = call('wihack', '-transient', str(client.id), 78 'xmessage', '-nearmouse', '-buttons', 'Kill,Wait', '-print', 79 '%s\n %s' % (msg, client.label)) 80 if resp == 'Kill': 81 client.slay() 82 83 # End Configuration 84 85 client.awrite('/event', 'Start wmiirc') 86 87 tags = Tags() 88 events.bind({ 89 ('Quit', Match('Start', 'wmiirc')): lambda *a: sys.exit(), 90 'CreateTag': tags.add, 91 'DestroyTag': tags.delete, 92 'FocusTag': tags.focus, 93 'UnfocusTag': tags.unfocus, 94 'UrgentTag': lambda args: tags.set_urgent(args.split()[1], True), 95 'NotUrgentTag': lambda args: tags.set_urgent(args.split()[1], False), 96 97 'AreaFocus': lambda args: (args == '~' and 98 (setbackground(floatbackground), True) or 99 setbackground(background)), 100 101 'Unresponsive': lambda args: Thread(target=unresponsive_client, 102 args=(Client(args),)).start(), 103 104 'Notice': lambda args: notice.show(args), 105 106 Match(('LeftBarClick', 'LeftBarDND'), 1): lambda e, b, tag: tags.select(tag), 107 Match('LeftBarClick', 4): lambda *a: tags.select(tags.next(True)), 108 Match('LeftBarClick', 5): lambda *a: tags.select(tags.next()), 109 110 Match('LeftBarMouseDown', 3): lambda e, n, tag: clickmenu(( 111 ('Delete', lambda t: Tag(t).delete()), 112 ), (tag,)), 113 Match('ClientMouseDown', _, 3): lambda e, client, n: clickmenu(( 114 ('Delete', lambda c: Client(c).kill()), 115 ('Kill', lambda c: Client(c).slay()), 116 ('Fullscreen', lambda c: Client(c).set('Fullscreen', 'on')), 117 ), (client,)), 118 119 Match('ClientClick', _, 4): lambda e, c, n: Tag('sel').select('up'), 120 Match('ClientClick', _, 5): lambda e, c, n: Tag('sel').select('down'), 121 }) 122 123 @apply 124 class Actions(event.Actions): 125 def rehash(self, args=''): 126 program_menu.choices = program_list(os.environ['PATH'].split(':')) 127 def showkeys(self, args=''): 128 message(keys.help) 129 def quit(self, args=''): 130 wmii.ctl('quit') 131 def eval_(self, args=''): 132 exec args 133 def exec_(self, args=''): 134 wmii['exec'] = args 135 def exit(self, args=''): 136 client.awrite('/event', 'Quit') 137 138 program_menu = Menu(histfile='%s/history.progs' % confpath[0], nhist=5000, 139 action=curry(call, 'wmiir', 'setsid', 140 pygmi.shell, '-c', background=True)) 141 action_menu = Menu(histfile='%s/history.actions' % confpath[0], nhist=500, 142 choices=lambda: Actions._choices, 143 action=Actions._call) 144 tag_menu = Menu(histfile='%s/history.tags' % confpath[0], nhist=100, 145 choices=lambda: sorted(tags.tags.keys())) 146 147 def clickmenu(choices, args): 148 ClickMenu(choices=(k for k, v in choices), 149 action=lambda choice: dict(choices).get(choice, identity)(*args) 150 ).call() 151 152 class Notice(Button): 153 def __init__(self): 154 super(Notice, self).__init__(*noticebar, colors=wmii.cache['normcolors']) 155 self.timer = None 156 self.show(' ') 157 158 def tick(self): 159 self.create(wmii.cache['normcolors'], ' ') 160 161 def write(self, notice): 162 client.awrite('/event', 'Notice %s' % notice.replace('\n', ' ')) 163 164 def show(self, notice): 165 if self.timer: 166 self.timer.cancel() 167 self.create(wmii.cache['normcolors'], notice) 168 self.timer = Timer(noticetimeout, self.tick) 169 self.timer.start() 170 notice = Notice() 171 172 keys.bind('main', ( 173 "Moving around", 174 ('%(mod)s-%(left)s', "Select the client to the left", 175 lambda k: Tag('sel').select('left')), 176 ('%(mod)s-%(right)s', "Select the client to the right", 177 lambda k: Tag('sel').select('right')), 178 ('%(mod)s-%(up)s', "Select the client above", 179 lambda k: Tag('sel').select('up')), 180 ('%(mod)s-%(down)s', "Select the client below", 181 lambda k: Tag('sel').select('down')), 182 183 ('%(mod)s-space', "Toggle between floating and managed layers", 184 lambda k: Tag('sel').select('toggle')), 185 186 "Moving through stacks", 187 ('%(mod)s-Control-%(up)s', "Select the stack above", 188 lambda k: Tag('sel').select('up', stack=True)), 189 ('%(mod)s-Control-%(down)s', "Select the stack below", 190 lambda k: Tag('sel').select('down', stack=True)), 191 192 193 "Moving clients around", 194 ('%(mod)s-Shift-%(left)s', "Move selected client to the left", 195 lambda k: Tag('sel').send(Client('sel'), 'left')), 196 ('%(mod)s-Shift-%(right)s', "Move selected client to the right", 197 lambda k: Tag('sel').send(Client('sel'), 'right')), 198 ('%(mod)s-Shift-%(up)s', "Move selected client up", 199 lambda k: Tag('sel').send(Client('sel'), 'up')), 200 ('%(mod)s-Shift-%(down)s', "Move selected client down", 201 lambda k: Tag('sel').send(Client('sel'), 'down')), 202 203 ('%(mod)s-Shift-space', "Toggle selected client between floating and managed layers", 204 lambda k: Tag('sel').send(Client('sel'), 'toggle')), 205 206 "Client actions", 207 ('%(mod)s-f', "Toggle selected client's fullsceen state", 208 lambda k: Client('sel').set('Fullscreen', 'toggle')), 209 ('%(mod)s-Shift-c', "Close client", 210 lambda k: Client('sel').kill()), 211 212 "Changing column modes", 213 ('%(mod)s-d', "Set column to default mode", 214 lambda k: setattr(Tag('sel').selcol, 'mode', 'default-max')), 215 ('%(mod)s-s', "Set column to stack mode", 216 lambda k: setattr(Tag('sel').selcol, 'mode', 'stack-max')), 217 ('%(mod)s-m', "Set column to max mode", 218 lambda k: setattr(Tag('sel').selcol, 'mode', 'stack+max')), 219 220 "Running programs", 221 ('%(mod)s-a', "Open wmii actions menu", 222 lambda k: action_menu()), 223 ('%(mod)s-p', "Open program menu", 224 lambda k: program_menu()), 225 226 ('%(mod)s-Return', "Launch a terminal", 227 lambda k: call(*terminal, background=True)), 228 229 "Tag actions", 230 ('%(mod)s-t', "Change to another tag", 231 lambda k: tags.select(tag_menu())), 232 ('%(mod)s-Shift-t', "Retag the selected client", 233 lambda k: setattr(Client('sel'), 'tags', tag_menu())), 234 235 ('%(mod)s-n', "Move to the view to the left", 236 lambda k: tags.select(tags.next())), 237 ('%(mod)s-b', "Move to the view to the right", 238 lambda k: tags.select(tags.next(True))), 239 ('%(mod)s-Shift-n', "Move to the view to the left, take along current client", 240 lambda k: tags.select(tags.next(), take_client=Client('sel'))), 241 ('%(mod)s-Shift-b', "Move to the view to the right, take along current client", 242 lambda k: tags.select(tags.next(True), take_client=Client('sel'))), 243 244 ('%(mod)s-i', "Move to the newer tag in the tag stack", 245 lambda k: tags.select(tags.NEXT)), 246 ('%(mod)s-o', "Move to the older tag in the tag stack", 247 lambda k: tags.select(tags.PREV)), 248 ('%(mod)s-Shift-i', "Move to the newer tag in the tag stack, take along current client", 249 lambda k: tags.select(tags.NEXT, take_client=Client('sel'))), 250 ('%(mod)s-Shift-o', "Move to the older tag in the tag stack, take along current client", 251 lambda k: tags.select(tags.PREV, take_client=Client('sel'))), 252 253 )) 254 def bind_num(i): 255 keys.bind('main', ( 256 "Tag actions", 257 ('%%(mod)s-%d' % i, "Move to view '%d'" % i, 258 lambda k: tags.select(str(i))), 259 ('%%(mod)s-Shift-%d' % i, "Retag selected client with tag '%d'" % i, 260 lambda k: setattr(Client('sel'), 'tags', i)), 261 )) 262 map(bind_num, range(0, 10)) 263 264 keys.bind('main', ( 265 "Changing modes", 266 ('%(mod)s-Control-r', "Enter resize mode", 267 lambda k: setattr(keys, 'mode', 'resize')), 268 ('%(mod)s-Control-t', "Enter passthrough mode", 269 lambda k: setattr(keys, 'mode', 'passthrough')), 270 )); 271 keys.bind('passthrough', ( 272 "Changing modes", 273 ('%(mod)s-Control-t', "Leave passthrough mode", 274 lambda k: setattr(keys, 'mode', 'main')), 275 )); 276 277 keys.bind('resize', ( 278 ('Escape', "Leave resize mode", 279 lambda k: setattr(keys, 'mode', 'main')), 280 ), import_={'main': ('%(mod)s-%(left)s', '%(mod)s-%(right)s', 281 '%(mod)s-%(up)s', '%(mod)s-%(down)s', 282 '%(mod)s-Space')}) 283 284 def addresize(mod, desc, cmd, *args): 285 keys.bind('resize', ( 286 (mod + '%(left)s', "%s selected client to the left" % desc, 287 lambda k: Tag('sel').ctl(cmd, 'sel sel', 'left', 288 *args)), 289 (mod + '%(right)s', "%s selected client to the right" % desc, 290 lambda k: Tag('sel').ctl(cmd, 'sel sel', 'right', 291 *args)), 292 (mod + '%(up)s', "%s selected client up" % desc, 293 lambda k: Tag('sel').ctl(cmd, 'sel sel', 'up', 294 *args)), 295 (mod + '%(down)s', "%s selected client down" % desc, 296 lambda k: Tag('sel').ctl(cmd, 'sel sel', 'down', 297 *args)), 298 )); 299 addresize('', 'Grow', 'grow') 300 addresize('Control-', 'Shrink', 'grow', '-1') 301 addresize('Shift-', 'Nudge', 'nudge') 302 303 Thread(target=lambda: Actions.rehash()).start() 304 305 if not os.environ.get('WMII_NOPLUGINS', ''): 306 dirs = filter(curry(os.access, _, os.R_OK), 307 ('%s/plugins' % dir for dir in confpath)) 308 files = filter(re.compile(r'\.py$').search, 309 reduce(operator.add, map(os.listdir, dirs), [])) 310 for f in ['wmiirc_local'] + ['plugins.%s' % file[:-3] for file in files]: 311 try: 312 __import__(f) 313 except Exception, e: 314 traceback.print_exc(sys.stdout) 315 316 call(*tray, background=True) 317 318 # vim:se sts=4 sw=4 et: