Check-in [3740586cc4]
Not logged in

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

Overview
Comment:
  • Added some basic info about layouts to minx.core.wm doc string.
  • Updated hooks-list.wiki with info about new hooks.
  • Fixed a bug in layman.receptive_layout(): have to add layout returned by receptive_layout_hook to layouts list.
  • In layman.find(), added ability to search for layouts based on their names. (Noticed we needed this ability when writing sample code to illustrate layouts usage.)
  • Removed unnecessary warnings from minxlib::window, which were simply cluttering the log.
  • Other minor edits elsewhere.
Timelines: family | ancestors | descendants | both | dev1.x
Files: files | file ages | folders
SHA1:3740586cc47081a34eeec94272c3924c52607735
User & Date: manuv 2013-08-01 19:12:50
Context
2013-08-03
00:27
Updated various bits of documentation (most of it concetrated in minx.core.hooks and minx.core.layman). check-in: d1c87b1563 user: manuv tags: dev1.x
2013-08-01
19:12
  • Added some basic info about layouts to minx.core.wm doc string.
  • Updated hooks-list.wiki with info about new hooks.
  • Fixed a bug in layman.receptive_layout(): have to add layout returned by receptive_layout_hook to layouts list.
  • In layman.find(), added ability to search for layouts based on their names. (Noticed we needed this ability when writing sample code to illustrate layouts usage.)
  • Removed unnecessary warnings from minxlib::window, which were simply cluttering the log.
  • Other minor edits elsewhere.
check-in: 3740586cc4 user: manuv tags: dev1.x
2013-07-31
01:06
Minor updates to make doxygen work without warnings. check-in: 690640b8e9 user: manuv tags: dev1.x
Changes

Changes to core/config.py.

114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
247
248
249
250
251
252
253

254
255
256
257
        @li <tt>terminal</tt> <b>(string)</b> [<em>xterm</em>]:
            This field specifies the command to use for launching a
            terminal window. Your PATH variable will be searched to find
            it; so you don't have to specify a full path. Moreover, you
            can supply command-line arguments for the terminal program
            in this setting and they will be passed as-is. Minx's
            default configuration defines a
            <a href="../wiki/hooks-list.wiki#launch_terminal>key binding</a> 
            that uses the value of this setting.
        @li <tt>synchronize_xlib</tt> <b>(Boolean)</b> [<em>False</em>]:
            If set to <tt>True</tt>, Xlib calls will be synchronous;
            otherwise, the X protocol operates asynchronously.
            Synchronous mode can be useful for debugging.

    """
................................................................................

##############################################
# Editor config:                             #
##############################################
# Local Variables:                           #
# indent-tabs-mode: nil                      #
# py-indent-offset: 4                        #

# End:                                       #
##############################################
# vim: set expandtab shiftwidth=4 tabstop=4: #
##############################################







|







 







>




114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
247
248
249
250
251
252
253
254
255
256
257
258
        @li <tt>terminal</tt> <b>(string)</b> [<em>xterm</em>]:
            This field specifies the command to use for launching a
            terminal window. Your PATH variable will be searched to find
            it; so you don't have to specify a full path. Moreover, you
            can supply command-line arguments for the terminal program
            in this setting and they will be passed as-is. Minx's
            default configuration defines a
            <a href="../wiki/hooks-list.wiki#launch_terminal>key binding</a>
            that uses the value of this setting.
        @li <tt>synchronize_xlib</tt> <b>(Boolean)</b> [<em>False</em>]:
            If set to <tt>True</tt>, Xlib calls will be synchronous;
            otherwise, the X protocol operates asynchronously.
            Synchronous mode can be useful for debugging.

    """
................................................................................

##############################################
# Editor config:                             #
##############################################
# Local Variables:                           #
# indent-tabs-mode: nil                      #
# py-indent-offset: 4                        #
# python-indent: 4                           #
# End:                                       #
##############################################
# vim: set expandtab shiftwidth=4 tabstop=4: #
##############################################

