Check-in [ac0236beec]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:
  • Added support for end-user hook to create layouts before managing existing windows and entering event loop.
  • Made the display and root_windows members of the minx.core.wm class public (i.e., removed leading underscore) so that they can be accessed by the init_hook.
  • Removed unnecessary layout creation in wm.start() because the default layout logic in the layman.receptive_layout() method takes care of this already.
Timelines: family | ancestors | descendants | both | dev1.x
Files: files | file ages | folders
SHA1:ac0236beeca5359302debb28ddfd6d24b6bcace1
User & Date: manuv 2013-07-28 14:56:17
Context
2013-07-30
00:17
Added a function and default key binding to quit Minx. check-in: 33a1e31904 user: manuv tags: dev1.x
2013-07-28
14:56
  • Added support for end-user hook to create layouts before managing existing windows and entering event loop.
  • Made the display and root_windows members of the minx.core.wm class public (i.e., removed leading underscore) so that they can be accessed by the init_hook.
  • Removed unnecessary layout creation in wm.start() because the default layout logic in the layman.receptive_layout() method takes care of this already.
check-in: ac0236beec user: manuv tags: dev1.x
13:06
  • Forgotten to register exception translators for protocol errors.
  • Add exception handler for generic protocol errors in minx.core.wm event loop.
check-in: fa872bf983 user: manuv tags: dev1.x
Changes

Changes to core/layman.py.

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
...
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224

#------------------------------- IMPORTS --------------------------------

# Standard library
import logging

# Minx
import minx.layout

#---------------------------- MODULE LOGGER -----------------------------

logger = logging.getLogger(__name__)

#-------------------------------- CLASS ---------------------------------

................................................................................
        This method returns the layout that has the top-level window that
        currently has the input focus. If no window has the input focus
        or if there is no layout corresponding to the focused window,
        this method will return None.

        """
        logger.debug('looking for focused layout')
        w = self._wm._display.get_focused_window()
        logger.debug('focused window = {}'.format(w.id))
        if w.id == 0:
           logger.debug('no window currently focused')
           return None

        try:
            p = w.parent()
................................................................................
               continue
            if L.window.screen() == s and L.will_manage(w):
               logger.info('layout {} can and will manage window {}'.
                           format(L, w.id))
               return L

        logger.debug('no receptive layout found')
        D = layout.full(self._wm, w.parent())
        self.add(D)
        logger.info('falling back to default layout {} for window {}'.
                    format(D, w.id))
        return D

#----------------------------- EXCEPTIONS -------------------------------








|







 







|







 







|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
...
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224

#------------------------------- IMPORTS --------------------------------

# Standard library
import logging

# Minx
from minx import layout

#---------------------------- MODULE LOGGER -----------------------------

logger = logging.getLogger(__name__)

#-------------------------------- CLASS ---------------------------------

................................................................................
        This method returns the layout that has the top-level window that
        currently has the input focus. If no window has the input focus
        or if there is no layout corresponding to the focused window,
        this method will return None.

        """
        logger.debug('looking for focused layout')
        w = self._wm.display.get_focused_window()
        logger.debug('focused window = {}'.format(w.id))
        if w.id == 0:
           logger.debug('no window currently focused')
           return None

        try:
            p = w.parent()
................................................................................
               continue
            if L.window.screen() == s and L.will_manage(w):
               logger.info('layout {} can and will manage window {}'.
                           format(L, w.id))
               return L

        logger.debug('no receptive layout found')
        D = layout.full(self._wm, self._wm.root_windows[s])
        self.add(D)
        logger.info('falling back to default layout {} for window {}'.
                    format(D, w.id))
        return D

#----------------------------- EXCEPTIONS -------------------------------

Changes to core/wm.py.

272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
...
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
...
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
...
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
            # Step three: start the window manager
            wm.start()
        @endverbatim

        """
        self.connect_x()
        self.configure_x()
        for w in self._root_windows:
            self.layouts.add(layout.full(self, w))
        self.manage_existing()
        self.event_loop()

    # Connect to the X server
    def connect_x(self):
        """Connect to the X server.

