Show
Ignore:
Timestamp:
07/14/2008 09:17:36 AM (2 years ago)
Author:
dunkfordyce <dunkfordyce@…>
Children:
8a84fd16a7eb94842a748169309b8184a176666d
Parents:
42db8fb5f3a04acbc4b6bbeae932b5349d99e403
git-committer:
dunkfordyce <dunkfordyce@561c22c7-a851-0410-91f3-c76db74392ff> / 2008-07-14T08:17:36Z+0000
Message:

work from the weekend

git-svn-id:  https://samurai-x.googlecode.com/svn/trunk@5 561c22c7-a851-0410-91f3-c76db74392ff

Location:
samurai-x
Files:
10 added
7 modified
2 moved

Legend:

Unmodified
Added
Removed
  • samurai-x/run.py

    r0540af r3b72c6  
     1#!/usr/bin/env python 
     2 
    13import sys 
    24sys.path.append('.') 
    35 
    46from samuraix.main import run 
    5 from samuraix.app import App 
     7from samuraix.appl import App 
    68 
    79run(App) 
  • samurai-x/samuraix/appl.py

    r42db8f r3b72c6  
    11import pyglet 
     2from pyglet.window.xlib import xlib  
     3 
     4import signal 
     5 
    26import samuraix 
    3  
    4 from pyglet.window.xlib import xlib  
    5 #from pyglet.window.xlib import cursorfont 
    6 from ctypes import * 
    7  
    8 import keydefs  
    9  
    107from samuraix.xhelpers import get_window_state 
     8from samuraix.screen import Screen 
    119from samuraix.client import Client 
    12 from samuraix.screen import Screen 
     10from samuraix.sxctypes import * 
     11from samuraix import xatom 
    1312 
    1413from samuraix.testfunc import testfunc 
     
    1817log = logging.getLogger(__name__) 
    1918 
     19 
    2020class App(pyglet.event.EventDispatcher): 
    2121 
    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 = Client 
    38  
    39     @classmethod 
    40     def register_x_event_handlers(cls): 
    41         for event in cls.x_event_map.itervalues(): 
    42             cls.register_event_type(event) 
    4322 
    4423    def __init__(self, config={}): 
     
    4827        ] 
    4928 
     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 
    5052        self.create_screens() 
    5153 
    52         self.clients = [] 
    5354        self.scan() 
    5455 
     
    5657 
    5758    def run(self): 
     59        log.info('app %s now running...' % self) 
     60 
    5861        xlib.XSync(samuraix.display, False) 
    5962        self.running = True 
    6063 
    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) 
    6471            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 
    7684 
    7785    def handle_event(self, ev): 
    7886        try: 
    79             evname = self.x_event_map[ev.type] 
     87            func = self.x_event_map[ev.type] 
    8088        except KeyError: 
    8189            log.debug('cant map event %s' % ev.type) 
    82             return  
    83         self.dispatch_event(evname, ev) 
     90        else: 
     91            func(ev) 
    8492        xlib.XSync(samuraix.display, False) 
    8593 
    8694    def create_screens(self): 
     95        log.info('creating screens...') 
    8796        num_screens = xlib.XScreenCount(samuraix.display) 
    8897 
     
    93102            self.screens.append(scr) 
    94103         
    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...') 
    103106        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() 
    153108 
    154109    def on_button_press(self, e): 
     
    161116        y = c_int() 
    162117 
    163         client = self.get_client_by_window(ev.window) 
     118        client = Client.get_by_window(ev.window) 
    164119        if client is not None: 
     120            client.focus() 
    165121            if CLEANMASK(ev.state) == xlib.NoSymbol and ev.button == xlib.Button1: 
    166122                xlib.XAllowEvents(samuraix.display, xlib.ReplayPointer, xlib.CurrentTime) 
     
    178134        ev = e.xconfigurerequest 
    179135 
    180         client = self.get_client_by_window(ev.window) 
     136        client = Client.get_by_window(ev.window) 
    181137        if client is not None: 
    182138            geom = client.geom.copy() 
     
    214170    def on_destroy_notify(self, e): 
    215171        ev = e.xdestroywindow 
    216         client = self.get_client_by_window(ev.window) 
     172        client = Client.get_by_window(ev.window) 
    217173        if client is not None: 
    218174            client.remove() 
     
    220176    def on_enter_notify(self, e): 
    221177        ev = e.xcrossing 
    222         client = self.get_client_by_window(ev.window) 
     178        client = Client.get_by_window(ev.window) 
    223179        if client: 
    224180            client.dispatch_event('on_enter') 
     
    229185                    return  
    230186 
    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 
    233196 
    234197    def on_key_press(self, e): 
     
    244207                scr.dispatch_event('on_key_press', e.xkey) 
    245208                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() 
    250217 
    251218    def on_map_request(self, e): 
    252219        ev = e.xmaprequest 
    253220        wa = xlib.XWindowAttributes() 
    254          
     221 
    255222        if not xlib.XGetWindowAttributes(e.xany.display, ev.window, byref(wa)): 
     223            log.debug('couldnt get XGetWindowAttributes') 
    256224            return  
    257225 
     
    259227            return  
    260228 
    261         client = self.get_client_by_window(ev.window) 
     229        client = Client.get_by_window(ev.window) 
    262230        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() 
    273255 
    274256    def on_unmap_notify(self, e): 
    275257        ev = e.xunmap 
    276         client = self.get_client_by_window(ev.window) 
     258        client = Client.get_by_window(ev.window) 
    277259        if (client is not None and  
    278260            ev.event == xlib.XRootWindow(e.xany.display, client.screen.num) and  
     
    281263            client.remove() 
    282264 
    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  
    11import pyglet 
    22from pyglet.window.xlib import xlib  
     3 
     4import weakref 
    35 
    46from samuraix.sxctypes import * 
     
    1315 
    1416class 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 
    1525    def __init__(self, screen, window, wa): 
    1626        self.screen = screen 
     
    2030        self.maxed_geom = self.geom.copy() 
    2131        self.old_border = wa.border_width 
     32        self.desktop = screen.active_desktop 
    2233 
    2334        self.configure_window() 
    2435        self.update_title() 
    2536        self.update_size_hints() 
     37        self.update_wm_hints() 
     38        self.check_ewmh() 
    2639 
    2740        xlib.XSelectInput(samuraix.display, window,  
     
    3043                xlib.EnterWindowMask) 
    3144 
    32         log.debug("new client with %s %s" % (self.window, self.geom)) 
     45        log.info("new client with %s %s" % (self.window, self.geom)) 
    3346 
    3447        self.buttons = [ 
     
    3649            (3, xlib.Mod4Mask, self.mouseresize), 
    3750        ] 
     51 
     52        self.all_clients.append(self) 
     53        self.window_2_client_map[self.window] = self 
     54 
    3855 
    3956    def __str__(self): 
     
    5673                xlib.StructureNotifyMask, cast(byref(ce), POINTER(xlib.XEvent))) 
    5774 
     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 
    5887    def update_title(self): 
    5988        self.title = xhelpers.get_text_property(self.window, samuraix.atoms['_NET_WM_NAME']) 
    6089        if not self.title: 
    6190            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)) 
    6392     
    6493    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 
    66163 
    67164    def resize(self, geometry, hints=False): 
     
    88185 
    89186    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) 
    91196 
    92197    def remove(self): 
    93         samuraix.app.clients.remove(self) 
    94          
     198        log.debug('removing %s' % self) 
    95199        wc = xlib.XWindowChanges() 
    96200 
     
    101205 
    102206        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) 
    104208        xlib.XSync(samuraix.display, False) 
    105209        xlib.XUngrabServer(samuraix.display) 
     210 
     211        self.all_clients.remove(self) 
    106212         
    107213    def on_button_press(self, ev): 
     
    246352 
    247353    def ban(self): 
     354        log.debug('banning %s' % self) 
    248355        xlib.XUnmapWindow(samuraix.display, self.window) 
    249356        xhelpers.set_window_state(self.window, xlib.IconicState) 
     
    251358 
    252359    def unban(self): 
     360        log.debug('unbanning %s' % self) 
    253361        xlib.XMapWindow(samuraix.display, self.window) 
    254362        xhelpers.set_window_state(self.window, xlib.NormalState) 
    255363        # titlebar remap here 
    256364                 
     365    def move_to_desktop(self, desktop): 
     366        desktop.remove_client 
    257367 
    258368Client.register_event_type('on_button_press') 
  • samurai-x/samuraix/desktop.py

    r42db8f r3b72c6  
    22import pyglet 
    33 
     4import weakref 
     5 
    46import samuraix 
     7 
     8import logging 
     9log = logging.getLogger(__name__) 
    510 
    611class Desktop(pyglet.event.EventDispatcher): 
     
    914        self.name = name 
    1015 
     16        log.info('created new desktop %s' % self) 
     17 
    1118        self.clients = [] 
    1219 
     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 
     46Desktop.register_event_type('on_show') 
     47Desktop.register_event_type('on_hide') 
     48 
  • samurai-x/samuraix/main.py

    r42db8f r3b72c6  
    1  
    2 import os 
    3  
    41import pyglet 
    52pyglet.options['shadow_window'] = False 
     
    107import samuraix 
    118from samuraix.sxctypes import * 
    12 from samuraix import keydefs 
     9from samuraix import xhelpers 
    1310 
    1411import logging 
     
    1613 
    1714 
    18 def open_display(displayname=None): 
    19     if displayname is None: 
    20         displayname = os.environ.get('DISPLAY', ':0') 
    21     samuraix.displayname = displayname 
    22  
    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 = 0  
    37  
    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 << i 
    42  
    43     xlib.XFreeModifiermap(modmap) 
    44  
    45     xlib.NumLockMask = mask 
    46  
    47  
    4815def init_atoms(): 
     16    log.info('creating atoms instance...') 
    4917    from samuraix.atoms import Atoms 
    5018    samuraix.atoms = Atoms() 
    5119 
     20 
    5221def init_cursors(): 
     22    log.info('creating cursors instance...') 
    5323    from samuraix.cursors import Cursors 
    5424    samuraix.cursors = Cursors() 
     
    6333 
    6434def load_config(): 
     35    log.info('loading config...') 
    6536    samuraix.config = { 
    6637        'screens': { 
    67             '0': { 
     38            0: { 
    6839                'virtual_desktops': [ 
    6940                    {'name': 'one'}, 
     
    7950    configure_logging() 
    8051 
     52    xhelpers.open_display() 
     53    xhelpers.check_for_other_wm() 
     54    #xhelpers.setup_xerror() 
     55 
    8156    load_config() 
    8257 
    83     open_display() 
    8458    init_atoms() 
    85     get_numlock_mask() 
     59    xhelpers.get_numlock_mask() 
    8660    init_cursors() 
    8761 
    88     app.register_x_event_handlers() 
     62    log.info('creating app instance...') 
    8963    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 
    9172 
    9273if __name__ == '__main__':     
    93     from samuraix.app import App 
     74    from samuraix.appl import App 
    9475    run(App) 
    9576 
  • samurai-x/samuraix/screen.py

    r42db8f r3b72c6  
    11import pyglet 
    22from pyglet.window.xlib import xlib  
     3 
     4import weakref 
     5import functools 
    36 
    47import samuraix 
     
    69from samuraix.xconstants import BUTTONMASK, CLEANMASK 
    710from samuraix.desktop import Desktop 
    8 from samuraix import keydefs 
     11from samuraix.statusbar import Statusbar 
     12from samuraix import keysymdef 
    913from samuraix.testfunc import testfunc 
     14from samuraix.sxctypes import * 
     15from samuraix import xatom 
     16from samuraix.xhelpers import get_window_state 
     17from samuraix.client import Client 
    1018 
    1119import logging 
    1220log = logging.getLogger(__name__) 
    1321 
     22def xterm(): 
     23    from subprocess import * 
     24    pid = Popen(["/usr/bin/xterm"]).pid 
     25 
     26 
    1427class Screen(pyglet.event.EventDispatcher): 
     28 
    1529    _default_conf = { 
    1630        'virtual_desktops': [ 
    1731            {'name':'one'}, 
    1832        ], 
     33        'status_bar': { 
     34            'position': 'top', 
     35        } 
    1936    } 
     37 
     38    client_class = Client 
    2039 
    2140    def __init__(self, num, buttons=None): 
     
    2746        self.buttons = () if buttons is None else buttons 
    2847        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')), 
    3055        ] 
    3156         
    3257        self.desktops = [] 
     58        self.active_desktop = None 
     59 
     60        self.clients = [] 
     61 
     62        self.config = self._default_conf.copy() 
    3363 
    3464        try: 
    35             conf = samuraix.config['screens'][self.num] 
     65            self.config.update(samuraix.config['screens'][self.num]) 
    3666        except KeyError: 
    37             conf = self._default_conf 
    38  
    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']: 
    4070            desktop = Desktop(self, conf_desktop['name']) 
    4171            self.desktops.append(desktop) 
    4272 
    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() 
    44103 
    45104    def __str__(self): 
     
    50109    root_window = property(_get_root_window) 
    51110 
    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): 
    53181        for desktop in self.desktops: 
    54182            if desktop.name == name: 
    55                 self.active_desktop = self.desktops[name] 
     183                self.set_active_desktop(desktop) 
    56184                return 
    57185        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') 
    58203 
    59204    def on_button_press(self, ev): 
     
    64209    def on_key_press(self, ev): 
    65210        keysym = xlib.XKeycodeToKeysym(samuraix.display, ev.keycode, 0) 
     211        log.debug('on_key_press %s %s %s' % (self, keysym, ev.keycode)) 
    66212        for ks, modifiers, func in self.keys: 
    67213            if ks == keysym and CLEANMASK(modifiers) == CLEANMASK(ev.state): 
     214                log.debug('doing %s' % func) 
    68215                func() 
     216                return 
     217        log.debug('not handler founnd') 
    69218 
    70219    def grab_buttons(self): 
     
    91240 
    92241    def grab_keys(self): 
    93         log.debug("gab_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() 
    98247        for keysym, modifiers, func in self.keys: 
    99248            kc = xlib.XKeysymToKeycode(samuraix.display, keysym) 
     
    112261                root, True, xlib.GrabModeAsync, xlib.GrabModeAsync) 
    113262 
     263    def ungrab_keys(self): 
     264        xlib.XUngrabKey(samuraix.display, xlib.AnyKey, xlib.AnyModifier, self.root_window)  
     265 
    114266 
    115267Screen.register_event_type('on_button_press') 
    116268Screen.register_event_type('on_key_press') 
    117  
    118  
     269Screen.register_event_type('on_desktop_change') 
     270Screen.register_event_type('on_client_add') 
     271 
     272 
  • samurai-x/samuraix/xconstants.py

    r0540af r3b72c6  
    44xlib.XModifierKeymap_p = POINTER(xlib.XModifierKeymap) 
    55xlib.Window_p = POINTER(xlib.Window) 
     6xlib.RevertToPointerRoot = xlib.PointerRoot 
    67 
    78BUTTONMASK = (xlib.ButtonPressMask | xlib.ButtonReleaseMask) 
  • samurai-x/samuraix/xhelpers.py

    r42db8f r3b72c6  
     1import os 
     2 
    13from pyglet.window.xlib import xlib  
    24from samuraix.sxctypes import * 
    35 
    46import samuraix 
     7from samuraix import keysymdef 
     8 
     9import logging 
     10log = logging.getLogger(__name__) 
     11 
    512 
    613def get_window_state(window): 
     
    4249 
    4350 
     51def 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 
     66def close_display(): 
     67    log.info('closing display..') 
     68    xlib.XSync(samuraix.display, False) 
     69    xlib.XCloseDisplay(samuraix.display) 
     70 
     71 
     72def 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 
     87def 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 
     104def 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)