Changes to core/focus_list.py.

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
...
187
188
189
190
191
192
193

194
195

196
197
198
199
200


201

        """
        self._head = None

    # Adding elements to the focus list
    def add(self, item):
        """Insert an item at the beginning of the list.

        @param item The item to be appended.

        This method inserts item (which can be of any type) at the
        beginning of the list, taking care to maintain circularity.

        @note We add new items to the beginning of the list because this
        is usually how we want input focus to behave: when a new window
        is created, it should acquire the input focus.
................................................................................
           self._remove_node(node)

    # Helper function for node removal
    def _remove_node(self, node):
        if node == self._head: # removing list's first element
           if (self._head._left  == self._head and
               self._head._right == self._head): # list has only one element
              self._head._left  = None
              self._head._right = None
              self._head        = None
           else: # removing first element when list has more than one item
              tail = self._head._left
              tail._right = self._head._right
              self._head._right._left = tail
              self._head._left  = None
              self._head._right = None
              self._head = tail._right
        else: # removing an item after the lists' first element
           node._left._right = node._right
           node._right._left = node._left
           node._left  = None
           node._right = None

    # Helper function for finding items in list
    def _find(self, item):
        if self._head == None: # list is empty
           return None         # therefore, it cannot contain item

        if self._head._item == item: # item is list's first element
................................................................................

        """
        if self._head != None:
           self._head  = self._head._left

#-----------------------------------------------------------------------


# Editor config:
#

# Local Variables:
# indent-tabs-mode: nil
# py-indent-offset: 4
# End:
#


# vim: expandtab shiftwidth=4 tabstop=4








|







 







|
|
|

|
|
|
|
|
|

|
|
|
|







 







>
|
<
>
|
|
|
<
|
>
>
|
>
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
...
187
188
189
190
191
192
193
194
195

196
197
198
199

200
201
202
203
204
        """
        self._head = None

    # Adding elements to the focus list
    def add(self, item):
        """Insert an item at the beginning of the list.

        @param item The item to be added.

        This method inserts item (which can be of any type) at the
        beginning of the list, taking care to maintain circularity.

        @note We add new items to the beginning of the list because this
        is usually how we want input focus to behave: when a new window
        is created, it should acquire the input focus.
................................................................................
           self._remove_node(node)

    # Helper function for node removal
    def _remove_node(self, node):
        if node == self._head: # removing list's first element
           if (self._head._left  == self._head and
               self._head._right == self._head): # list has only one element
               self._head._left  = None
               self._head._right = None
               self._head        = None
           else: # removing first element when list has more than one item
               tail = self._head._left
               tail._right = self._head._right
               self._head._right._left = tail
               self._head._left  = None
               self._head._right = None
               self._head = tail._right
        else: # removing an item after the lists' first element
            node._left._right = node._right
            node._right._left = node._left
            node._left  = None
            node._right = None

    # Helper function for finding items in list
    def _find(self, item):
        if self._head == None: # list is empty
           return None         # therefore, it cannot contain item

        if self._head._item == item: # item is list's first element
................................................................................

        """
        if self._head != None:
           self._head  = self._head._left

#-----------------------------------------------------------------------

##############################################
# Editor config:                             #

##############################################
# Local Variables:                           #
# indent-tabs-mode: nil                      #
# py-indent-offset: 4                        #

# python-indent: 4                           #
# End:                                       #
##############################################
# vim: set expandtab shiftwidth=4 tabstop=4: #
##############################################

Changes to core/layman.py.

91
92
93
94
95
96
97
98
99
100
101
102

103
104
105
106



107
108
109








110
111
112
113
114
115
116
117
118
119
120
121
...
177
178
179
180
181
182
183




184
185
186
187
188
189
190
191
192
193
194


