Changeset 3b72c6f02dde3ec9451bd43e4fc86d3143cc6775 for samurai-x
- Timestamp:
- 07/14/2008 09:17:36 AM (2 years ago)
- Children:
- 8a84fd16a7eb94842a748169309b8184a176666d
- Parents:
- 42db8fb5f3a04acbc4b6bbeae932b5349d99e403
- git-committer:
- dunkfordyce <dunkfordyce@561c22c7-a851-0410-91f3-c76db74392ff> / 2008-07-14T08:17:36Z+0000
- Location:
- samurai-x
- Files:
-
- 10 added
- 7 modified
- 2 moved
-
run.py (modified) (1 diff)
-
samuraix/appl.py (moved) (moved from samurai-x/samuraix/app.py) (13 diffs)
-
samuraix/cairo.py (added)
-
samuraix/client.py (modified) (10 diffs)
-
samuraix/desktop.py (modified) (2 diffs)
-
samuraix/drawcontext.py (added)
-
samuraix/focus.py (added)
-
samuraix/keysymdef.py (moved) (moved from samurai-x/samuraix/keydefs.py)
-
samuraix/main.py (modified) (5 diffs)
-
samuraix/rules.py (added)
-
samuraix/screen.py (modified) (7 diffs)
-
samuraix/simple_window.py (added)
-
samuraix/statusbar.py (added)
-
samuraix/widget.py (added)
-
samuraix/xatom.py (added)
-
samuraix/xconstants.py (modified) (1 diff)
-
samuraix/xhelpers.py (modified) (2 diffs)
-
tools/makeatoms.py (added)
-
tools/makekeydefs.py (added)
Legend:
- Unmodified
- Added
- Removed
-
samurai-x/run.py
r0540af r3b72c6 1 #!/usr/bin/env python 2 1 3 import sys 2 4 sys.path.append('.') 3 5 4 6 from samuraix.main import run 5 from samuraix.app import App7 from samuraix.appl import App 6 8 7 9 run(App) -
samurai-x/samuraix/appl.py
r42db8f r3b72c6 1 1 import pyglet 2 from pyglet.window.xlib import xlib 3 4 import signal 5 2 6 import samuraix 3 4 from pyglet.window.xlib import xlib5 #from pyglet.window.xlib import cursorfont6 from ctypes import *7 8 import keydefs9 10 7 from samuraix.xhelpers import get_window_state 8 from samuraix.screen import Screen 11 9 from samuraix.client import Client 12 from samuraix.screen import Screen 10 from samuraix.sxctypes import * 11 from samuraix import xatom 13 12 14 13 from samuraix.testfunc import testfunc … … 18 17 log = logging.getLogger(__name__) 19 18 19 20 20 class App(pyglet.event.EventDispatcher): 21 21 22 x_event_map = {23 xlib.ButtonPress: 'on_button_press',24 xlib.ConfigureRequest: 'on_configure_request',25 xlib.ConfigureNotify: 'on_configure_notify',26 xlib.DestroyNotify: 'on_destroy_notify',27 xlib.EnterNotify: 'on_enter_notify',28 xlib.Expose: 'on_expose',29 xlib.KeyPress: 'on_key_press',30 xlib.MappingNotify: 'on_mapping_notify',31 xlib.MapRequest: 'on_map_request',32 xlib.PropertyNotify: 'on_property_notify',33 xlib.UnmapNotify: 'on_unmap_notify',34 xlib.ClientMessage: 'on_client_message',35 }36 37 client_class = Client38 39 @classmethod40 def register_x_event_handlers(cls):41 for event in cls.x_event_map.itervalues():42 cls.register_event_type(event)43 22 44 23 def __init__(self, config={}): … … 48 27 ] 49 28 29 self.x_event_map = { 30 xlib.ButtonPress: self.on_button_press, 31 xlib.ConfigureRequest: self.on_configure_request, 32 xlib.ConfigureNotify: self.on_configure_notify, 33 xlib.DestroyNotify: self.on_destroy_notify, 34 xlib.EnterNotify: self.on_enter_notify, 35 xlib.Expose: self.on_expose, 36 xlib.KeyPress: self.on_key_press, 37 xlib.MappingNotify: self.on_mapping_notify, 38 xlib.MapRequest: self.on_map_request, 39 xlib.PropertyNotify: self.on_property_notify, 40 xlib.UnmapNotify: self.on_unmap_notify, 41 xlib.ClientMessage: self.on_client_message, 42 } 43 44 def init(self): 45 log.info('app %s initialising...' % self) 46 47 log.info('registering signal handlers...') 48 signal.signal(signal.SIGINT, self.stop) 49 signal.signal(signal.SIGTERM, self.stop) 50 signal.signal(signal.SIGHUP, self.stop) 51 50 52 self.create_screens() 51 53 52 self.clients = []53 54 self.scan() 54 55 … … 56 57 57 58 def run(self): 59 log.info('app %s now running...' % self) 60 58 61 xlib.XSync(samuraix.display, False) 59 62 self.running = True 60 63 61 try: 62 self._run() 63 finally: 64 ev = xlib.XEvent() 65 66 while self.running: 67 # for non blocking use this .. 68 #while xlib.XPending(samuraix.display): 69 xlib.XNextEvent(samuraix.display, byref(ev)) 70 self.handle_event(ev) 64 71 xlib.XSync(samuraix.display, False) 65 xlib.XCloseDisplay(samuraix.display) 66 67 def _run(self): 68 ev = xlib.XEvent() 69 70 while self.running: 71 while xlib.XPending(samuraix.display): 72 while xlib.XPending(samuraix.display): 73 xlib.XNextEvent(samuraix.display, byref(ev)) 74 self.handle_event(ev) 75 xlib.XSync(samuraix.display, False) 72 73 for screen in self.screens: 74 for widget in screen.widgets: 75 if widget.dirty: 76 widget.draw() 77 78 for screen in self.screens: 79 screen.remove() 80 81 def stop(self, *args, **kwargs): 82 log.info(' app %s stop' % self) 83 self.running = False 76 84 77 85 def handle_event(self, ev): 78 86 try: 79 evname= self.x_event_map[ev.type]87 func = self.x_event_map[ev.type] 80 88 except KeyError: 81 89 log.debug('cant map event %s' % ev.type) 82 return83 self.dispatch_event(evname,ev)90 else: 91 func(ev) 84 92 xlib.XSync(samuraix.display, False) 85 93 86 94 def create_screens(self): 95 log.info('creating screens...') 87 96 num_screens = xlib.XScreenCount(samuraix.display) 88 97 … … 93 102 self.screens.append(scr) 94 103 95 wa = xlib.XSetWindowAttributes() 96 wa.event_mask = ( xlib.SubstructureRedirectMask | 97 xlib.SubstructureNotifyMask | 98 xlib.EnterWindowMask | 99 xlib.LeaveWindowMask | 100 xlib.StructureNotifyMask ) 101 wa.cursor = samuraix.cursors['normal'] 102 104 def scan(self): 105 log.info('scanning screens for existing windows...') 103 106 for screen in self.screens: 104 root = screen.root_window 105 106 xlib.XChangeWindowAttributes(samuraix.display, 107 root, 108 xlib.CWEventMask | xlib.CWCursor, 109 byref(wa)) 110 111 xlib.XSelectInput(samuraix.display, 112 root, 113 wa.event_mask) 114 115 screen.grab_buttons() 116 screen.grab_keys() 117 118 def scan(self): 119 wa = xlib.XWindowAttributes() 120 121 wins = xlib.Window_p() 122 wins.contains = None 123 d1 = xlib.Window() 124 d2 = xlib.Window() 125 num = c_uint() 126 127 for screen in self.screens: 128 root = xlib.XRootWindow(samuraix.display, screen.num) 129 log.debug('root is %s' % root) 130 if xlib.XQueryTree(samuraix.display, root, byref(d1), byref(d2), byref(wins), byref(num)): 131 log.debug('found %s window' % num) 132 for i in range(num.value): 133 log.debug('found window %s' % wins[i]) 134 if (xlib.XGetWindowAttributes(samuraix.display, wins[i], byref(wa)) and 135 not wa.override_redirect and 136 (wa.map_state == xlib.IsViewable or 137 get_window_state(wins[i]) == xlib.IconicState)): 138 self.manage(wins[i], wa, screen) 139 if wins: 140 xlib.XFree(wins) 141 142 143 def manage(self, window, wa, screen): 144 log.debug('managing %s %s %s' % (window, wa, screen)) 145 client = self.client_class(screen, window, wa) 146 self.clients.append(client) 147 148 def get_client_by_window(self, win): 149 for client in self.clients: 150 if client.window == win: 151 return client 152 return None 107 screen.scan() 153 108 154 109 def on_button_press(self, e): … … 161 116 y = c_int() 162 117 163 client = self.get_client_by_window(ev.window)118 client = Client.get_by_window(ev.window) 164 119 if client is not None: 120 client.focus() 165 121 if CLEANMASK(ev.state) == xlib.NoSymbol and ev.button == xlib.Button1: 166 122 xlib.XAllowEvents(samuraix.display, xlib.ReplayPointer, xlib.CurrentTime) … … 178 134 ev = e.xconfigurerequest 179 135 180 client = self.get_client_by_window(ev.window)136 client = Client.get_by_window(ev.window) 181 137 if client is not None: 182 138 geom = client.geom.copy() … … 214 170 def on_destroy_notify(self, e): 215 171 ev = e.xdestroywindow 216 client = self.get_client_by_window(ev.window)172 client = Client.get_by_window(ev.window) 217 173 if client is not None: 218 174 client.remove() … … 220 176 def on_enter_notify(self, e): 221 177 ev = e.xcrossing 222 client = self.get_client_by_window(ev.window)178 client = Client.get_by_window(ev.window) 223 179 if client: 224 180 client.dispatch_event('on_enter') … … 229 185 return 230 186 231 def on_expose(self, ev): 232 pass 187 def on_expose(self, e): 188 log.debug('expose') 189 ev = e.xexpose 190 if not ev.count: 191 for screen in self.screens: 192 for widget in screen.widgets: 193 if widget.test_window(ev.window): 194 widget.refresh() 195 return 233 196 234 197 def on_key_press(self, e): … … 244 207 scr.dispatch_event('on_key_press', e.xkey) 245 208 return 246 log.warn('got a key press for a screen we dnt know!') 247 248 def on_mapping_notify(self, ev): 249 pass 209 log.warn('got a key press for a screen we dont know!') 210 211 def on_mapping_notify(self, e): 212 ev = e.xmapping 213 xlib.XRefreshKeyboardMapping(ev) 214 if ev.request == xlib.MappingKeyboard: 215 for screen in self.screens: 216 screen.grab_keys() 250 217 251 218 def on_map_request(self, e): 252 219 ev = e.xmaprequest 253 220 wa = xlib.XWindowAttributes() 254 221 255 222 if not xlib.XGetWindowAttributes(e.xany.display, ev.window, byref(wa)): 223 log.debug('couldnt get XGetWindowAttributes') 256 224 return 257 225 … … 259 227 return 260 228 261 client = self.get_client_by_window(ev.window)229 client = Client.get_by_window(ev.window) 262 230 if client is None: 263 screen = self.screens[0] 264 for s in self.screens: 265 if wa.screen == s.num: 266 screen = s 267 break 268 269 self.manage(ev.window, wa, screens) 270 271 def on_property_notify(self, ev): 272 pass 231 for screen in self.screens: 232 if (addressof(wa.screen.contents) == 233 addressof(xlib.XScreenOfDisplay(e.xany.display, screen.num).contents)): 234 screen.manage(ev.window, wa) 235 return 236 assert screen is not None, "looking for screen %s(%s) failed" %(wa.screen, type(wa.screen)) 237 238 def on_property_notify(self, e): 239 ev = e.xproperty 240 if ev.state == xlib.PropertyDelete: 241 return 242 client = Client.get_by_window(ev.window) 243 if client: 244 log.debug('prop change for client %s' % client) 245 if ev.atom == xatom.XA_WM_TRANSIENT_FOR: 246 trans = xlib.Window() 247 xlib.XGetTransientForHint(e.xany.display, client.window, byref(trans)) 248 # needs rearrange 249 elif ev.atom == xatom.XA_WM_NORMAL_HINTS: 250 client.update_size_hints() 251 elif ev.atom == xatom.XA_WM_HINTS: 252 client.update_wm_hints() 253 elif ev.atom == xatom.XA_WM_NAME or ev.atom == samuraix.atoms['_NET_WM_NAME']: 254 client.update_title() 273 255 274 256 def on_unmap_notify(self, e): 275 257 ev = e.xunmap 276 client = self.get_client_by_window(ev.window)258 client = Client.get_by_window(ev.window) 277 259 if (client is not None and 278 260 ev.event == xlib.XRootWindow(e.xany.display, client.screen.num) and … … 281 263 client.remove() 282 264 283 def on_client_message(self, ev): 284 pass 285 286 287 265 def on_client_message(self, e): 266 ev = e.xclient 267 self.process_ewmh_message(ev) 268 269 def process_ewmh_message(self, ev): 270 if ev.message_type == samuraix.atoms['_NET_CURRENT_DESKTOP']: 271 pass 272 # change the desktop 273 elif ev.message_type == samuraix.atoms['_NET_CLOSE_WINDOW']: 274 client = Client.get_by_window(ev.window) 275 if client: 276 client.kill() 277 elif ev.message_type == samuraix.atoms['_NET_WM_STATE']: 278 client = Client.get_by_window(ev.window) 279 if client: 280 client.process_ewmh_state_atom(ev.data.l[1], ev.data.l[0]) 281 if ev.data.l[2]: 282 client.process_ewmh_state_atom(ev.data.l[2], ev.data.l[0]) 283 284 285 286 287 -
samurai-x/samuraix/client.py
r42db8f r3b72c6 1 1 import pyglet 2 2 from pyglet.window.xlib import xlib 3 4 import weakref 3 5 4 6 from samuraix.sxctypes import * … … 13 15 14 16 class Client(pyglet.event.EventDispatcher): 17 18 all_clients = [] 19 window_2_client_map = weakref.WeakValueDictionary() 20 21 @classmethod 22 def get_by_window(cls, window): 23 return cls.window_2_client_map.get(window) 24 15 25 def __init__(self, screen, window, wa): 16 26 self.screen = screen … … 20 30 self.maxed_geom = self.geom.copy() 21 31 self.old_border = wa.border_width 32 self.desktop = screen.active_desktop 22 33 23 34 self.configure_window() 24 35 self.update_title() 25 36 self.update_size_hints() 37 self.update_wm_hints() 38 self.check_ewmh() 26 39 27 40 xlib.XSelectInput(samuraix.display, window, … … 30 43 xlib.EnterWindowMask) 31 44 32 log. debug("new client with %s %s" % (self.window, self.geom))45 log.info("new client with %s %s" % (self.window, self.geom)) 33 46 34 47 self.buttons = [ … … 36 49 (3, xlib.Mod4Mask, self.mouseresize), 37 50 ] 51 52 self.all_clients.append(self) 53 self.window_2_client_map[self.window] = self 54 38 55 39 56 def __str__(self): … … 56 73 xlib.StructureNotifyMask, cast(byref(ce), POINTER(xlib.XEvent))) 57 74 75 def check_ewmh(self): 76 format = c_int() 77 real = xlib.Atom() 78 data = c_uchar_p() 79 n = c_ulong() 80 extra = c_ulong() 81 82 #if (xlib.XGetWindowProperty(samuraix.display, self.window, samuraix.atoms['_NET_WM_STATE'], 83 # 0, LONG_NAN, False, xatom.XA_ATOM, byref(real), byref(format), byref(n), 84 # byref(extra), byref(data)) == xlib.Success): 85 # state = cast(data, xlib.Atom_p) 86 58 87 def update_title(self): 59 88 self.title = xhelpers.get_text_property(self.window, samuraix.atoms['_NET_WM_NAME']) 60 89 if not self.title: 61 90 self.title = xhelpers.get_text_property(self.window, samuraix.atoms['WM_NAME']) 62 log.debug("title is now %s" % self.title)91 log.debug("title of %s is now %s" % (self, self.title)) 63 92 64 93 def update_size_hints(self): 65 print "TODO update_size_hints" 94 msize = c_long() 95 size = xlib.XSizeHints() 96 97 if not xlib.XGetWMNormalHints(samuraix.display, self.window, byref(size), byref(msize)): 98 return 0 99 100 if size.flags & xlib.PBaseSize: 101 self.base_width = size.base_width 102 self.base_height = size.base_height 103 elif size.flags & xlib.PMinSize: 104 self.base_width = size.min_width 105 self.base_height = size.min_height 106 else: 107 self.base_width = 0 108 self.base_height = 0 109 110 if size.flags & xlib.PResizeInc: 111 self.inc_width = size.width_inc 112 self.inc_height = size.height_inc 113 else: 114 self.inc_width = 0 115 self.inc_height = 0 116 117 if size.flags & xlib.PMaxSize: 118 self.max_width = size.max_width 119 self.max_height = size.max_height 120 else: 121 self.max_width = 0 122 self.max_height = 0 123 124 if size.flags & xlib.PMinSize: 125 self.min_width = size.min_width 126 self.min_height = size.min_height 127 elif size.flags & xlib.PBaseSize: 128 self.min_width = size.base_width 129 self.min_height = size.base_height 130 else: 131 self.min_width = 0 132 self.min_height = 0 133 134 if size.flags & xlib.PAspect: 135 self.min_aspect_x = size.min_aspect.x 136 self.min_aspect_y = size.min_aspect.y 137 self.max_aspect_x = size.max_aspect.x 138 self.max_aspect_y = size.max_aspect.y 139 else: 140 self.min_aspect_x = 0 141 self.min_aspect_y = 0 142 self.max_aspect_x = 0 143 self.max_aspect_y = 0 144 145 return size.flags 146 147 def update_wm_hints(self): 148 wmhp = xlib.XGetWMHints(samuraix.display, self.window) 149 wmh = wmhp[0] 150 if wmh: 151 self.urgent = wmh.flags & xlib.XUrgencyHint 152 if self.urgent: # and its not the focused window... 153 pass 154 # meant to invalidate that cache and draw titlebar 155 if wmh.flags & xlib.StateHint and wmh.initial_state == xlib.WithdrawnState: 156 self.border_width = 0 157 self.skip = True 158 xlib.XFree(wmhp) 159 160 def process_ewmh_state_atom(self, client, state, set): 161 if state == samuraix.atoms['_NET_WM_STATE_STICKY']: 162 pass 66 163 67 164 def resize(self, geometry, hints=False): … … 88 185 89 186 def focus(self): 90 pass 187 log.debug('focusing %s' % self) 188 xlib.XSetInputFocus(samuraix.display, self.window, xlib.RevertToPointerRoot, 189 xlib.CurrentTime) 190 self.stack() 191 self.grab_buttons() 192 193 def stack(self): 194 log.debug('stacking %s' % self) 195 xlib.XRaiseWindow(samuraix.display, self.window) 91 196 92 197 def remove(self): 93 samuraix.app.clients.remove(self) 94 198 log.debug('removing %s' % self) 95 199 wc = xlib.XWindowChanges() 96 200 … … 101 205 102 206 xlib.XUngrabButton(samuraix.display, xlib.AnyButton, xlib.AnyModifier, self.window) 103 # TODO: window_setstate(c->win, WithdrawnState);207 xhelpers.set_window_state(self.window, xlib.WithdrawnState) 104 208 xlib.XSync(samuraix.display, False) 105 209 xlib.XUngrabServer(samuraix.display) 210 211 self.all_clients.remove(self) 106 212 107 213 def on_button_press(self, ev): … … 246 352 247 353 def ban(self): 354 log.debug('banning %s' % self) 248 355 xlib.XUnmapWindow(samuraix.display, self.window) 249 356 xhelpers.set_window_state(self.window, xlib.IconicState) … … 251 358 252 359 def unban(self): 360 log.debug('unbanning %s' % self) 253 361 xlib.XMapWindow(samuraix.display, self.window) 254 362 xhelpers.set_window_state(self.window, xlib.NormalState) 255 363 # titlebar remap here 256 364 365 def move_to_desktop(self, desktop): 366 desktop.remove_client 257 367 258 368 Client.register_event_type('on_button_press') -
samurai-x/samuraix/desktop.py
r42db8f r3b72c6 2 2 import pyglet 3 3 4 import weakref 5 4 6 import samuraix 7 8 import logging 9 log = logging.getLogger(__name__) 5 10 6 11 class Desktop(pyglet.event.EventDispatcher): … … 9 14 self.name = name 10 15 16 log.info('created new desktop %s' % self) 17 11 18 self.clients = [] 12 19 20 def __str__(self): 21 return "<Desktop '%s' on %s>" % (self.name, self.screen) 22 23 def add_client(self, client): 24 log.debug('adding client %s to desktop %s' % (client, self)) 25 self.clients.append(weakref.ref(client)) 26 if client.desktop is self: 27 client.unban() 28 else: 29 client.ban() 30 31 def on_show(self): 32 log.info('showing desktop %s' % self) 33 for client in self.clients: 34 c = client() 35 if c is not None: 36 c.unban() 37 38 def on_hide(self): 39 log.info('hiding desktop %s' % self) 40 for client in self.clients: 41 c = client() 42 if c is not None: 43 c.ban() 44 45 46 Desktop.register_event_type('on_show') 47 Desktop.register_event_type('on_hide') 48 -
samurai-x/samuraix/main.py
r42db8f r3b72c6 1 2 import os3 4 1 import pyglet 5 2 pyglet.options['shadow_window'] = False … … 10 7 import samuraix 11 8 from samuraix.sxctypes import * 12 from samuraix import keydefs9 from samuraix import xhelpers 13 10 14 11 import logging … … 16 13 17 14 18 def open_display(displayname=None):19 if displayname is None:20 displayname = os.environ.get('DISPLAY', ':0')21 samuraix.displayname = displayname22 23 log.debug("connecting to %s" % displayname)24 samuraix.display = xlib.XOpenDisplay(None)25 if not samuraix.display:26 # not sure what this exception should be really...27 raise RuntimeError("Cant connect to xserver")28 29 xlib.XSynchronize(samuraix.display, True)30 31 32 def get_numlock_mask():33 modmap = xlib.XGetModifierMapping(samuraix.display)[0]34 keycode = xlib.XKeysymToKeycode(samuraix.display, keydefs.XK_Num_Lock)35 36 mask = 037 38 for i in range(8):39 for j in range(0, modmap.max_keypermod):40 if modmap.modifiermap[i * modmap.max_keypermod + j] == keycode:41 mask = 1 << i42 43 xlib.XFreeModifiermap(modmap)44 45 xlib.NumLockMask = mask46 47 48 15 def init_atoms(): 16 log.info('creating atoms instance...') 49 17 from samuraix.atoms import Atoms 50 18 samuraix.atoms = Atoms() 51 19 20 52 21 def init_cursors(): 22 log.info('creating cursors instance...') 53 23 from samuraix.cursors import Cursors 54 24 samuraix.cursors = Cursors() … … 63 33 64 34 def load_config(): 35 log.info('loading config...') 65 36 samuraix.config = { 66 37 'screens': { 67 '0': {38 0: { 68 39 'virtual_desktops': [ 69 40 {'name': 'one'}, … … 79 50 configure_logging() 80 51 52 xhelpers.open_display() 53 xhelpers.check_for_other_wm() 54 #xhelpers.setup_xerror() 55 81 56 load_config() 82 57 83 open_display()84 58 init_atoms() 85 get_numlock_mask()59 xhelpers.get_numlock_mask() 86 60 init_cursors() 87 61 88 app.register_x_event_handlers()62 log.info('creating app instance...') 89 63 samuraix.app = app() 90 samuraix.app.run() 64 samuraix.app.init() 65 log.info('let battle commence...') 66 try: 67 samuraix.app.run() 68 finally: 69 xhelpers.close_display() 70 log.info('done') 71 91 72 92 73 if __name__ == '__main__': 93 from samuraix.app import App74 from samuraix.appl import App 94 75 run(App) 95 76 -
samurai-x/samuraix/screen.py
r42db8f r3b72c6 1 1 import pyglet 2 2 from pyglet.window.xlib import xlib 3 4 import weakref 5 import functools 3 6 4 7 import samuraix … … 6 9 from samuraix.xconstants import BUTTONMASK, CLEANMASK 7 10 from samuraix.desktop import Desktop 8 from samuraix import keydefs 11 from samuraix.statusbar import Statusbar 12 from samuraix import keysymdef 9 13 from samuraix.testfunc import testfunc 14 from samuraix.sxctypes import * 15 from samuraix import xatom 16 from samuraix.xhelpers import get_window_state 17 from samuraix.client import Client 10 18 11 19 import logging 12 20 log = logging.getLogger(__name__) 13 21 22 def xterm(): 23 from subprocess import * 24 pid = Popen(["/usr/bin/xterm"]).pid 25 26 14 27 class Screen(pyglet.event.EventDispatcher): 28 15 29 _default_conf = { 16 30 'virtual_desktops': [ 17 31 {'name':'one'}, 18 32 ], 33 'status_bar': { 34 'position': 'top', 35 } 19 36 } 37 38 client_class = Client 20 39 21 40 def __init__(self, num, buttons=None): … … 27 46 self.buttons = () if buttons is None else buttons 28 47 self.keys = [ 29 (keydefs.XK_Return, xlib.Mod4Mask, testfunc), 48 (keysymdef.XK_Return, xlib.Mod4Mask, xterm), 49 (keysymdef.XK_F1, xlib.Mod4Mask, 50 functools.partial(self.set_active_desktop_by_name, 'one')), 51 (keysymdef.XK_F2, xlib.Mod4Mask, 52 functools.partial(self.set_active_desktop_by_name, 'two')), 53 (keysymdef.XK_F3, xlib.Mod4Mask, 54 functools.partial(self.set_active_desktop_by_name, 'three')), 30 55 ] 31 56 32 57 self.desktops = [] 58 self.active_desktop = None 59 60 self.clients = [] 61 62 self.config = self._default_conf.copy() 33 63 34 64 try: 35 conf = samuraix.config['screens'][self.num]65 self.config.update(samuraix.config['screens'][self.num]) 36 66 except KeyError: 37 conf = self._default_conf38 39 for conf_desktop in conf['virtual_desktops']:67 log.debug('cant find config for screen %s' % self.num) 68 69 for conf_desktop in self.config['virtual_desktops']: 40 70 desktop = Desktop(self, conf_desktop['name']) 41 71 self.desktops.append(desktop) 42 72 43 self.active_desktop = self.desktops[0] 73 self.widgets = [] 74 75 if self.config['status_bar']['position'] is not None: 76 self.widgets.append(Statusbar(self)) 77 78 self.set_active_desktop(self.desktops[0]) 79 80 wa = xlib.XSetWindowAttributes() 81 wa.event_mask = ( xlib.SubstructureRedirectMask | 82 xlib.SubstructureNotifyMask | 83 xlib.EnterWindowMask | 84 xlib.LeaveWindowMask | 85 xlib.StructureNotifyMask ) 86 wa.cursor = samuraix.cursors['normal'] 87 88 root = self.root_window 89 90 xlib.XChangeWindowAttributes(samuraix.display, 91 root, 92 xlib.CWEventMask | xlib.CWCursor, 93 byref(wa)) 94 95 xlib.XSelectInput(samuraix.display, 96 root, 97 wa.event_mask) 98 99 self.set_supported_hints() 100 101 self.grab_buttons() 102 self.grab_keys() 44 103 45 104 def __str__(self): … … 50 109 root_window = property(_get_root_window) 51 110 52 def set_active_desktop(self, name): 111 def set_supported_hints(self): 112 atoms = [ 113 samuraix.atoms['_NET_SUPPORTED'], 114 samuraix.atoms['_NET_CLIENT_LIST'], 115 samuraix.atoms['_NET_NUMBER_OF_DESKTOPS'], 116 samuraix.atoms['_NET_CURRENT_DESKTOP'], 117 samuraix.atoms['_NET_DESKTOP_NAMES'], 118 samuraix.atoms['_NET_ACTIVE_WINDOW'], 119 samuraix.atoms['_NET_CLOSE_WINDOW'], 120 121 samuraix.atoms['_NET_WM_NAME'], 122 samuraix.atoms['_NET_WM_ICON_NAME'], 123 samuraix.atoms['_NET_WM_WINDOW_TYPE'], 124 samuraix.atoms['_NET_WM_WINDOW_TYPE_NORMAL'], 125 samuraix.atoms['_NET_WM_WINDOW_TYPE_DOCK'], 126 samuraix.atoms['_NET_WM_WINDOW_TYPE_SPLASH'], 127 samuraix.atoms['_NET_WM_WINDOW_TYPE_DIALOG'], 128 samuraix.atoms['_NET_WM_STATE'], 129 samuraix.atoms['_NET_WM_STATE_STICKY'], 130 samuraix.atoms['_NET_WM_STATE_SKIP_TASKBAR'], 131 samuraix.atoms['_NET_WM_STATE_FULLSCREEN'], 132 133 samuraix.atoms['UTF8_STRING'], 134 ] 135 n = len(atoms) 136 atoms_arr_type = xlib.Atom * n 137 atoms_arr = atoms_arr_type(*atoms) 138 139 xlib.XChangeProperty(samuraix.display, self.root_window, 140 samuraix.atoms['_NET_SUPPORTED'], xatom.XA_ATOM, 32, 141 xlib.PropModeReplace, cast(atoms_arr, c_uchar_p), n) 142 143 def scan(self): 144 wa = xlib.XWindowAttributes() 145 146 wins = xlib.Window_p() 147 wins.contains = None 148 d1 = xlib.Window() 149 d2 = xlib.Window() 150 num = c_uint() 151 152 root = self.root_window 153 log.debug('root is %s' % root) 154 if xlib.XQueryTree(samuraix.display, root, byref(d1), byref(d2), byref(wins), byref(num)): 155 log.debug('found %s windows' % num) 156 for i in range(num.value): 157 log.debug('found window %s' % wins[i]) 158 if (xlib.XGetWindowAttributes(samuraix.display, wins[i], byref(wa)) and 159 not wa.override_redirect and 160 (wa.map_state == xlib.IsViewable or 161 get_window_state(wins[i]) == xlib.IconicState)): 162 self.manage(wins[i], wa) 163 if wins: 164 xlib.XFree(wins) 165 166 def remove(self): 167 self.ungrab_buttons() 168 self.ungrab_keys() 169 170 def manage(self, window, wa): 171 client = self.client_class(self, window, wa) 172 log.info('screen %s managing %s' % (self, client)) 173 self.clients.append(weakref.ref(client)) 174 175 self.dispatch_event('on_client_add', client) 176 177 def on_client_add(self, client): 178 self.active_desktop.add_client(client) 179 180 def set_active_desktop_by_name(self, name): 53 181 for desktop in self.desktops: 54 182 if desktop.name == name: 55 self. active_desktop = self.desktops[name]183 self.set_active_desktop(desktop) 56 184 return 57 185 raise ValueError(name) 186 187 def next_desktop(self): 188 idx = self.desktops.index(self.active_desktop) + 1 189 if idx >= len(self.desktops): 190 idx = 0 191 self.set_active_desktop(self.desktops[idx]) 192 193 def set_active_desktop(self, desktop): 194 assert desktop in self.desktops 195 if self.active_desktop is not None: 196 log.debug('hiding desktop %s' % self.active_desktop) 197 self.active_desktop.dispatch_event('on_hide') 198 199 self.active_desktop = desktop 200 log.debug('showing desktop %s' % desktop) 201 desktop.dispatch_event('on_show') 202 self.dispatch_event('on_desktop_change') 58 203 59 204 def on_button_press(self, ev): … … 64 209 def on_key_press(self, ev): 65 210 keysym = xlib.XKeycodeToKeysym(samuraix.display, ev.keycode, 0) 211 log.debug('on_key_press %s %s %s' % (self, keysym, ev.keycode)) 66 212 for ks, modifiers, func in self.keys: 67 213 if ks == keysym and CLEANMASK(modifiers) == CLEANMASK(ev.state): 214 log.debug('doing %s' % func) 68 215 func() 216 return 217 log.debug('not handler founnd') 69 218 70 219 def grab_buttons(self): … … 91 240 92 241 def grab_keys(self): 93 log.debug("g ab_keys %s" % self)94 95 root = self.root_window 96 97 xlib.XUngrabKey(samuraix.display, xlib.AnyKey, xlib.AnyModifier, root)242 log.debug("grab_keys %s" % self) 243 244 root = self.root_window 245 246 self.ungrab_keys() 98 247 for keysym, modifiers, func in self.keys: 99 248 kc = xlib.XKeysymToKeycode(samuraix.display, keysym) … … 112 261 root, True, xlib.GrabModeAsync, xlib.GrabModeAsync) 113 262 263 def ungrab_keys(self): 264 xlib.XUngrabKey(samuraix.display, xlib.AnyKey, xlib.AnyModifier, self.root_window) 265 114 266 115 267 Screen.register_event_type('on_button_press') 116 268 Screen.register_event_type('on_key_press') 117 118 269 Screen.register_event_type('on_desktop_change') 270 Screen.register_event_type('on_client_add') 271 272 -
samurai-x/samuraix/xconstants.py
r0540af r3b72c6 4 4 xlib.XModifierKeymap_p = POINTER(xlib.XModifierKeymap) 5 5 xlib.Window_p = POINTER(xlib.Window) 6 xlib.RevertToPointerRoot = xlib.PointerRoot 6 7 7 8 BUTTONMASK = (xlib.ButtonPressMask | xlib.ButtonReleaseMask) -
samurai-x/samuraix/xhelpers.py
r42db8f r3b72c6 1 import os 2 1 3 from pyglet.window.xlib import xlib 2 4 from samuraix.sxctypes import * 3 5 4 6 import samuraix 7 from samuraix import keysymdef 8 9 import logging 10 log = logging.getLogger(__name__) 11 5 12 6 13 def get_window_state(window): … … 42 49 43 50 51 def open_display(displayname=None): 52 log.info('opening display...') 53 if displayname is None: 54 displayname = os.environ.get('DISPLAY', ':0') 55 samuraix.displayname = displayname 56 57 log.info("connecting to %s" % displayname) 58 samuraix.display = xlib.XOpenDisplay(None) 59 if not samuraix.display: 60 # not sure what this exception should be really... 61 raise RuntimeError("Cant connect to xserver") 62 63 xlib.XSynchronize(samuraix.display, True) 64 65 66 def close_display(): 67 log.info('closing display..') 68 xlib.XSync(samuraix.display, False) 69 xlib.XCloseDisplay(samuraix.display) 70 71 72 def check_for_other_wm(): 73 log.info('checking for other wm...') 74 def xerror(display, ev): 75 raise "another wm is already running!" 76 c_xerror = xlib.XErrorHandler(xerror) 77 78 xlib.XSetErrorHandler(c_xerror) 79 for screen in range(xlib.XScreenCount(samuraix.display)): 80 xlib.XSelectInput(samuraix.display, 81 xlib.XRootWindow(samuraix.display, screen), 82 xlib.SubstructureRedirectMask) 83 xlib.XSync(samuraix.display, False) 84 xlib.XSetErrorHandler(xlib.XErrorHandler()) 85 86 87 def get_numlock_mask(): 88 log.info('fetching numlock mask...') 89 modmap = xlib.XGetModifierMapping(samuraix.display)[0] 90 keycode = xlib.XKeysymToKeycode(samuraix.display, keysymdef.XK_Num_Lock) 91 92 mask = 0 93 94 for i in range(8): 95 for j in range(0, modmap.max_keypermod): 96 if modmap.modifiermap[i * modmap.max_keypermod + j] == keycode: 97 mask = 1 << i 98 99 xlib.XFreeModifiermap(modmap) 100 101 xlib.NumLockMask = mask 102 103 104 def setup_xerror(): 105 log.info('installing x error handler...') 106 def xerror(display, ev): 107 log.debug('xerror %s' % ev) 108 if (ev.error_code == xlib.BadWindow or 109 (ev.error_code == xlib.BadMatch and ev.request_code == xlib.X_SetInputFocus) or 110 (ev.error_code == xlib.BadValue and ev.request_code == xlib.X_KillClient) or 111 (ev.error_code == xlib.BadMatch and ev.request_code == xlib.X_ConfigureWindow)): 112 return 0 113 log.warn('fatal error: request_code=%s error_code=%s' % (ev.request_code, ev.error_code)) 114 return xerrorxlib(display, ev) 115 116 c_xerror = xlib.XErrorHandler(xerror) 117 xerrorxlib = xlib.XSetErrorHandler(c_xerror) 118 xlib.XSync(samuraix.display, False)