................................................................................
        function.

        """
        try:
            conf = self.config
            logger.info('connecting to X server (synchronous = {})'.
                        format(conf.synchronize_xlib))
            self._display = minxlib.display(sync = conf.synchronize_xlib)
        except minxlib.connection_error as e:
            logger.critical(e)
            raise

    # Configure X to send us events we need to manage windows
    def configure_x(self):
        """Configure X server to send Minx events it needs to manage windows.
................................................................................
        If you decide not to use wm.start(), look at the Minx code to
        see how and what you will need to do to effectively use this
        function.

        """
        # Find hooks that correspond to key bindings
        logger.info('finding key binding hooks')
        km = '|'.join(self._display.get_keyboard_mapping())
        kb = re.compile('^(([CAS]|M[1-5]?)-)*(' + km + ')$')
        key_bindings = [n for n in self.hooks.names() if kb.search(n)]
        #logger.debug('km = {}'.format(km))
        logger.debug('key bindings hooks = {}'.format(' '.join(key_bindings)))

        # Setup event masks and passive grabs for all screens
        self._root_windows = self._display.get_root_windows()
        for w in self._root_windows:
            logger.info('configuring root window {}'.format(w.id))
            w.select_events(minxlib.substructure_redirect_mask |
                            minxlib.substructure_notify_mask   |
                            minxlib.key_press_mask)
            for k in key_bindings:
                w.grab_key(k)

................................................................................
        @par
        If you decide not to use wm.start(), look at the Minx code to
        see how and what you will need to do to effectively use this
        function.

        """
        logger.info('managing existing top-level windows')
        for w in self._display.get_top_level_windows():
            prop = w.properties()
            logger.debug('window {} class = {}, name = {}'.
                         format(w.id, prop['class'], prop['name']))
            if prop['class'] != 'minx.layout' and self.manage(w):
               self.layouts.receptive_layout(w).add(w)

    # Event loop
................................................................................
        function.

        """
        logger.info('entering event loop')
        while True:
            try:
                logger.debug('waiting for event')
                e = self._display.get_event()
                logger.debug('got event {}'.format(e))
                self.hooks.trigger(str(e), e)

            # Tried to query the window hierarchy of a non-existent
            # window. This happens when a window is destroyed and we
            # receive various other notifications before the destroy
            # notification comes in. Well, there's not much to be done in







|
<







 







|







 







|






|
|







 







|







 







|







272
273
274
275
276
277
278
279

280
281
282
283
284
285
286
...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
...
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
...
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
...
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
            # Step three: start the window manager
            wm.start()
        @endverbatim

        """
        self.connect_x()
        self.configure_x()
        self.hooks.trigger('init_hook', self)

        self.manage_existing()
        self.event_loop()

    # Connect to the X server
    def connect_x(self):
        """Connect to the X server.

................................................................................
        function.

        """
        try:
            conf = self.config
            logger.info('connecting to X server (synchronous = {})'.
                        format(conf.synchronize_xlib))
            self.display = minxlib.display(sync = conf.synchronize_xlib)
        except minxlib.connection_error as e:
            logger.critical(e)
            raise

    # Configure X to send us events we need to manage windows
    def configure_x(self):
        """Configure X server to send Minx events it needs to manage windows.
................................................................................
        If you decide not to use wm.start(), look at the Minx code to
        see how and what you will need to do to effectively use this
        function.

        """
        # Find hooks that correspond to key bindings
        logger.info('finding key binding hooks')
        km = '|'.join(self.display.get_keyboard_mapping())
        kb = re.compile('^(([CAS]|M[1-5]?)-)*(' + km + ')$')
        key_bindings = [n for n in self.hooks.names() if kb.search(n)]
        #logger.debug('km = {}'.format(km))
        logger.debug('key bindings hooks = {}'.format(' '.join(key_bindings)))

        # Setup event masks and passive grabs for all screens
        self.root_windows = self.display.get_root_windows()
        for w in self.root_windows:
            logger.info('configuring root window {}'.format(w.id))
            w.select_events(minxlib.substructure_redirect_mask |
                            minxlib.substructure_notify_mask   |
                            minxlib.key_press_mask)
            for k in key_bindings:
                w.grab_key(k)