195
196
197
198
199
200
201
...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244

        This method adds the specified layout object to the layout
        manager's internal list and performs other necessary bookkeeping.

        """
        self._layouts.append(layout)

    # Find layout corresponding to specified window
    def find(self, w):
        """Return layout object given its X window.

        @param w The @ref minxlib::window "minxlib.window" to look for.


        This method searches all the layouts currently being managed by
        the layout manager to see if any of them corresponds to the
        window w. If there is such a layout, we will return that object.



        Otherwise, this function will raise an unknown_layout exception.

        """








        logger.debug('looking for layout corresponding to window {}'.
                     format(w.id))
        for layout in self._layouts:
            if layout.window == w:
               return layout
        raise unknown_layout(w)

    # Return layout with window that has the input focus
    def focused_layout(self):
        """Return current layout.

        This method returns the layout that has the top-level window that
................................................................................
        If no such layout exists, Minx will fall back to creating a new
        layout object on the same screen as the new window and use that
        as the receptive layout. The layout class used for this fallback
        policy is referred to as the default layout. Currently, Minx uses
        the @ref minx.layout.full.full "full layout" as the default
        layout class.





        """
        s = w.screen()
        logger.debug('looking for receptive layout for window {} on screen {}'.
                     format(w.id, s))

        logger.debug('looking for receptive layout via user hook')
        U = self._wm.hooks.trigger('receptive_layout_hook', w)
        if len(U) > 0:
           logger.info('receptive_layout_hook returned {}'.format(U[0]))
           if (U[0] != None and isinstance(U[0], layout.base) and
               U[0].window.screen() == s and U[0].will_manage(w)):


               return U[0] # use first layout returned by hook
           else:
               logger.warning('bad layout ({}) '.format(U[0]) +
                              'returned by receptive_layout_hook')

        F = self.focused_layout()
        logger.debug('checking focused layout {} for receptivity'.format(F))
................................................................................
    The layout manager raises this exception when it fails to find a
    layout object corresponding to some window.

    """
    def __init__(self, w):
        """Construct an unknown_layout.

        @param w The @ref minxlib::window "minxlib.window" for which
        there is no corresponding layout.

        The parameter w can be accessed as the exception's window member.

        """
        self.window = w

#------------------------------------------------------------------------







|

|

|
>



|
>
>
>
|


>
>
>
>
>
>
>
>
|
|
|
|
|







 







>
>
>
>











>
>







 







|
|







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262

        This method adds the specified layout object to the layout
        manager's internal list and performs other necessary bookkeeping.

        """
        self._layouts.append(layout)

    # Find layout corresponding to specified window or name
    def find(self, w):
        """Return layout object given either its X window or the window's name.

        @param  w A string or the @ref minxlib::window "minxlib.window" to find.
        @return Layout matching w.

        This method searches all the layouts currently being managed by
        the layout manager to see if any of them corresponds to the
        window w. If w is a string, then this method will look for a
        layout whose X window has the string w in its name.

        If there is no matching layout, this function will raise an
        unknown_layout exception.

        """
        if isinstance(w, str):
           logger.debug('looking for layout with "{}" in its name'.
                        format(w))
           for layout in self._layouts:
               name = layout.window.properties()['name']
               if w in name:
                  return layout
        else: # assume w refers to a minxlib.window
           logger.debug('looking for layout corresponding to window ID {}'.
                        format(w.id))
           for layout in self._layouts:
               if layout.window == w:
                  return layout
        raise unknown_layout(w)

    # Return layout with window that has the input focus
    def focused_layout(self):
        """Return current layout.

        This method returns the layout that has the top-level window that
................................................................................
        If no such layout exists, Minx will fall back to creating a new
        layout object on the same screen as the new window and use that
        as the receptive layout. The layout class used for this fallback
        policy is referred to as the default layout. Currently, Minx uses
        the @ref minx.layout.full.full "full layout" as the default
        layout class.

        @note End-user code should not need to call this function.
        Specifically, don't call this function from your
        <tt>receptive_layout_hook</tt>.

        """
        s = w.screen()
        logger.debug('looking for receptive layout for window {} on screen {}'.
                     format(w.id, s))

        logger.debug('looking for receptive layout via user hook')
        U = self._wm.hooks.trigger('receptive_layout_hook', w)
        if len(U) > 0:
           logger.info('receptive_layout_hook returned {}'.format(U[0]))
           if (U[0] != None and isinstance(U[0], layout.base) and
               U[0].window.screen() == s and U[0].will_manage(w)):
               if not U[0] in self._layouts:
                  self.add(U[0])
               return U[0] # use first layout returned by hook
           else:
               logger.warning('bad layout ({}) '.format(U[0]) +
                              'returned by receptive_layout_hook')

        F = self.focused_layout()
        logger.debug('checking focused layout {} for receptivity'.format(F))
................................................................................
    The layout manager raises this exception when it fails to find a
    layout object corresponding to some window.

    """
    def __init__(self, w):
        """Construct an unknown_layout.

        @param w The @ref minxlib::window "minxlib.window" or window name
        for which there is no corresponding layout.

        The parameter w can be accessed as the exception's window member.

        """
        self.window = w

#------------------------------------------------------------------------

Changes to core/wm.py.

142
143
144
145
146
147
148






























































149
150
151
152
153
154
155
...
162
163
164
165
166
167
168

169
170
171
172
173
174
175
...
200
201
202
203
204
205
206













207
208
209
210
211
212
213
    <a href="../wiki/hooks-list.wiki">Hooks List</a> documents all the
    hooks that Minx currently supports.

    One important use of hooks is for defining custom key bindings. The
    <a href="../wiki/key-bindings.wiki">Key Bindings HOWTO</a> has the
    details.































































    @note Although this class is defined in the minx.core.wm "package"
    and, technically, must be accessed as minx.core.wm.wm, it can, in
    fact (and as illustrated in the code snippets above), be referred to
    simply as minx.core.wm.

    """
    # Constructor
................................................................................
        manager. You will have to first create an instance of this class
        and then call its start() method to run the window manager. This
        constructor simply sets up some internal attributes, the most
        important of which are:

            @li config
            @li hooks


        The @ref minx.core.config.config "config" object specifies
        various settings such as the border colors, sizes, etc. To
        customize these settings, you will (typically) create a config
        object, change its various attributes, and pass that object into
        this constructor. (Alternatively, you could first create a wm
        object and then access its config attribute; however, the former
................................................................................
        One thing to keep in mind about hooks is that, since Minx uses
        them internally, it is easy to override its internal hooks and
        even disable them. Usually, this will cause Bad Things (TM) to
        happen. Thus, you should exercise care when dealing with
        "dangerous" hooks. As long as you stick to "external" hooks used
        by Minx specifically to effect customization, you should be
        okay.














        """
        if conf == None: # create a default config object
           conf =  config()
        self.config = conf

        # Configure Minx's root logger







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>







 