................................................................................
        @par
        If you decide not to use wm.start(), look at the Minx code to
        see how and what you will need to do to effectively use this
        function.

        """
        logger.info('managing existing top-level windows')
        for w in self.display.get_top_level_windows():
            prop = w.properties()
            logger.debug('window {} class = {}, name = {}'.
                         format(w.id, prop['class'], prop['name']))
            if prop['class'] != 'minx.layout' and self.manage(w):
               self.layouts.receptive_layout(w).add(w)

    # Event loop
................................................................................
        function.

        """
        logger.info('entering event loop')
        while True:
            try:
                logger.debug('waiting for event')
                e = self.display.get_event()
                logger.debug('got event {}'.format(e))
                self.hooks.trigger(str(e), e)

            # Tried to query the window hierarchy of a non-existent
            # window. This happens when a window is destroyed and we
            # receive various other notifications before the destroy
            # notification comes in. Well, there's not much to be done in

Changes to core/xevents.py.

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
    # be managed by Minx or ignored.
    def _manage(self, e):
        prop = e.target.properties()
        logger.debug('window {} class = {}, name = {}'.
                     format(e.target.id, prop['class'], prop['name']))
        return (not e.override_redirect and
                prop['class'] != 'minx.layout' and
                e.parent in self._wm._root_windows and
                self._wm.manage(e.target))

    # When a new top-level window is created, the window manager has to
    # update its internal state to include this new window in its list
    # of top-level windows it has to manage.
    #
    # NOTE: We do not add new top-level windows to the focus list right







|







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
    # be managed by Minx or ignored.
    def _manage(self, e):
        prop = e.target.properties()
        logger.debug('window {} class = {}, name = {}'.
                     format(e.target.id, prop['class'], prop['name']))
        return (not e.override_redirect and
                prop['class'] != 'minx.layout' and
                e.parent in self._wm.root_windows and
                self._wm.manage(e.target))

    # When a new top-level window is created, the window manager has to
    # update its internal state to include this new window in its list
    # of top-level windows it has to manage.
    #
    # NOTE: We do not add new top-level windows to the focus list right

Changes to layout/base.py.

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
           m.hooks.add('x_reparent_notify', _on_reparent, m.hooks.MAX_PRIORITY)
           m.hooks.add(   'x_unmap_notify', _on_unmap,    m.hooks.MAX_PRIORITY)

        x, y, w, h = p.geometry()[:4] # don't need border width
        if r != None: # use supplied rectangle instead of entire parent window
           x, y, w, h = r

        self.window = m._display.create_window(p, x, y, w, h)

        name = 'minx.layout.{}.{}'.format(self.__class__.__name__,
                                          self.window.id)
        self.window.set_properties({'class': 'minx.layout', 'name' : name})
        self.window.select_events(minxlib.substructure_redirect_mask |
                                  minxlib.substructure_notify_mask)








|







163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
           m.hooks.add('x_reparent_notify', _on_reparent, m.hooks.MAX_PRIORITY)
           m.hooks.add(   'x_unmap_notify', _on_unmap,    m.hooks.MAX_PRIORITY)

        x, y, w, h = p.geometry()[:4] # don't need border width
        if r != None: # use supplied rectangle instead of entire parent window
           x, y, w, h = r

        self.window = m.display.create_window(p, x, y, w, h)

        name = 'minx.layout.{}.{}'.format(self.__class__.__name__,
                                          self.window.id)
        self.window.set_properties({'class': 'minx.layout', 'name' : name})
        self.window.select_events(minxlib.substructure_redirect_mask |
                                  minxlib.substructure_notify_mask)