>
>
>
>
>
>
>
>
>
>
>
>
>







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
...
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
...
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
    <a href="../wiki/hooks-list.wiki">Hooks List</a> documents all the
    hooks that Minx currently supports.

    One important use of hooks is for defining custom key bindings. The
    <a href="../wiki/key-bindings.wiki">Key Bindings HOWTO</a> has the
    details.

    To customize how Minx arranges windows, you can:

        @li Specify the layouts you would like to use
        @li Specify the layout for particular windows
        @li Implement your own layouts

    Here is an example that illustrates the first two of the above
    possibilities:

    @verbatim
        #!/usr/bin/env python

        import minx

        def my_init_hook(m):
            scr = m.root_windows
            m.layouts.add(minx.layout.tall(m, scr[0]))
            m.layouts.add(minx.layout.rows(m, scr[1]))

        def my_receptive_layout_hook(w):
            prop = w.properties()
            if 'gimp' in prop['class'].lower():
                global wm
                try:
                    L = wm.layouts.find('gimp')
                    return L
                except minx.core.layman.unknown_layout:
                   parent = wm.root_windows[w.screen()]
                   return minx.layout.gimp(wm, parent)
            return None

        wm = minx.core.wm()
        wm.hooks.add('init_hook', my_init_hook)
        wm.hooks.add('receptive_layout_hook', my_receptive_layout_hook)
        wm.start()
    @endverbatim

    The <a href="../wiki/hooks-list.wiki#init_hook">init hook</a> allows
    you to setup the layouts you want to use. If you don't supply an init
    hook, Minx will use a default layout for each screen. At this time,
    the default layout is the @ref minx.layout.full.full "full" layout,
    which shows one window at a time by resizing windows to occupy the
    entire screen. In the above example, we use the tall layout for the
    first screen and the rows layout for the second screen. Of course,
    this would only work if you actually have two screens. Please also
    note that the tall and rows layout classes have not yet been
    implemented; we use these nonexistent layouts just to illustrate the
    intended spirit of layouts specification.

    The <a href="../wiki/hooks-list.wiki#receptive_layout_hook">receptive
    layout hook</a> allows you to either create or find a layout for each
    new window that Minx manages. In the above example, we created an
    instance of the gimp layout when Gimp starts up and use that for
    subsequent windows. For all other window types, we fall back to
    either the tall or rows layouts setup in the init hook. If, for some
    reason, the tall and rows layouts refuse to manage the new window,
    Minx will fall back its default, viz., the full layout. Again, like
    tall and rows, the gimp layout does not exist yet; it was used merely
    to illustrate how the receptive layout hook is intended to work.

    Documentation for implementing layouts will come later.

    @note Although this class is defined in the minx.core.wm "package"
    and, technically, must be accessed as minx.core.wm.wm, it can, in
    fact (and as illustrated in the code snippets above), be referred to
    simply as minx.core.wm.

    """
    # Constructor
................................................................................
        manager. You will have to first create an instance of this class
        and then call its start() method to run the window manager. This
        constructor simply sets up some internal attributes, the most
        important of which are:

            @li config
            @li hooks
            @li layouts

        The @ref minx.core.config.config "config" object specifies
        various settings such as the border colors, sizes, etc. To
        customize these settings, you will (typically) create a config
        object, change its various attributes, and pass that object into
        this constructor. (Alternatively, you could first create a wm
        object and then access its config attribute; however, the former
................................................................................
        One thing to keep in mind about hooks is that, since Minx uses
        them internally, it is easy to override its internal hooks and
        even disable them. Usually, this will cause Bad Things (TM) to
        happen. Thus, you should exercise care when dealing with
        "dangerous" hooks. As long as you stick to "external" hooks used
        by Minx specifically to effect customization, you should be
        okay.

        Finally, the @ref minx.core.layman.layman "layouts" object
        provides an interface for dealing with window layouts. By
        default, Minx uses the @ref minx.layout.full.full "full" layout,
        which shows one window at a time, resizing windows so that they
        occupy the entire screen. You can use the
        <a href="../wiki/hooks-list.wiki#init_hook">init hook</a> to add
        your preferred layouts to the layout manager.

        Another way to customize layout selection is to use the
        <a href="../wiki/hooks-list.wiki#receptive_layout_hook">receptive
        layout hook</a>, which provides a mechanism for deciding a layout
        for each new window.

        """
        if conf == None: # create a default config object
           conf =  config()
        self.config = conf

        # Configure Minx's root logger

Changes to minxlib/window.cc.

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
    prop["icon_name"] = "" ;
    prop["class"    ] = "" ;
    prop["res_name" ] = "" ;

    XTextProperty tp ;
    if (XGetWMName(m_display, m_id, &tp))
        prop["name"] = property_to_string(&tp) ;
    else
        logger.warning() << "unable to get WM_NAME for window " << m_id ;

    if (XGetWMIconName(m_display, m_id, &tp))
        prop["icon_name"] = property_to_string(&tp) ;
    else
        logger.warning() << "unable to get WM_ICON_NAME for window " << m_id ;

    XClassHint ch ;
    if (XGetClassHint(m_display, m_id, &ch)) {
        prop["class"] = ch.res_class ;
        prop["res_name"] = ch.res_name ;
        XFree(ch.res_class) ;
        XFree(ch.res_name ) ;
    }
    else
        logger.warning() << "unable to get WM_CLASS for window " << m_id ;

    return prop ;
}

void window::set_properties(const std::map<std::string, std::string>& prop)
{
    std::map<std::string, std::string>::const_iterator it = prop.find("name") ;
................................................................................
        char* p = const_cast<char*>(it->second.c_str()) ;
        if (XStringListToTextProperty(&p, 1, &tp)) {
            XSetWMName(m_display, m_id, &tp) ;
            XFree(tp.value) ;
            logger.debug() << "set WM_NAME for window " << m_id
                           << " to " << it->second ;
        }
        else
            logger.warning() << "unable to set WM_NAME for window " << m_id ;
    }

    it = prop.find("icon_name") ;
    if (it != prop.end()) {
        XTextProperty tp ;
        char* p = const_cast<char*>(it->second.c_str()) ;
        if (XStringListToTextProperty(&p, 1, &tp)) {
            XSetWMIconName(m_display, m_id, &tp) ;
            XFree(tp.value) ;
            logger.debug() << "set WM_ICON_NAME for window " << m_id
                           << " to " << it->second ;
        }
        else
            logger.warning() << "unable to set WM_ICON_NAME for window " << m_id;
    }

    XClassHint ch ;
    ch.res_class = 0 ;
    ch.res_name  = 0 ;
    it = prop.find("class") ;
    if (it != prop.end()) {







<
<



<
<








<
<







 







<
<












<
<







96
97
98
99
100
101
102


103
104
105


106
107
108
109
110
111
112
113


114
115
116
117
118
119
120
...
123
124
125
126
127
128
129


130
131
132
133
134
135
136
137
138
139
140
141


142
143
144
145
146
147
148
    prop["icon_name"] = "" ;
    prop["class"    ] = "" ;
    prop["res_name" ] = "" ;

    XTextProperty tp ;
    if (XGetWMName(m_display, m_id, &tp))
        prop["name"] = property_to_string(&tp) ;



    if (XGetWMIconName(m_display, m_id, &tp))
        prop["icon_name"] = property_to_string(&tp) ;



    XClassHint ch ;
    if (XGetClassHint(m_display, m_id, &ch)) {
        prop["class"] = ch.res_class ;
        prop["res_name"] = ch.res_name ;
        XFree(ch.res_class) ;
        XFree(ch.res_name ) ;
    }



    return prop ;
}

void window::set_properties(const std::map<std::string, std::string>& prop)
{
    std::map<std::string, std::string>::const_iterator it = prop.find("name") ;
................................................................................
        char* p = const_cast<char*>(it->second.c_str()) ;
        if (XStringListToTextProperty(&p, 1, &tp)) {
            XSetWMName(m_display, m_id, &tp) ;
            XFree(tp.value) ;
            logger.debug() << "set WM_NAME for window " << m_id
                           << " to " << it->second ;
        }


    }

    it = prop.find("icon_name") ;
    if (it != prop.end()) {
        XTextProperty tp ;
        char* p = const_cast<char*>(it->second.c_str()) ;
        if (XStringListToTextProperty(&p, 1, &tp)) {
            XSetWMIconName(m_display, m_id, &tp) ;
            XFree(tp.value) ;
            logger.debug() << "set WM_ICON_NAME for window " << m_id
                           << " to " << it->second ;
        }


    }

    XClassHint ch ;
    ch.res_class = 0 ;
    ch.res_name  = 0 ;
    it = prop.find("class") ;
    if (it != prop.end()) {

Changes to wiki/hooks-list.wiki.

5
6
7
8
9
10
11

12

13
14
15
16
17
18
19

20
21
22
23
24
25
26
..
32
33
34
35
36
37
38
























































39
40
41
42
43
44
45
...
102
103
104
105
106
107
108








































109
110
111
112
113
114
115
...
170
171
172
173
174
175
176







177
178
179
180
181
182
183
end-users to define their own hooks and triggers those hooks in response
to different events/situations.

This page documents all of Minx's currently supported hooks, both
internal ones and those meant for end-users. Here is the complete list:

[#end-user-hooks|End-user Hooks]

  #  [#manage_hook|manage_hook]


[#default-key-bindings|Default Key Bindings]
  #  [#focus_next|A-Tab]
  #  [#focus_prev|S-A-Tab]
  #  [#focus_kill|A-F4]
  #  [#focus_nuke|C-F4]
  #  [#launch_terminal|C-A-T]


[#internal-hook|Internal Hooks]
  #  [#x_create_notify|x_create_notify]
  #  [#x_destroy_notify|x_destroy_notify]
  #  [#x_configure_request|x_configure_request]
  #  [#x_map_request|x_map_request]
  #  [#x_map_notify|x_map_notify]
................................................................................

<a name="end-user-hooks"></a>
<h1>End-user Hooks</h1>

Minx triggers these hooks to allow end-users to customize how the window
manager responds to different events.

























































<a name="manage_hook"></a>
<h2>manage_hook</h2>

Minx triggers this hook when a new window is created. It will pass to
each <tt>manage_hook</tt> a
[/doc/ckout/api/classminxlib_1_1window.html|minxlib.window] object and
expects a <tt>True</tt> or <tt>False</tt> return value to decide whether
................................................................................
</verbatim>

In a similar vein, you can use regular expressions and other such
techniques to check against a multitude of patterns to decide whether or
not to manage a given window without needing more than one
<tt>manage_hook</tt>.









































<hr>

<a name="default-key-bindings"></a>
<h1>Default Key Bindings</h1>

Key bindings are simply hooks whose names follow the pattern described
[/doc/ckout/wiki/key-bindings.wiki|here]. Whenever a keyboard event
................................................................................
    conf = minx.core.config()
    conf.terminal = 'gnome-terminal'

    wm = minx.core.wm(conf)
    wm.start()
</verbatim>








<hr>

<a name="internal-hooks"></a>
<h1>Internal Hooks</h1>

Minx defines and uses these hooks internally to respond to events
generated by the X server. In general, you should not override these







>

>







>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
..
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
...
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
...
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
end-users to define their own hooks and triggers those hooks in response
to different events/situations.

This page documents all of Minx's currently supported hooks, both
internal ones and those meant for end-users. Here is the complete list:

[#end-user-hooks|End-user Hooks]
  #  [#init_hook|init_hook]
  #  [#manage_hook|manage_hook]
  #  [#receptive_layout_hook|receptive_layout_hook]

[#default-key-bindings|Default Key Bindings]
  #  [#focus_next|A-Tab]
  #  [#focus_prev|S-A-Tab]
  #  [#focus_kill|A-F4]
  #  [#focus_nuke|C-F4]
  #  [#launch_terminal|C-A-T]
  #  [#quit_wm|C-A-X]

[#internal-hook|Internal Hooks]
  #  [#x_create_notify|x_create_notify]
  #  [#x_destroy_notify|x_destroy_notify]
  #  [#x_configure_request|x_configure_request]
  #  [#x_map_request|x_map_request]
  #  [#x_map_notify|x_map_notify]
................................................................................

<a name="end-user-hooks"></a>
<h1>End-user Hooks</h1>

Minx triggers these hooks to allow end-users to customize how the window
manager responds to different events.

<a name="init_hook"></a>
<h2>init_hook</h2>

When you start Minx (by calling the
[/doc/ckout/api/classminx_1_1core_1_1wm_1_1wm.html|wm] object's start
method), it goes through the following sequence of steps:

  #  Connect to the X server
  #  Configure X event masks and key bindings
  #  Trigger the init hook
  #  Manage existing windows
  #  Initiate the X event loop

The intent of the init hook is to allow you to insert some custom
initialization before Minx starts managing windows and processing events
but after it has obtained a valid X connection. When the init hook is
called, you can be sure that the <tt>wm</tt> object's <tt>display</tt>
and <tt>root_windows</tt> attributes are available to you. The
<tt>display</tt> attribute is an instance of the
[/doc/ckout/api/classminxlib_1_1display.html|<tt>minxlib::display</tt>]
class and isn't something you would usually need to deal with directly.
However, <tt>wm.root_windows</tt> is almost certainly an attribute of
interest: it contains a list of
[/doc/ckout/api/classminxlib_1_1root__window.html|<tt>minxlib::root_window</tt>]
objects, one for each physical screen you have.

Typically, in the init hook, you will create layouts for each screen as
shown below:

<verbatim>
    #!/usr/bin/env python

    import minx

    def my_init_hook(m):
        scr = m.root_windows
        m.layouts.add(minx.layout.tall(m, scr[0]))
        if len(scr) > 1:
           for w in scr[1:]:
               m.layouts.add(minx.layout.full(m, w))

    wm = minx.core.wm()
    wm.hooks.add('init_hook', my_init_hook)
    wm.start()
</verbatim>

The above example sets up the first screen to use the tall layout and the
full layout on the remaining screens. Note that the tall layout has not
yet been implemented; it is used above merely for illustration.

There is no per-screen restriction on the number of layouts nor any
requirement that a layout occupy the entire screen. We kept it simple for
the sake of the example. However, you can create multiple layouts per
screen, assign them to different parts of the screens, and use whatever
criteria that fit your needs and that you can code up.

<a name="manage_hook"></a>
<h2>manage_hook</h2>

Minx triggers this hook when a new window is created. It will pass to
each <tt>manage_hook</tt> a
[/doc/ckout/api/classminxlib_1_1window.html|minxlib.window] object and
expects a <tt>True</tt> or <tt>False</tt> return value to decide whether
................................................................................
</verbatim>

In a similar vein, you can use regular expressions and other such
techniques to check against a multitude of patterns to decide whether or
not to manage a given window without needing more than one
<tt>manage_hook</tt>.

<a name="receptive_layout_hook"></a>
<h2>receptive_layout_hook</h2>

Once a window gets past the [#manage_hook|manage hook], to manage it,
Minx will assign it to a layout. The receptive layout hook, allows you to
find or create a layout for each new window. Here is an example:

<verbatim>
    #!/usr/bin/env python

    import minx

    def my_receptive_layout_hook(w):
        prop = w.properties()
        if 'gimp' in prop['class'].lower():
            global wm
            try:
                L = wm.layouts.find('gimp')
                return L
            except minx.core.layman.unknown_layout:
                parent = wm.root_windows[w.screen()]
                return minx.layout.gimp(wm, parent)
        return None

    wm = minx.core.wm()
    wm.hooks.add('receptive_layout_hook', my_receptive_layout_hook)
    wm.start()
</verbatim>

The above example returns a new gimp layout for the first Gimp window and
reuses that layout for subsequent windows that Gimp creates. For all
other window types, it returns nothing, which makes Minx use its default
policies for layout selection (read all about that on the
[/doc/ckout/api/classminx_1_1core_1_1layman_1_1layman.html|layout
manager's API page]).

Please note that there is no gimp layout. Thus, the above code won't
actually work; it is only meant to illustrate how the receptive layout
hook is meant to be used.

<hr>

<a name="default-key-bindings"></a>
<h1>Default Key Bindings</h1>

Key bindings are simply hooks whose names follow the pattern described
[/doc/ckout/wiki/key-bindings.wiki|here]. Whenever a keyboard event
................................................................................
    conf = minx.core.config()
    conf.terminal = 'gnome-terminal'

    wm = minx.core.wm(conf)
    wm.start()
</verbatim>

<a name="quit_wm"></a>
<h2>C-A-X</h2>

This key binding makes Minx get out of its event loop. Usually, this will
also quit the window manager (unless you have code in your Minx init file
after the call to <tt>wm.start()</tt>).

<hr>

<a name="internal-hooks"></a>
<h1>Internal Hooks</h1>

Minx defines and uses these hooks internally to respond to events
generated by the X server. In general, you should not override these