Changes On Branch dev1.x
Not logged in

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

Changes In Branch dev1.x Excluding Merge-Ins

This is equivalent to a diff from e4acbfc0e4 to 49f4a20229

2013-08-04
09:47
Merged from dev1.x to rel1.x in anticipation of 0.2.0 release. check-in: a7356e4e43 user: manuv tags: rel1.x
09:28
Added rectangle to minx.layout.full constructor. Leaf check-in: 49f4a20229 user: manuv tags: dev1.x
08:43
Updated design notes. check-in: 3f11394238 user: manuv tags: dev1.x
2012-12-23
11:51
Create new branch named "rel1.x" check-in: 0a176bf6c5 user: mvnathan tags: rel1.x
2012-11-18
02:39
Added preliminary code for minxlib, a custom C++ wrapper around Xlib that will be exposed as a Python module for the rest of minx. At present, this is a pure C++ beastie without any Python wrapping. This check-in is just to get the build infrastructure in place... check-in: a8ee5c0982 user: mvnathan tags: dev1.x
2012-11-15
17:24
initial empty check-in Leaf check-in: e4acbfc0e4 user: mvnathan tags: trunk

Added CMakeLists.txt.

































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#
# top-level minx build spec
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki for the full list of authors who have
# contributed to this project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

# Min cmake version
cmake_minimum_required(VERSION 2.8)

# Project name
project(minx)

# Build sub-projects
add_subdirectory(minxlib)
add_subdirectory(dox)

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

Added __init__.py.





























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#
# __init__.py -- initialization for minx module
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki for the full list of authors who have
# contributed to this project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

#----------------------------- EXPORTS ---------------------------------

__all__ = ["core"]

# Pull in minx.core so that users don't have to do it explicitly
# themselves...
import core

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

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

Added core/__init__.py.











































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#
# __init__.py -- initialization for minx.core module
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki in the top-level directory of the Minx source
# distribution for the full list of authors who have contributed to this
# project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

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

# Pull in various classes from minx.core so that end-users see them as
# minx.core.wm instead of minx.core.wm.wm, minx.core.config instead of
# minx.core.config.config, and so on.
from wm import wm
from config import config

#----------------------------- EXPORTS ---------------------------------

__all__ = ["wm", "config", "hooks"]

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

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

Added core/config.py.





































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
#
# config.py -- various end-user settings
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki in the top-level directory of the Minx source
# distribution for the full list of authors who have contributed to this
# project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

#------------------------ MODULE DOC STRING ----------------------------

"""@package minx.core.config
Settings object.

This file defines a config class that contains attributes for various
settings through which end-users can effect simple customizations.

"""

#------------------------- CLASS DEFINITION ----------------------------

class config:
    """Attributes for simple customizations.

    This class has the following attributes to allow simple
    customizations. In the list below, the parenthesized term specifies
    the type of the attribute and the term in square brackets is the
    attribute's default value.

    <h3>Focus-related Customizations</h3>

        @li <tt>active_border_color</tt> <b>(int)</b> [<em>0xFF0000</em>]:
            This attribute specifies the color of the border of the
            window with the input focus. It should be a three-byte RGB
            packed into a single integer. The easiest way to specify
            this is as a 24-bit hex number, where byte 0 is blue, byte 1
            is green, and byte 2 is red. By default, the active window's
            border color is red.
        @li <tt>inactive_border_color</tt> <b>(int)</b> [<em>0xFFFFFF</em>]:
            This attribute specifies the color of unfocused windows. By
            default, this color is white.
        @li <tt>active_border_size</tt> <b>(int)</b> [<em>1</em>]:
            This attribute specifies the size (in pixels) of the border
            of the window with the input focus.
        @li <tt>inactive_border_size</tt> <b>(int)</b> [<em>1</em>]:
            This attribute specifies the border size (in pixels) of
            inactive windows.

    <h3>Logging Configuration</h3>

        @li <tt>logger</tt> <b>(dict)</b> [<em>see below</em>]:
            This field is passed to
            <a href="http://docs.python.org/2/library/logging.config.html#logging.config.dictConfig">logging.config.dictConfig()</a>.
            The default configuration sets up a
            <a href="http://docs.python.org/2/library/logging.handlers.html#logging.NullHandler">logging.NullHandler</a>
            to suppress Minx's log messages.

            To enable logging, use either log_to_console() to send log
            messages to STDERR or log_to_file() to send them to a file.
            You can also use log_level() to configure the level of
            verbosity.

            The above three functions should be enough to configure
            logging for the most common cases. However, you can further
            customize logging by retrieving the keys of the logger dict
            and reassigning them to the desired values. The following
            paragraphs provide some details.

            <tt>logger['formatters']['minx_formatter']</tt> will get you
            a reference to the formatter for Minx's log messages. This
            formatter is itself a dict with the keys <tt>'format'</tt>
            and <tt>'datefmt'</tt>. Consult the
            <a href="http://docs.python.org/2/library/logging.config.html#logging-config-dictschema">Python logging documentation</a>
            for further details about formatters.

            <tt>logger['handlers']['minx_handler']</tt> yields Minx's
            logging handler, which is also a dict with keys
            <tt>'class'</tt> and <tt>'formatter'</tt>. As mentioned
            above, the handler's <tt>'class'</tt> is
            <tt>'logging.NullHandler'</tt>. The value of the
            <tt>'formatter'</tt> key is <tt>'minx_formatter'</tt>. You
            should reset <tt>'class'</tt> to another logging handler
            class (e.g., <tt>'logging.FileHandler'</tt>). You should
            also set other keys appropriately. Consult the Python
            logging module's documentation for more info.

            Instead of using the predefined <tt>'minx_formatter'</tt>
            and <tt>'minx_handler'</tt> keys as described above, you can
            also reset the <tt>config</tt> object's <tt>logger</tt>
            attribute to anything you want.

    <h3>Miscellaneous Settings</h3>

        @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.

    """

    # Constructor
    def __init__(self):
        """Default values for various settings.

        Instantiating this class will result in a config object with
        default values for the various settings. Clients can then assign
        different values to the desired attributes to customize Minx and
        pass the modified config object to the @ref minx.core.wm.wm "wm"
        constructor.

        """
        self.active_border_color   = 0xFF0000
        self.inactive_border_color = 0xFFFFFF
        self.active_border_size    = 1
        self.inactive_border_size  = 1

        self.logger = self._init_logger()

        self.terminal = 'xterm'
        self.synchronize_xlib = False

    # Helper to initialize logger configuration
    def _init_logger(self):
        mesg_format = ('%(asctime)s.%(msecs)03d %(levelname)-9s' +
                       '%(name)-18s%(lineno)-5s%(funcName)s\n  ' +
                       '  %(message)s')
        date_format = '%Y-%m-%d %H:%M:%S'
        formatter   = {'format' : mesg_format,
                       'datefmt': date_format}

        # Helper class to strip "minx." prefix from module name of each
        # log record (to save some space on each header line). Also:
        # line number and function name for messages from the minxlib
        # module are incorrect; so this filter removes those things from
        # log records produced by the minxlib module.
        class _minx_logging_filter:
            def filter(self, log_record):
                log_record.name = log_record.name.replace('minx.', '')
                if log_record.name.startswith('minxlib'):
                   log_record.lineno   = ''
                   log_record.funcName = ''
                return 1
        filter_ = {'()': lambda: _minx_logging_filter()}

        handler = {'class'    : 'logging.NullHandler',
                   'formatter': 'minx_formatter',
                   'filters'  : ['minx_filter']}

        logger = {'handlers': ['minx_handler']}

        return {'version'   : 1,
                'formatters': {'minx_formatter': formatter},
                'filters'   : {'minx_filter'   : filter_  },
                'handlers'  : {'minx_handler'  : handler  },
                'loggers'   : {'minx'          : logger   }}

    # Convenience function for configuring logging to console
    def log_to_console(self):
        """Send log messages to STDERR.

        This is a convenience function that allows you to avoid dealing
        directly with the <tt>config.logger</tt> attribute's complicated
        dict-of-dict-of-dict structure. Using it, you can easily
        configure Minx's log messages to be printed to STDERR.

        """
        handler = self.logger['handlers']['minx_handler']
        handler['class'] = 'logging.StreamHandler'

    # Convenience function for configuring logging to a file
    def log_to_file(self, name, mode = 'w'):
        """Send log messages to a file.

        @param name Log file's name.
        @param mode Log file open mode; default = 'w'.

        One of the most common configurations for logging is to send log
        messages to a file. This function configures the
        <tt>config.logger</tt> attribute so that log messages will be
        written to the named file. By default, the log will be
        overwritten. However, if you use the value 'a' for the
        <tt>mode</tt> parameter, log messages will be appended to the
        file.

        As described earlier, you can configure Minx's logging by
        directly manipulating the <tt>config.logger</tt> dict. However,
        since that process can be somewhat convoluted and because
        sending log messages to a file is a fairly common thing to do,
        it's easier to use this function.

        """
        handler = self.logger['handlers']['minx_handler']
        handler['class'   ] = 'logging.FileHandler'
        handler['filename'] = name
        handler['mode'    ] = mode

    # Convenience function for configuring logging level
    def log_level(self, level):
        """Set the level of logging verbosity.

        @param level The log level from the Python logging module.

        The default log level is <tt>logging.WARNING</tt>. Thus, only
        <tt>WARNING</tt>, <tt>ERROR</tt>, and <tt>CRITICAL</tt> messages
        will be printed. However, with this function, you can change the
        log level to either produce more or fewer messages.

        Consult the Python logging documentation for more details about
        logging levels.

        """
        logger  = self.logger['loggers' ]['minx']
        handler = self.logger['handlers']['minx_handler']
        logger ['level'] = level
        handler['level'] = level

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

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

Added core/focus_list.py.

























































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
#
# focus_list.py -- circular, doubly linked list of top-level windows
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki in the top-level directory of the Minx source
# distribution for the full list of authors who have contributed to this
# project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

#------------------------ MODULE DOC STRING ----------------------------

"""@package wm.core.focus_list

This file defines the minx.core.focus_list.focus_list class, which can
be referred to simply as minx.core.focus_list.

"""

#------------------------- CLASS DEFINITION ----------------------------

class focus_list:
    """A doubly-linked circular list for keeping track of windows that
    can be focused.

    This class implements a doubly-linked circular list that is meant to
    be used by @ref minx.core.wm.wm "the window manager" for keeping
    track of the list of @ref minxlib::window "top-level windows" that
    can be focused. The head of this list will always be taken to be the
    currently focused window.

    """

    # Internal class for storing an item and references to its two
    # neighbours.
    class _node:
        def __init__(self, item):
            self._item  = item
            self._left  = None
            self._right = None

    # Constructor
    def __init__(self):
        """Create an empty list.

        """
        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.

        """
        node = self._node(item) # create a new node to store item
        if self._head == None:  # list is empty
           node._left  = node
           node._right = node
        else: # list has at least one element
           tail = self._head._left
           tail._right = node
           node._left  = tail
           node._right = self._head
           self._head._left = node
        self._head = node

    # Removing items from from the focus list
    def remove(self, item):
        """Remove specified item from list.

        @param item List item to be removed.

        This method searches the list for item and, if it is present,
        removes it, taking care to maintain circularity. If item is the
        first element in the list, the second element will become the
        list's new head after the removal.

        @note To be able to find item, we need its type to support the
        equality operator. Also, if item occurs more than once, the
        first instance will be removed.

        """
        node = self._find(item)
        if node == None: # list does not contain specified item
           return        # therefore, nothing to remove
        else:
           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
           return self._head         # so let's return that

        # Look for item starting at second element of list
        node = self._head._right
        while node != self._head:
            if node._item == item: # found it!
               return node
            node = node._right # no luck yet, examine next element

        # If we get to this point, then the list does not contain item
        return None

    # Return list's first element
    def head(self):
        """Return list's first element or None if list is empty.

        """
        if self._head == None:
           return None
        return self._head._item

    def forward(self):
        """Move head to next element.

        This method is meant to allow moving the input focus from the
        current @ref minxlib::window "top-level window" to the next one
        in the @ref minx.core.wm.wm "window manager's" list of windows
        that can be focused.

        If the focus list is empty, this function does nothing.

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

    def backward(self):
        """Move head to previous element.

        This method is meant to allow moving the input focus from the
        current @ref minxlib::window "top-level window" to the previous
        one in the @ref minx.core.wm.wm "window manager's" list of
        windows that can be focused.

        If the focus list is empty, this function does nothing.

        """
        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: #
##############################################

Added core/hooks.py.























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
##
# @file  hooks.py
# @brief Minx's hooking infrastructure.
# @defgroup grp_minx_core_hooks Hooks Infrastructure
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki in the top-level directory of the Minx source
# distribution for the full list of authors who have contributed to this
# project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

#------------------------ MODULE DOC STRING ----------------------------

"""@ingroup grp_minx_core_hooks
Minx's infrastructure for defining and using hooks.

This module defines the minx.core.hooks.hooks and related classes that
implement the infrastructure for defining and triggering hook functions,
which are callbacks that Minx invokes in response to different events.
Minx uses hooks both internally (to handle events sent by the X server)
and externally (to allow end-users to customize its responses to and
also to be notified of different window manager events).

"""

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

# Standard library
from heapq import heappush
import logging

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

logger = logging.getLogger(__name__)

#------------------------- CLASS DEFINITION ----------------------------

class hooks:
    """@ingroup grp_minx_core_hooks
    Mapping arbitrary key types to callable objects.

    This class maps keys (strings, ints, whatever) to prioritized lists
    of callables (i.e., functions or function objects). After a mapping
    has been setup, clients can trigger the functions for a key.

    This class provides a general infrastructure for Minx's support for
    customization via hooks. Although we can use any (reasonable) type
    as the keys, in Minx, keys are strings that name the different hooks
    that Minx supports (e.g., 'manage_hook', 'x_create_notify', and so
    on). If you name your hooks using a non-string type, those hooks
    will be added to the map but simply be ignored.

    """

    MIN_PRIORITY = 0
    MAX_PRIORITY = 101

    # Constructor
    def __init__(self):
        """Create an empty hook map.

        @return An empty hook map.

        When a new hooks object is created, it will have no hook
        functions in it. Clients (i.e., other Minx classes and
        functions or end-user configuration code) will have to then add
        hook functions to the hook map.

        @note In general, there should be no need in end-user code to
        create a hooks object. Rather, end-users should use the hooks
        attribute of the @ref minx.core.wm.wm "main window manager object".
        Refer to the <a href="../wiki/hooks-howto.wiki">Hooks HOWTO</a>
        for more on typical usage patterns for this class.

        """
        self._hooks = {}

    # Add a new function for some key
    def add(self, k, f, p = None):
        """Add a new function for some key.

        @param k The name of the hook.
        @param f The function to be executed for k.
        @param p The function priority (must be in range [1, 100]).

        This method adds f to the (prioritized) list of functions
        corresponding to k. If f is already in the list for k, it will
        not be duplicated. Thus, you can safely call this function
        multiple times with the same hook without worrying about
        creating duplicate entries in the hook lists or needing to
        first check to avoid duplication. This is useful, for example,
        when creating window objects that add hooks for various X
        events; the same function will be passed for each window
        instance and we don't want duplicate entries of the same
        function in our hook map (because each hook should be called
        once and only once per triggering).

        Priorities should be integers in the range [1, 100]. Higher
        numbers will insert f into the beginning of the list. If the
        priority p is not supplied, it will be assigned a default
        priority. Passing a non-integral value for the parameter p will
        also result in the priority for f being set to the default
        priority.

        To add a hook at the highest priority, pass MAX_PRIORITY as the
        value of p. Similarly, to add a hook at the lowest priority, pass
        MIN_PRIORITY as the value of p. Alternatively, to add hooks at
        the highest or lowest priorities, you can pass values greater
        than hundred or less than one respectively (however, using
        MAX_PRIORITY and MIN_PRIORITY is probably clearer).

        Here is a snippet of code illustrating how to add a hook for some
        event 'foo' so that it is the highest priority hook:

        @verbatim
            wm.hooks.add('foo', my_foo_hook, wm.hooks.MAX_PRIORITY)
        @endverbatim

        In general, you should not care about the order in which hooks
        execute. That is, you should implement hook functions so that the
        final result is the same regardless of the order of their
        execution. Having said that, however, such idealism is not always
        feasible, and, depending on the specific situation, perhaps not
        even wholly desirable. Thus, if you do need to control the order
        in which your hooks execute, you should be aware that the order
        in which you add hooks can be significant, especially if you use
        MIN_PRIORITY and MAX_PRIORITY.

        For example, let's say you have two hooks A and B for some key
        "foo" and want to execute A before B and B before every other
        hook for "foo." If you add the hooks in the following order:

        @verbatim
            wm.hooks.add('foo', A, wm.hooks.MAX_PRIORITY)
            wm.hooks.add('foo', B, wm.hooks.MAX_PRIORITY)
        @endverbatim

        B will end up at a higher priority than A and will execute before
        A instead of the other way around. This is because, MIN_PRIORITY
        and MAX_PRIORITY look at the current minimum and maximum
        priorities and are not absolute values. To achieve the effect
        described above, you should first add B and then A.
        Alternatively, you could also do the following:

        @verbatim
            wm.hooks.add('foo', A, wm.hooks.MAX_PRIORITY)
            wm.hooks.add('foo', B, wm.hooks.max_priority('foo'))
        @endverbatim

        The above code will first add A at the current highest priority
        for "foo" and then add B at the same priority as A.

        @note As mentioned earlier, although you can use any
        (reasonable) type for the hook map's keys, in Minx, we use
        strings as the keys. That is, pass a string as the first
        parameter k.

        """
        if k not in self._hooks:
           self._hooks[k] = priority_queue()

        if p == None or not isinstance(p, int):
           p = self.default_priority()
        elif p < 1:
           p = self.min_priority(k)
           if p == -1:
              p = self.default_priority() - 1
           else:
              p = max(1, p - 1)
        elif p > 100:
           p = self.max_priority(k)
           if p == -1:
              p = self.default_priority() + 1
           else:
              p = min(p + 1, 100)

        if self._hooks[k].add(f, p):
           logger.info('added hook: [{}, {}, {}]'.format(k, f.__name__, p))

    # Remove all hooks for specified name
    def remove(self, k):
        """Remove all hooks for specified name.

        @param k Name of hook that is to be removed.

        This function will remove all the hooks corresponding to the
        name k.

        Please understand that this is a fairly dangerous function! It
        is intended to be used in conjunction with hooks for key
        bindings. Specifically, you can use it to remove the default key
        bindings. Using it to remove other hooks will almost certainly
        lead to trouble.

        @note As mentioned earlier, although you can use any
        (reasonable) type for the hook map's keys, in Minx, we use
        strings as the keys. That is, pass a string for the parameter k.

        """
        if k in self._hooks:
           del self._hooks[k]
           logger.info('removed {} hooks'.format(k))

    # Rename specified hook
    def rename(self, k, n):
        """Rename the specified hook.

        @param k Current name of hook to be renamed.
        @param n New hook name.

        This function will assign the name n to the hooks currently
        identified by k. If the hook map does not contain any hooks
        corresponding to k, the function will do nothing. However, if
        there are already hooks assigned to n and to k, the older hooks
        for n will be replaced by the ones for k.

        Needless to say, this is a fairly dangerous function! Use it
        only to rename the default key bindings. Renaming other hooks is
        a Very Bad Idea (TM).

        @note Both k and n should be strings. Although you can use any
        (reasonable) type as keys for the hook map, Minx convention is
        to use strings. Other key types will result in "ghost" hooks,
        i.e., hook functions that are never triggered.

        """
        if k in self._hooks:
           self._hooks[n] = self._hooks[k]
           del self._hooks[k]
           logger.info('renamed {} hooks to {}'.format(k, n))

    # Call all the functions corresponding to a key
    def trigger(self, k, *p):
        """Execute functions for a given key.

        @param  k The name of the hook whose functions we want to call.
        @param  p Parameters to be passed to the hook functions.
        @return List of hook return values.

        This method triggers all the functions corresponding to k,
        calling them in order of descending priorities. Functions that
        have the same priority will be executed in the order in which
        they were added to the hook map.

        Each function will be passed the parameters in the positional
        args tuple p. Thus, hook functions can take an arbitrary number
        of arguments. Furthermore, these hook function parameters can be
        of any type; this method doesn't care and simply passes them
        through to the hooks as-is.

        This function collects the return values of all the hook
        functions for key k in a list. Callers of this function can use
        the return values in whatever way they please. For example,
        depending on the specific hook, you may:

            @li Simply ignore the hook return values.
            @li Use only the first return value, i.e., the value
                returned by the highest-priority hook.
            @li Use the last return value (i.e., last hook executed).
            @li Use all the return values.

        If a hook wants or needs to cut short the execution of the
        remaining hooks in its chain, it can raise a short_circuit
        exception. If the hook also wants to return a value along with
        cutting short its hook chain, it will have to pass the return
        value via the short_circuit exception.

        The hooks.trigger() function will stop executing the hooks for
        key k when it sees a short_circuit exception.

        @note As mentioned earlier, although you can use any
        (reasonable) type for the hook map's keys, in Minx, we use
        strings as the keys. That is, pass a string as the first
        parameter k.

        """
        ret = []
        if k in self._hooks:
           logger.debug('triggering {} hooks'.format(k))
           try:
               for f in self._hooks[k]:
                   ret.append(f(*p))
           except short_circuit as e:
               ret.append(e.retval)
        return ret

    # Get all the currently defined keys
    def names(self):
        """Get names of currently defined hooks.

        @return List of strings containing names of currently defined hooks.

        This function returns the names of all the currently defined
        hooks. Callers should not rely on the returned names being in
        any particular order.

        @note Although Minx uses strings for the keys in its hook map,
        if end-users add hooks using keys of other types, the returned
        list will contain those types as well. That is, Minx makes no
        effort to enforce using strings as hook names. If you do, that's
        fine; however, those particular hooks will not be triggered (so
        don't waste your time and your computer's resources).

        """
        return self._hooks.keys()

    # What is the maximum priority for some key?
    def max_priority(self, k):
        """Priority value of highest-priority hook for some key.

        @param  k The name of the hook.
        @return Priority (integer) of highest-priority hook corresponding to k.

        This function is intended to allow end-users to determine the
        priority of the current highest-priority hook function
        corresponding to k so that they can insert higher priority
        functions. Here is a somewhat contrived snippet of code
        illustrating typical usage:

        @verbatim
            #!/usr/bin/env python

            import minx

            def my_manage_hook(w):
                prop = w.properties()
                if prop['class'].lower() == 'gkrellm':
                   return False
                return True

            # Create window manager
            wm = minx.core.wm()

            # Ensure my_manage_hook is the first to execute
            m = wm.hooks.max_priority('manage_hook')
            if m < 0: # no manage_hook installed
               m = wm.hooks.default_priority() + 1
            else: # some module installed a manage_hook
               m = m + 1
            wm.hooks.add('manage_hook', my_manage_hook, m)

            # Okay, let's run the window manager...
            wm.start()
        @endverbatim

        The above example is contrived because if that is all your Minx
        start-up file contained, there would be no manage_hook
        installed and, so, no need to check to ensure that
        my_manage_hook() would execute first. Furthermore, usually,
        only a single manage_hook would be needed; there's no point to
        having multiple manage hooks.

        Moreover, to add a hook at the highest priority, you can simply
        pass MAX_PRIORITY to the call to hooks.add() instead of going
        about it yourself. For example, to add the highest priority hook
        for some event 'foo', you could just call the hooks.add() method
        as shown below:

        @verbatim
            wm.hooks.add('foo', my_foo_hook, wm.hooks.MAX_PRIORITY)
        @endverbatim

        Nonetheless, the example serves to illustrate how and why you
        might want to use the hooks.max_priority() function.

        Note that if the hook map does not contain any hooks for the
        key k, this function will return a negative number.

        @note As mentioned earlier, although you can use any
        (reasonable) type for the hook map's keys, in Minx, we use
        strings as the keys. That is, pass a string for the parameter k.

        """
        if k in self._hooks:
           return self._hooks[k].max_priority()
        return -1

    # What is the minimum priority for some key?
    def min_priority(self, k):
        """Priority value of lowest-priority hook for some key.

        @param  k The name of the hook.
        @return Priority (integer) of lowest-priority hook corresponding to k.

        This function is intended to allow end-users to determine the
        priority of the current lowest-priority hook function
        corresponding to k so that they can insert lower priority
        functions.

        Here is a somewhat contrived snippet of code illustrating
        typical usage:

        @verbatim
            #!/usr/bin/env python

            import minx

            def my_manage_hook(w):
                prop = w.properties()
                if prop['class'].lower() == 'gkrellm':
                   return False
                return True

            # Create window manager
            wm = minx.core.wm()

            # Ensure my_manage_hook is the last to execute
            m = wm.hooks.min_priority('manage_hook')
            if m < 0: # no manage_hook installed
               m = wm.hooks.default_priority() - 1
            else: # some module installed a manage_hook
               m = m - 1
            wm.hooks.add('manage_hook', my_manage_hook, m)

            # Okay, let's run the window manager...
            wm.start()
        @endverbatim

        The above example is contrived because if that is all your Minx
        start-up file contained, there would be no manage_hook
        installed and, so, no need to check to ensure that
        my_manage_hook() would execute last. Furthermore, usually,
        only a single manage_hook would be needed; there's no point to
        having multiple manage hooks.

        Moreover, to add a hook at the lowest priority, you can simply
        pass MIN_PRIORITY to the call to hooks.add() instead of going
        about it yourself. For example, to add the lowest priority hook
        for some event 'foo', you could just call the hooks.add() method
        as shown below:

        @verbatim
            wm.hooks.add('foo', my_foo_hook, wm.hooks.MIN_PRIORITY)
        @endverbatim

        Nonetheless, the example serves to illustrate how and why you
        might want to use the hooks.min_priority() function.

        If the hook map does not contain any hooks for the key k, this
        function will return a negative number.

        @note Typically, you would want your hooks to execute before
        currently installed hooks. Thus, this function is much less
        useful than hooks.max_priority(), but is provided for the sake
        of completeness and just in case someone or some situation
        finds it necessary.

        """
        if k in self._hooks:
           return self._hooks[k].min_priority()
        return -1

    # Default hook priority
    def default_priority(self):
        """Default priority for hooks.

        @return Integer specifying default hook priority.

        To allow end-users greater control over the execution order of
        hook functions, the minx.core.hooks.hooks class arranges hook
        functions according to priorities, which must be integers in
        the range [1, 100]. Higher priority hooks are executed before
        lower priority ones.

        If end-users don't specify the priority for a hook, it will be
        assigned the default priority, which is the value returned by
        this function.

        @note Since hook priorities must lie in [1, 100], we use 50 as
        the default priority as this will allow end-users to add their
        hooks both above and below the default level.

        """
        return 50

#------------------------- CLASS DEFINITION ----------------------------

class short_circuit(Exception):
    """@ingroup grp_minx_core_hooks
    An exception for cutting short the execution of a chain of hooks.

    This class allows an end-user hook function to have Minx stop
    excecuting the remaining hooks in its chain of hooks.

    @note In addition to being a customization mechanism available to
    end-users, Minx also uses hooks internally for various purposes.
    All hooks, internal and external, are stored in a single hook map
    maintained by the @ref minx.core.wm.wm "main window manager object".
    This design allows for a very powerful way of customizing the
    window manager because it gives you access to even the low-level X
    event processing...

    @par
    However, with great power comes great responsibilty! In general, it
    would be unwise to short-circuit Minx's internal hooks. That is,
    <em>just because you can, doesn't mean you should</em>. As a rule
    of thumb, use short-circuting only when you're absolutely sure it
    won't have an adverse effect.

    @par
    For example, the <tt>manage_hook</tt> is expected to return True or
    False depending on whether it wants a particular window managed or
    not. While it would be unusual to have more than one
    <tt>manage_hook</tt> (because one hook can perform multiple checks
    on window properties for all window types), if you do have more than
    one <tt>manage_hook</tt>, the one that returns a False can
    short-circuit the rest because Minx will only manage a window if all
    the manage hooks return True. Thus, if even one returns False,
    there's no point executing the remaining hooks; that one can simply
    short-circuit the rest of the <tt>manage_hook</tt> chain.

    """
    def __init__(self, ret = None):
        """Create a short_circuit exception with the specified return value.

        @param ret The hook's return value (default = None).

        If a function raises an exception, it cannot also communicate a
        return value to its caller using the usual function return
        mechanism. Instead, we allow the short-circuiting hook to stuff
        its return value into the short_circuit exception. The
        hooks.trigger() function will extract the return value from its
        short_circuit exception handler and also stop executing the
        remaining hooks in the short-circuiting hook's chain.

        Here is an example of an end-user hook short-circuiting its
        chain of hooks and returning a value:

        @verbatim
            #!/usr/bin/env python

            import minx
            from minx.core.hooks import short_circuit

            def my_manage_hook(w):
                prop = w.properties()
                if prop['class'].lower() == 'gkrellm':
                   raise short_circuit(False)
                return True

            wm = minx.core.wm()
            wm.hooks.add('manage_hook', my_manage_hook)
            wm.start()
        @endverbatim

        @note The return value can be anything the hook function wants
        to return. The exception and hooks classes don't care about it;
        they simply pass it back to the Minx function that triggered the
        hooks.

        """
        self.retval = ret

#------------------------- CLASS DEFINITION ----------------------------

class priority_queue:
    """@ingroup grp_minx_core_hooks
    A helper class for Minx's hooks implementation.

    This class implements a priority queue that the hooks class can use
    to prioritize its hook function lists.

    @note This class is not a general-purpose priority queue
    implementation. It is specifically designed for use by the
    minx.core.hooks.hooks class. It is also not meant to be used by
    end-users, who should treat it as internal to Minx.

    """

    # Constructor
    def __init__(self):
        """Create an empty priority queue.

        """
        self._queue  = [] # the priority queue
        self._values = {} # all values stored in p.q. (to prevent duplication)
        self._count  = 0  # for ordering values of the same priority

    # Add element to priority queue
    # NOTE: We negate priority because the standard library's heapq
    # module defaults to a min heap while we want a max heap (so that
    # high-priority hooks are executed first).
    def add(self, v, p):
        """Add an element with specified priority.

        @param  v The value to be added to the priority queue.
        @param  p The priority of the value to be added.
        @return False if priority queue already contains v; True otherwise.

        This function adds v with priority p to the priority queue.
        This function does not perform any checks on the value of p,
        requiring its caller to implement appropriate policies
        regarding priorities.

        If the priority queue already contains v, it will not be added
        again. Thus, clients can make repeated calls to this function
        with the same value without having to worry about creating
        duplicate entries.

        """
        if v not in self._values:
           heappush(self._queue, (-p, self._count, v)) # NOTE: -p for max heap
           self._values[v] = True # to prevent duplicate entries
           self._count += 1       # for ordering values of same priority
           return True
        return False # priority queue already contains v

    # Priority of highest-priority item
    def max_priority(self):
        """Return priority of highest-priority item in priority queue.

        If the priority queue is empty, this function will return -1.

        """
        # Each item in the priority queue is a 3-tuple, the first element
        # of which is the negated priority (for making a max heap).
        if len(self._queue) <= 0:
           return -1
        return -self._queue[0][0]

    # Priority of lowest-priority item
    def min_priority(self):
        """Return priority of lowest-priority item in priority queue.

        If the priority queue is empty, this function will return -1.

        """
        # Each item in the priority queue is a 3-tuple, the first element
        # of which is the negated priority (for making a max heap).
        if len(self._queue) <= 0:
           return -1
        return -self._queue[-1][0]

    # Iterator interface
    def __iter__(self):
        """Iterator interface to priority queue.

        This function returns an iterator for accessing the priority
        queue's elements in order of descending priority.

        """
        # Helper class to implement priority queue iterator
        class _iterator_adaptor:
            def __init__(self, pq):
                self._iter = iter(pq)
            def next(self):
                p, c, v = self._iter.next()
                return v # queue stores priority and count; we only want value
        return _iterator_adaptor(self._queue)

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

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

Added core/layman.py.



































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
##
# @file  layman.py
# @brief Class to manage layouts.
# @defgroup grp_minx_core_layman Layout Manager
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki in the top-level directory of the Minx source
# distribution for the full list of authors who have contributed to this
# project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

#-------------------------- MODULE DOC STRING ---------------------------

"""@ingroup grp_minx_core_layman
A helper for managing layouts.

This module defines helper classes for dealing with different layouts.
The layouts member of the @ref minx.core.wm.wm "main window manager object"
is an instance of the layout manager class. Both the main window manager
object as well as end-user code will use the layouts object to interface
with the different layout objects that Minx currently has.

"""

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

# Standard library
import logging

# Minx
from minx import layout

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

logger = logging.getLogger(__name__)

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

class layman:
    """@ingroup grp_minx_core_layman
    Layout manager.

    This class keeps track of the different layout objects created by
    end-users and also provides a convenient API for dealing with these
    layouts.

    """

    # Constructor
    def __init__(self, wm):
        """Construct layout manager.

        @param wm The @ref minx.core.wm.wm "main window manager object".

        The layout manager is meant to be used by the
        @ref minx.core.wm.wm "main window manager object". When the
        layout manager is created, we squirrel away a reference to the
        main wm object so we can later get access to the "global"
        @ref minx.core.config.config "config" object and any other things
        we might need from the wm object.

        """
        self._wm = wm
        self._layouts = []

    # Add a layout object to internal list
    def add(self, layout):
        """Add given layout object to the layout manager.

        @param layout The layout object to be added.

        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
        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()
            logger.debug('focused window = {}, its parent = {}'.
                         format(w.id, p.id))
            return self.find(p)
        except unknown_layout:
            logger.debug('no layout corresponding to focused window {}'.
                         format(w.id))
            return None

    # Find layout for new window
    def receptive_layout(self, w):
        """Find a layout to manage a new window.

        @param w The @ref minxlib::window "minxlib.window" to be managed.

        When a new window is created, Minx has to find a layout that will
        manage it. For lack of a better term, we refer to this layout as
        the receptive layout (because it will "receive" the new window).
        To find a layout willing and able to manage the new window, this
        function follows the procedure outlined below:

            @li Trigger the <tt>receptive_layout_hook</tt>.
            @li Failing that, check the focused layout.
            @li Failing that, search the remaining layouts.
            @li Failing that, create a new default layout.

        The <tt>receptive_layout_hook</tt> gives end-user code an
        opportunity to fine-tune the layout to be used for each window.
        If you have multiple functions for this hook, only the return
        value of the first one will be considered. That is, use only one
        hook for this; in fact, you shouldn't need an entire chain of
        hooks for the <tt>receptive_layout_hook</tt>.

        Minx will only accept the return value of the
        <tt>receptive_layout_hook</tt> if all of the following conditions
        are true:

            @li The return value is not None.
            @li It is an instance of the
                @ref minx.layout.base.base "minx.layout.base" class.
            @li The layout is on the same screen as w.
            @li The layout is willing to manage w.

        If the above-mentioned hook is not defined or if it returns
        something not fulfilling the above conditions, we check if the
        layout with the window that is currently focused is on the same
        screen as the new window and is willing to manage it. If so, this
        function will return the currently focused layout as the
        receptive layout, i.e., the layout that will manage the new
        window.

        If no window has the input focus, or if the focused layout is not
        on the same screen as the new window, or if it is unwilling to
        manage the new window, then we search the layout manager's
        remaining layouts for a layout that is on the same screen as the
        new window and is willing to manage it.

        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))
        if F != None and F.window.screen() == s and F.will_manage(w):
           logger.info('focused layout {} can and will manage window {}'.
                       format(F, w.id))
           return F

        logger.debug('checking remaining layouts for receptivity')
        for L in self._layouts:
            if L == F:
               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 -------------------------------

class unknown_layout(Exception):
    """@ingroup grp_minx_core_layman
    Unknown layout exception.

    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

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

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

Added core/window.py.























































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
105
106
107
##
# @file  window.py
# @brief Convenience functions for working with windows.
# @defgroup grp_minx_core_window Window Convenience API
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki in the top-level directory of the Minx source
# distribution for the full list of authors who have contributed to this
# project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

#-------------------------- MODULE DOC STRING ---------------------------

"""@ingroup grp_minx_core_window
Convenience functions for working with windows.

This module defines some convenience functions for dealing with
minxlib.window objects. Although you could simply call minxlib.window
functions directly, the functions defined in this module are more
convenient and also take into account things such as settings in
minx.core.config.

"""

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

# Standard library
import logging

# minx
import minxlib

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

logger = logging.getLogger(__name__)

#------------------------ CONVENIENCE FUNCTIONS -------------------------

# Reset border color and size to match focused window and then focus
# the window.
def focus(w, c):
    """@ingroup grp_minx_core_window
    Focus the specified window.

    @param w The minxlib.window object to be focused.
    @param c The minx.core.config object containing Minx settings.

    This function sets the window's border attributes to those of the
    active window and then raises and focuses the window.

    """
    logger.info('setting window {} border attributes: 0x{:0<6X}, {}'.
                format(w.id, c.active_border_color, c.active_border_size))
    w.set_border_attr(c.active_border_color, c.active_border_size)

    logger.debug('focusing window {}'.format(w.id))
    w.focus()

# Reset border color and size to match unfocused windows
def unfocus(w, c):
    """@ingroup grp_minx_core_window
    Unfocus the specified window.

    @param w The minxlib.window object to be unfocused.
    @param c The minx.core.config object containing Minx settings.

    This function sets the window's border attributes to those of
    inactive windows.

    """
    logger.info('setting window {} border attributes: 0x{:0<6X}, {}'.
                format(w.id, c.inactive_border_color, c.inactive_border_size))
    w.set_border_attr(c.inactive_border_color, c.inactive_border_size)

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

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

Added core/wm.py.

















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
#
# wm.py -- main object for interacting with the Minx window manager
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki in the top-level directory of the Minx source
# distribution for the full list of authors who have contributed to this
# project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

#------------------------ MODULE DOC STRING ----------------------------

"""@package minx.core.wm
Main interface object for Minx's end-users.

This file defines the minx.core.wm.wm class, which can be used simply as
minx.core.wm.

"""

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

# Standard library
import shlex, subprocess
import re, logging, logging.config
import sys, traceback

# Minx core
import window
from   layman     import layman
from   xevents    import xevents
from   hooks      import hooks
from   config     import config
from   focus_list import focus_list
import minxlib

# Minx layouts
from minx import layout

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

logger = logging.getLogger(__name__)

#------------------------- CLASS DEFINITION ----------------------------

class wm:
    """Main window manager object.

    This class encapsulates all the internal state required by the
    window manager. Typically, you will create an instance of this class
    in order to start the window manager. For example, the simplest Minx
    configuration would be a file with the following contents:

    @verbatim
        #!/usr/bin/env python
        import minx
        minx.core.wm().start()
    @endverbatim

    Of course, the above code requires the minx package to be in your
    Python path. But, assuming that is the case, it would start Minx
    with the default key bindings, hooks, and other settings.

    To make simple customizations, create an instance of the
    @ref minx.core.config.config "config" class and pass that to the wm
    constructor:

    @verbatim
        #!/usr/bin/env python

        import minx

        conf = minx.core.config()
        conf.active_border_color = 0x00FF00 # green

        minx.core.wm(conf).start()
    @endverbatim

    In addition to customizing window border attributes, the config
    class enables logging to be configured. Here is an example:

    @verbatim
        #!/usr/bin/env python

        import logging
        import minx

        conf = minx.core.config()
        conf.log_to_file('minx.log')
        conf.log_level(logging.DEBUG)

        minx.core.wm(conf).start()
    @endverbatim

    The <a href="../wiki/logging.wiki">Logging HOWTO</a> provides more
    details on logging configuration.

    Apart from the simple attribute customizations shown above, if you
    would also like to change the way Minx responds to various events,
    you will have to define hook functions and pass those to Minx. Here
    is a simple example:

    @verbatim
        #!/usr/bin/env python

        import minx

        def my_manage_hook(w):
            prop = w.properties()
            if prop['class'].lower() == 'gkrellm':
               return False
            return True

        wm = minx.core.wm()
        wm.hooks.add('manage_hook', my_manage_hook)
        wm.start()
    @endverbatim

    The above configuration will setup a manage hook that instructs Minx
    to ignore the GKrellM window. Have a look at the
    <a href="../wiki/hooks-howto.wiki">Hooks HOWTO</a> for lots more
    info about configuring Minx using hooks. Additionally, the
    <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
    def __init__(self, conf = None):
        """Create the main window manager object.

        @param conf Config object containing simple customizations.

        The wm class implements the main interface to the Minx window
        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.) If you don't supply
        a config object, the window manager will use default settings.

        The wm object's @ref minx.core.hooks.hooks "hooks" attribute
        maps names of hook functions (i.e., strings) to prioritized
        lists of callables. Minx will trigger these hooks at appropriate
        points in its event processing workflow. Minx uses hooks both
        internally (to handle various events) and "externally" (to allow
        end-users to customize its behaviour).

        To supply your own hooks, after creating a wm instance, use its
        hooks attribute to add hook functions for various events. Take a
        look at the <a href="../wiki/hooks-howto.wiki">Hooks HOWTO</a>
        for more on customizing Minx with hook functions. The
        <a href="../wiki/hooks-list.wiki">Hooks List</a> documents all
        the hooks currently supported by Minx.

        As mentioned earlier, Minx leverages its hooks mechanism to
        allow end-users to define custom key bindings. The
        <a href="../wiki/key-bindings.wiki">Key Bindings HOWTO</a>
        explains this feature.

        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
        logging.config.dictConfig(conf.logger)
        logger.info('starting Minx')

        # Other initialization
        logger.debug('creating focus list')
        self._focus_list = focus_list()

        logger.debug('creating layout manager')
        self.layouts = layman(self)

        logger.info('setting up X event handlers and default keybindings')
        self.hooks = hooks()
        self._xevents = xevents(self)
        self._init_keybindings()

        self._quit = False

    # Default keybindings
    def _init_keybindings(self):
        self.hooks.add(  'A-Tab', self.focus_next)
        self.hooks.add('S-A-Tab', self.focus_prev)
        self.hooks.add(   'A-F4', self.kill)
        self.hooks.add(   'C-F4', self.nuke)
        self.hooks.add(  'C-A-T', lambda: self.spawn(self.config.terminal))
        self.hooks.add(  'C-A-X', self.quit)

    # Start the window manager
    def start(self):
        """Start the window manager.

        Call this method after creating a wm instance to get Minx up and
        running. Here is an example showing how to start Minx with its
        default settings, key bindings, etc.:

        @verbatim
            #!/usr/bin/env python
            import minx
            minx.core.wm().start()
        @endverbatim

        If you would like to customize Minx by specifying your own hooks
        to be able to deal with various events, the initialization and
        start-up sequence will be a three step procedure as shown below:

        @verbatim
            #!/usr/bin/env python

            import minx

            # Define your hook functions
            def my_manage_hook(w):
                return True # actually, you would do something more useful

            # Step one: create window manager object
            wm = minx.core.wm()

            # Step two: customize using hooks
            wm.hooks.add('manage_hook', my_manage_hook)
            wm.hooks.add(  'F1', wm.focus_next) # custom key binding
            wm.hooks.add('S-F1', wm.focus_prev) # custom key binding

            # 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.

        This method connects to the X server. If we are unable to do so,
        it will raise a minxlib.connection_error.

        @note This method is mostly an internal one meant to be used by
        Minx itself. In fact, it is called by wm.start(). You should not
        really need to call it yourself. However, we provide this as a
        public method to allow customization in case you want to do
        something after connecting to X but before the other steps in
        Minx's usual start-up sequence.

        @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.

        """
        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.

        This method sets up the event mask for all the root windows so
        that Minx gets the notifications it needs to be able to manage
        windows. It also sets up passive keyboard grabs to make the
        keybindings mechanism work.

        @note This method is mostly an internal one meant to be used by
        Minx itself. In fact, it is called by wm.start(). You should not
        really need to call it yourself. However, we provide this as a
        public method to allow customization in case you want to do
        something after connecting to and setting up X but before the
        remaining steps in Minx's usual start-up sequence.

        @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.

        """
        # 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)

    # Manage extant top-level windows (we won't get create notifications
    # for these).
    def manage_existing(self):
        """Manage existing top-level windows.

        Minx uses this function to get the list of existing top-level
        windows and add them to its internal data structures so it can
        manage them. This is necessary, for example, when an end-user's
        ~/.xinitrc starts X programs before starting the window manager.
        It is also required when the window manager is restarted or when
        a user switches from another running window manager to Minx.

        @note This method is mostly an internal one meant to be used by
        Minx itself. In fact, it is called by wm.start(). You should not
        really need to call it yourself. However, we provide this as a
        public method to allow customization in case you want to do
        something after connecting to X, setting it up, and managing the
        existing top-level windows but before entering the event loop.

        @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
    def event_loop(self):
        """Retrieve and process X events.

        This method implements Minx's event loop. Once we enter this
        function, Minx will initiate an infinite loop, wherein it
        blocks, waiting for the X server to send it events. When it
        receives an event notification, it will trigger its internal
        event processing hooks to respond appropriately.

        @note This method is mostly an internal one meant to be used by
        Minx itself. In fact, it is called by wm.start(). You should not
        really need to call it yourself. However, we provide this as a
        public method to allow customization in case you want to do
        something after connecting to X, setting it up, and managing the
        existing top-level windows but right before entering the event
        loop.

        @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('entering event loop')
        while not self._quit:
            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
            # this situation; so, just log the error and keep going.
            except minxlib.query_tree_error as e:
                logger.warning(e)

            # Tried to focus a non-existent window (happens sometimes
            # upon window destruction, causing the resulting unmap and
            # focus notification handlers to go out-of-sync with the X
            # server's internal state). We can use the protocol error
            # that ensues as an opportunity to sync the internal states
            # of the window manager and X server.
            except minxlib.set_focus_error as e:
                logger.warning(e)
                self._focus_list.remove(e.resource_id)

            # Tried to change attributes of a non-existent window. This
            # used to happen when a window was destroyed and the
            # resulting focus_out event handler's attempt to set its
            # border color to the inactive window border color causes
            # unnecessary pain...
            #
            # However, now that we no longer rely on X's focus change
            # events to perform the window border update, this exception
            # should not be generated and its handler no longer
            # required. Nonetheless, it is in place for now; we can
            # remove it later on during development when the design has
            # stabilized enough for us to be absolutely sure this bit of
            # code is no longer required.
            except minxlib.change_window_attributes as e:
                logger.warning(e)
                if e.error_code == minxlib.bad_window:
                   pass # ignore protocol error (should be okay)

            # Generic protocol error
            except minxlib.protocol_error as e:
                logger.warning(e)

            # Some other exception: log it and keep going
            except:
                logger.warning('received {} exception'.
                               format(sys.exc_info()[0]))
                logger.debug(traceback.format_exc())

        logger.info('exiting event loop')


    # API to focus next window
    def focus_next(self):
        """Focus next window.

        This function passes input focus to the next window in the
        window manager's list of top-level windows that can accept input
        focus. It is meant to be invoked via a key binding's hook. Here
        is an example of intended usage:

        @verbatim
            #!/usr/bin/env python

            import minx

            wm = minx.core.wm()
            wm.hooks.add(  'F1', wm.focus_next)
            wm.hooks.add('S-F1', wm.focus_prev)
            wm.start()
        @endverbatim

        With that in your Minx start-up script, you will be able to
        cycle input focus with F1 and SHIFT + F1 (in addition to the
        default key bindings for focus cycling, viz., ALT + Tab and
        ALT + SHIFT + Tab).

        """
        L = self._focus_list
        old_head = L.head()
        L.forward()
        new_head = L.head()
        if new_head != old_head:
           logger.info('switching focus from {} to {}'.
                       format(old_head.id, new_head.id))
           window.unfocus(old_head, self.config)
           window.  focus(new_head, self.config)
        #else: new_head == old_head ==> focus list empty or only one window

    # API to focus previous window
    def focus_prev(self):
        """Focus previous window.

        This function passes input focus to the previous window in the
        window manager's list of top-level windows that can accept input
        focus. It is meant to be invoked via a key binding's hook. Here
        is an example of intended usage:

        @verbatim
            #!/usr/bin/env python

            import minx

            wm = minx.core.wm()
            wm.hooks.add(  'F1', wm.focus_next)
            wm.hooks.add('S-F1', wm.focus_prev)
            wm.start()
        @endverbatim

        With that in your Minx start-up script, you will be able to
        cycle input focus with F1 and SHIFT + F1 (in addition to the
        default key bindings for focus cycling, viz., ALT + Tab and
        ALT + SHIFT + Tab).

        """
        L = self._focus_list
        old_head = L.head()
        L.backward()
        new_head = L.head()
        if new_head != old_head:
           logger.info('switching focus from {} to {}'.
                       format(old_head.id, new_head.id))
           window.unfocus(old_head, self.config)
           window.  focus(new_head, self.config)
        #else: new_head == old_head ==> focus list empty or only one window

    # Kill a window
    def kill(self, w = None):
        """Kill window.

        @param w The @ref minxlib::window "minxlib.window" to be killed.

        This function kills the X client application that created the
        window w and all of its other windows and X resources. If w is
        not supplied by the caller, this function will kill the
        currently focused window.

        """
        if w == None: # kill the currently focused window
           w = self._focus_list.head()
        if w != None: # there is a focused window to kill
           w.kill()

    # Kill a window using brute force
    def nuke(self, w = None):
        """Kill window using brute force.

        @param w The @ref minxlib::window "minxlib.window" to be nuked.

        This function kills the X client application that created the
        window w and all of its other windows and X resources. If w is
        not supplied by the caller, this function will kill the
        currently focused window.

        @note Whereas the kill() function attempts a graceful shutdown,
        this function resorts to brute force. It is meant to be used on
        windows that advertise support for the WM_DELETE_WINDOW protocol
        but don't implement it properly, thus, requiring a brute force
        kill (i.e., a nuking).

        """
        if w == None: # kill the currently focused window
           w = self._focus_list.head()
        if w != None: # there is a focused window to kill
           w.nuke()

    # Start an application
    def spawn(self, cmd):
        """Run specified command.

        @param cmd A string containing the command and command-line arguments.

        This function can be used to run arbitrary commands. Minx does
        not wait for the command to complete or communicate with it any
        further after starting it. The intent of this function is to
        facilitate launching GUI applications via window manager key
        bindings.

        If the command fails, Minx will write details to its log (if
        logging has been enabled).

        """
        logger.info('running command: {}'.format(cmd))
        try:
            subprocess.Popen(shlex.split(cmd))
        except:
            logger.warning('{} exception on command: {}'.
                           format(sys.exc_info()[0], cmd))
            logger.debug(traceback.format_exc())

    # Add newly created top-level window to focus list
    def add_to_focus_list(self, w):
        """Add a newly created top-level window to the focus list.

        @param w The @ref minxlib::window "minxlib.window" to be added.

        This function is meant to be used internally by Minx.
        Specifically, the wm constructor calls it to take over
        management of any top-level windows that might have been created
        before Minx was started. Also, the <tt>MapNotify</tt> handler in
        the xevents class uses it to add a newly mapped top-level window
        to the focus list and to focus it.

        End-users should not use this function.

        """
        L = self._focus_list
        f = L.head()
        if f != None:
           logger.debug('unfocusing {}'.format(f.id))
           window.unfocus(f, self.config)
        logger.debug('adding {} to focus list and focusing'.format(w.id))
        L.add(w)
        window.focus(w, self.config)

    # Whether or not manage the given window
    def manage(self, w):
        """Check if given window should be managed or not.

        @param  w The @ref minxlib::window "minxlib.window" to be checked.
        @return True if Minx should manage w, false if it should ignore w.

        This function triggers the manage hooks setup by end-users and
        checks all their return values. If all the manage hooks return
        True, then this function will return True. If any of the manage
        hooks returns False, this function will return False. Thus,
        Minx will only manage a top-level window if all the manage
        hooks return True.

        @note This function is meant to be used internally by Minx.
        End-user code should refrain from calling it.

        """
        # hooks.trigger() returns a list of return values of each hook
        # it calls.  The manage_hook expects a Boolean return value:
        # True to indicate that the window w should be managed, False
        # to make Minx ignore w. Thus, to determine whether w should be
        # managed, we have to examine the each of these return values
        # and confirm that they're all True.
        for r in self.hooks.trigger('manage_hook', w):
            if r == False:  # some manage hook returned False
               return False # therefore, ignore w

        # If we get here, all manage hooks passed w ==> we should
        # manage it...
        return True

    # Quit window manager
    def quit(self):
        """Quit the window manager.

        This function sets a flag that will eventually result in Minx
        exiting its event loop. It is meant to be invoked via a key
        binding or other similar action.

        """
        self._quit = True

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

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

Added core/xevents.py.

























































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
#
# xevents.py -- X event handlers
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki in the top-level directory of the Minx source
# distribution for the full list of authors who have contributed to this
# project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

#------------------------ MODULE DOC STRING ----------------------------

"""@package minx.core.xevents
Helper class for handling various X events.

"""

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

# Standard library
import logging

# Minx
import layman
import window
import minxlib

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

logger = logging.getLogger(__name__)

#------------------------- CLASS DEFINITION ----------------------------

class xevents:
    """Helper class for handling various X events.

    This class encapsulates the X event handlers so that the
    @ref minx.core.wm.wm "main window manager object" can delegate this
    low-level functionality. This class is not really meant to be used
    by end-users; it should be considered internal to Minx.

    """

    # Constructor
    def __init__(self, wm):
        """Initialize X event handlers.

        @param wm The @ref minx.core.wm.wm "main window manager object".

        This class is meant to be used by @ref minx.core.wm.wm "minx.core.wm"
        so the main window manager object can delegate all the low-level
        X event handling. Consequently, the xevents object needs a
        reference to the main window manager object so it can access and
        manipulate the window manager's internal state in response to
        various X events.

        """
        self._wm = wm
        self._init_hooks()

    # Helper function to initialize the mapping between X events and
    # their corresponding handler functions.
    #
    # NOTE: This relies on the string forms of all minxlib::event
    # subclasses being "x_something". Thus, the mapping between event
    # types and handlers uses strings as keys and functions as the
    # corresponding values.
    def _init_hooks(self):
        logger.debug('setting up X event handlers')
        h = self._wm.hooks
        h.add('x_create_notify',     self._on_create)
        h.add('x_configure_request', self._on_configure_request)
        h.add('x_map_request',       self._on_map_request)
        h.add('x_map_notify',        self._on_map)
        h.add('x_unmap_notify',      self._on_unmap)
        h.add('x_key_press',         self._on_key_press)

    # Whether or not window specified by x_create_notify event should
    # 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
    # away. Instead, we wait for them to be mapped first before putting
    # them on the focus list. This is because some applications (e.g.,
    # GNOME and XFCE terminal) create hidden top-level windows that
    # should never receive input focus.
    def _on_create(self, e):
        if self._manage (e):
           self._wm.layouts.receptive_layout(e.target).add(e.target)

    # What to do when a window wants to be configured: pass configure
    # request through as-is except for top-level windows, which have to
    # be resized according to their managing layout's policy.
    def _on_configure_request(self, e):
        logger.info ('configure request for window {}'.format(e.target.id))
        logger.debug('configure request details: ' +
                     'geom = {}x{}+{}+{}, bw = {}, mask = {:#010b}'.
                     format(e.width, e.height, e.x, e.y,
                            e.border_width, e.value_mask))
        try:
            layout = self._wm.layouts.find(e.parent)
            x, y, w, h = layout.configure_request(e.target, e.x, e.y,
                                                  e.width, e.height)

        except layman.unknown_layout: # pass configure request through as-is
            logger.debug('window {} not a top-level window'.
                         format(e.target.id))
            x, y, w, h = (e.x, e.y, e.width, e.height)

        logger.debug('setting window {} geometry to {}x{}+{}+{}'.
                     format(e.target.id, w, h, x, y))
        e.target.configure(x, y, w, h, e.border_width,
                           e.above, e.stack_mode, e.value_mask)

    # What to do when a window wants to be shown on-screen: top-level
    # windows will be passed to their managing layout for possible
    # reconfiguration before being mapped; all other windows are mapped
    # as-is.
    def _on_map_request(self, e):
        logger.info('map request for window {}'.format(e.target.id))
        try:
            layout = self._wm.layouts.find(e.parent)
            layout.map_request(e.target)
        except layman.unknown_layout:
            pass
        e.target.show()

    # What to do when a top-level window is successfully shown
    # on-screen: we should add it to the window manager's focus list and
    # focus it.
    def _on_map(self, e):
        try:
            self._wm.layouts.find(e.parent)
            logger.debug('adding top-level window {} to focus list'.
                         format(e.target.id))
            self._wm.add_to_focus_list(e.target)
        except layman.unknown_layout: # not a top-level window
            pass

    # What to do when a top-level window is taken off-screen: remove it
    # from the window manager's focus list and focus the next window on
    # the focus list.
    def _on_unmap(self, e):
        try:
            self._wm.layouts.find(e.parent)
            L = self._wm._focus_list
            logger.info('removing {} from focus list'.format(e.target.id))
            L.remove(e.target)
            f = L.head()
            if f != None:
               logger.info('focusing {}'.format(f.id))
               window.focus(f, self._wm.config)
        except layman.unknown_layout: # not a top-level window
            pass

    # What to do when a key is pressed.
    def _on_key_press(self, e):
        logger.info('keypress: {}, keycode: {}, mask: {:#06x}'.
                    format(e.key, e.keycode, e.mask))
        self._wm.hooks.trigger(e.key)

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

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

Added dox/CMakeLists.txt.































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
#
# Build spec for Minx's API docs
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki for the full list of authors who have
# contributed to this project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

# Min cmake version
cmake_minimum_required(VERSION 2.8)

# Project name
project(minxdoc)

# Check if we have Xinerama and, if so, set a CMake variable that will
# tell Doxygen so that it generates the documentation for the optional
# Xinerama-dependent parts of Minx.
find_package(X11)
if(X11_Xinerama_FOUND)
    set(minxdoc_PREDEFINED MINXLIB_HAS_XINERAMA)
endif()

# Custom target for API documentation
find_package(Doxygen)
if(DOXYGEN_FOUND)
    configure_file("${CMAKE_CURRENT_SOURCE_DIR}/doxyfile.in"
                   "${CMAKE_CURRENT_BINARY_DIR}/doxyfile" @ONLY)
    add_custom_target(doc
                      ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxyfile
                      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
                      COMMENT "Generating documentation")
endif(DOXYGEN_FOUND)

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

Added dox/dox.css.











































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
/* The standard CSS for doxygen */

body, table, div, p, dl {
	font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
	font-size: 13px;
	line-height: 1.3;
}

/* @group Heading Levels */

h1 {
	font-size: 150%;
}

.title {
	font-size: 150%;
	font-weight: bold;
	margin: 10px 2px;
}

h2 {
	font-size: 120%;
}

h3 {
	font-size: 100%;
}

dt {
	font-weight: bold;
}

div.multicol {
	-moz-column-gap: 1em;
	-webkit-column-gap: 1em;
	-moz-column-count: 3;
	-webkit-column-count: 3;
}

p.startli, p.startdd, p.starttd {
	margin-top: 2px;
}

p.endli {
	margin-bottom: 0px;
}

p.enddd {
	margin-bottom: 4px;
}

p.endtd {
	margin-bottom: 2px;
}

/* @end */

caption {
	font-weight: bold;
}

span.legend {
        font-size: 70%;
        text-align: center;
}

h3.version {
        font-size: 90%;
        text-align: center;
}

div.qindex, div.navtab{
	background-color: #EBEFF6;
	border: 1px solid #A3B4D7;
	text-align: center;
}

div.qindex, div.navpath {
	width: 100%;
	line-height: 140%;
}

div.navtab {
	margin-right: 15px;
}

/* @group Link Styling */

a {
	color: #3D578C;
	font-weight: normal;
	text-decoration: none;
}

.contents a:visited {
	color: #4665A2;
}

a:hover {
	text-decoration: underline;
}

a.qindex {
	font-weight: bold;
}

a.qindexHL {
	font-weight: bold;
	background-color: #9CAFD4;
	color: #ffffff;
	border: 1px double #869DCA;
}

.contents a.qindexHL:visited {
        color: #ffffff;
}

a.el {
	font-weight: bold;
}

a.elRef {
}

a.code, a.code:visited {
	color: #4665A2; 
}

a.codeRef, a.codeRef:visited {
	color: #4665A2; 
}

/* @end */

dl.el {
	margin-left: -1cm;
}

.fragment {
	font-family: monospace, fixed;
	font-size: 105%;
}

pre.fragment {
	border: 1px solid #C4CFE5;
	background-color: #FBFCFD;
	padding: 4px 6px;
	margin: 4px 8px 4px 2px;
	overflow: auto;
	word-wrap: break-word;
	font-size:  9pt;
	line-height: 125%;
}

div.ah {
	background-color: black;
	font-weight: bold;
	color: #ffffff;
	margin-bottom: 3px;
	margin-top: 3px;
	padding: 0.2em;
	border: solid thin #333;
	border-radius: 0.5em;
	-webkit-border-radius: .5em;
	-moz-border-radius: .5em;
	box-shadow: 2px 2px 3px #999;
	-webkit-box-shadow: 2px 2px 3px #999;
	-moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
	background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));
	background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);
}

div.groupHeader {
	margin-left: 16px;
	margin-top: 12px;
	font-weight: bold;
}

div.groupText {
	margin-left: 16px;
	font-style: italic;
}

body {
	background-color: white;
	color: black;
        margin: 0;
}

div.contents {
	margin-top: 10px;
	margin-left: 8px;
	margin-right: 8px;
}

td.indexkey {
	background-color: #EBEFF6;
	font-weight: bold;
	border: 1px solid #C4CFE5;
	margin: 2px 0px 2px 0;
	padding: 2px 10px;
        white-space: nowrap;
        vertical-align: top;
}

td.indexvalue {
	background-color: #EBEFF6;
	border: 1px solid #C4CFE5;
	padding: 2px 10px;
	margin: 2px 0px;
}

tr.memlist {
	background-color: #EEF1F7;
}

p.formulaDsp {
	text-align: center;
}

img.formulaDsp {
	
}

img.formulaInl {
	vertical-align: middle;
}

div.center {
	text-align: center;
        margin-top: 0px;
        margin-bottom: 0px;
        padding: 0px;
}

div.center img {
	border: 0px;
}

address.footer {
	text-align: right;
	padding-right: 12px;
}

img.footer {
	border: 0px;
	vertical-align: middle;
}

/* @group Code Colorization */

span.keyword {
	color: #008000
}

span.keywordtype {
	color: #604020
}

span.keywordflow {
	color: #e08000
}

span.comment {
	color: #800000
}

span.preprocessor {
	color: #806020
}

span.stringliteral {
	color: #002080
}

span.charliteral {
	color: #008080
}

span.vhdldigit { 
	color: #ff00ff 
}

span.vhdlchar { 
	color: #000000 
}

span.vhdlkeyword { 
	color: #700070 
}

span.vhdllogic { 
	color: #ff0000 
}

/* @end */

/*
.search {
	color: #003399;
	font-weight: bold;
}

form.search {
	margin-bottom: 0px;
	margin-top: 0px;
}

input.search {
	font-size: 75%;
	color: #000080;
	font-weight: normal;
	background-color: #e8eef2;
}
*/

td.tiny {
	font-size: 75%;
}

.dirtab {
	padding: 4px;
	border-collapse: collapse;
	border: 1px solid #A3B4D7;
}

th.dirtab {
	background: #EBEFF6;
	font-weight: bold;
}

hr {
	height: 0px;
	border: none;
	border-top: 1px solid #4A6AAA;
}

hr.footer {
	height: 1px;
}

/* @group Member Descriptions */

table.memberdecls {
	border-spacing: 0px;
	padding: 0px;
}

.mdescLeft, .mdescRight,
.memItemLeft, .memItemRight,
.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
	background-color: #F9FAFC;
	border: none;
	margin: 4px;
	padding: 1px 0 0 8px;
}

.mdescLeft, .mdescRight {
	padding: 0px 8px 4px 8px;
	color: #555;
}

.memItemLeft, .memItemRight, .memTemplParams {
	border-top: 1px solid #C4CFE5;
}

.memItemLeft, .memTemplItemLeft {
        white-space: nowrap;
}

.memItemRight {
	width: 100%;
}

.memTemplParams {
	color: #4665A2;
        white-space: nowrap;
}

/* @end */

/* @group Member Details */

/* Styles for detailed member documentation */

.memtemplate {
	font-size: 80%;
	color: #4665A2;
	font-weight: normal;
	margin-left: 9px;
}

.memnav {
	background-color: #EBEFF6;
	border: 1px solid #A3B4D7;
	text-align: center;
	margin: 2px;
	margin-right: 15px;
	padding: 2px;
}

.mempage {
	width: 100%;
}

.memitem {
	padding: 0;
	margin-bottom: 10px;
	margin-right: 5px;
}

.memname {
        white-space: nowrap;
        font-weight: bold;
        margin-left: 6px;
}

.memproto, dl.reflist dt {
        border-top: 1px solid #A8B8D9;
        border-left: 1px solid #A8B8D9;
        border-right: 1px solid #A8B8D9;
        padding: 6px 0px 6px 0px;
        color: #253555;
        font-weight: bold;
        text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
        /* opera specific markup */
        box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
        border-top-right-radius: 8px;
        border-top-left-radius: 8px;
        /* firefox specific markup */
        -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
        -moz-border-radius-topright: 8px;
        -moz-border-radius-topleft: 8px;
        /* webkit specific markup */
        -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
        -webkit-border-top-right-radius: 8px;
        -webkit-border-top-left-radius: 8px;
        background-image:url('nav_f.png');
        background-repeat:repeat-x;
        background-color: #E2E8F2;

}

.memdoc, dl.reflist dd {
        border-bottom: 1px solid #A8B8D9;      
        border-left: 1px solid #A8B8D9;      
        border-right: 1px solid #A8B8D9; 
        padding: 2px 5px;
        background-color: #FBFCFD;
        border-top-width: 0;
        /* opera specific markup */
        border-bottom-left-radius: 8px;
        border-bottom-right-radius: 8px;
        box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
        /* firefox specific markup */
        -moz-border-radius-bottomleft: 8px;
        -moz-border-radius-bottomright: 8px;
        -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
        background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7F8FB 95%, #EEF1F7);
        /* webkit specific markup */
        -webkit-border-bottom-left-radius: 8px;
        -webkit-border-bottom-right-radius: 8px;
        -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
        background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7F8FB), to(#EEF1F7));
}

dl.reflist dt {
        padding: 5px;
}

dl.reflist dd {
        margin: 0px 0px 10px 0px;
        padding: 5px;
}

.paramkey {
	text-align: right;
}

.paramtype {
	white-space: nowrap;
}

.paramname {
	color: #602020;
	white-space: nowrap;
}
.paramname em {
	font-style: normal;
}

.params, .retval, .exception, .tparams {
        border-spacing: 6px 2px;
}       

.params .paramname, .retval .paramname {
        font-weight: bold;
        vertical-align: top;
}
        
.params .paramtype {
        font-style: italic;
        vertical-align: top;
}       
        
.params .paramdir {
        font-family: "courier new",courier,monospace;
        vertical-align: top;
}




/* @end */

/* @group Directory (tree) */

/* for the tree view */

.ftvtree {
	font-family: sans-serif;
	margin: 0px;
}

/* these are for tree view when used as main index */

.directory {
	font-size: 9pt;
	font-weight: bold;
	margin: 5px;
}

.directory h3 {
	margin: 0px;
	margin-top: 1em;
	font-size: 11pt;
}

/*
The following two styles can be used to replace the root node title
with an image of your choice.  Simply uncomment the next two styles,
specify the name of your image and be sure to set 'height' to the
proper pixel height of your image.
*/

/*
.directory h3.swap {
	height: 61px;
	background-repeat: no-repeat;
	background-image: url("yourimage.gif");
}
.directory h3.swap span {
	display: none;
}
*/

.directory > h3 {
	margin-top: 0;
}

.directory p {
	margin: 0px;
	white-space: nowrap;
}

.directory div {
	display: none;
	margin: 0px;
}

.directory img {
	vertical-align: -30%;
}

/* these are for tree view when not used as main index */

.directory-alt {
	font-size: 100%;
	font-weight: bold;
}

.directory-alt h3 {
	margin: 0px;
	margin-top: 1em;
	font-size: 11pt;
}

.directory-alt > h3 {
	margin-top: 0;
}

.directory-alt p {
	margin: 0px;
	white-space: nowrap;
}

.directory-alt div {
	display: none;
	margin: 0px;
}

.directory-alt img {
	vertical-align: -30%;
}

/* @end */

div.dynheader {
        margin-top: 8px;
}

address {
	font-style: normal;
	color: #2A3D61;
}

table.doxtable {
	border-collapse:collapse;
}

table.doxtable td, table.doxtable th {
	border: 1px solid #2D4068;
	padding: 3px 7px 2px;
}

table.doxtable th {
	background-color: #374F7F;
	color: #FFFFFF;
	font-size: 110%;
	padding-bottom: 4px;
	padding-top: 5px;
	text-align:left;
}

table.fieldtable {
        width: 100%;
        margin-bottom: 10px;
        border: 1px solid #A8B8D9;
        border-spacing: 0px;
        -moz-border-radius: 4px;
        -webkit-border-radius: 4px;
        border-radius: 4px;
        -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
        -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
        box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
}

.fieldtable td, .fieldtable th {
        padding: 3px 7px 2px;
}

.fieldtable td.fieldtype, .fieldtable td.fieldname {
        white-space: nowrap;
        border-right: 1px solid #A8B8D9;
        border-bottom: 1px solid #A8B8D9;
        vertical-align: top;
}

.fieldtable td.fielddoc {
        border-bottom: 1px solid #A8B8D9;
        width: 100%;
}

.fieldtable tr:last-child td {
        border-bottom: none;
}

.fieldtable th {
        background-image:url('nav_f.png');
        background-repeat:repeat-x;
        background-color: #E2E8F2;
        font-size: 90%;
        color: #253555;
        padding-bottom: 4px;
        padding-top: 5px;
        text-align:left;
        -moz-border-radius-topleft: 4px;
        -moz-border-radius-topright: 4px;
        -webkit-border-top-left-radius: 4px;
        -webkit-border-top-right-radius: 4px;
        border-top-left-radius: 4px;
        border-top-right-radius: 4px;
        border-bottom: 1px solid #A8B8D9;
}


.tabsearch {
	top: 0px;
	left: 10px;
	height: 36px;
	background-image: url('tab_b.png');
	z-index: 101;
	overflow: hidden;
	font-size: 13px;
}

.navpath ul
{
	font-size: 11px;
	background-image:url('tab_b.png');
	background-repeat:repeat-x;
	height:30px;
	line-height:30px;
	color:#8AA0CC;
	border:solid 1px #C2CDE4;
	overflow:hidden;
	margin:0px;
	padding:0px;
}

.navpath li
{
	list-style-type:none;
	float:left;
	padding-left:10px;
	padding-right:15px;
	background-image:url('bc_s.png');
	background-repeat:no-repeat;
	background-position:right;
	color:#364D7C;
}

.navpath li.navelem a
{
	height:32px;
	display:block;
	text-decoration: none;
	outline: none;
}

.navpath li.navelem a:hover
{
	color:#6884BD;
}

.navpath li.footer
{
        list-style-type:none;
        float:right;
        padding-left:10px;
        padding-right:15px;
        background-image:none;
        background-repeat:no-repeat;
        background-position:right;
        color:#364D7C;
        font-size: 8pt;
}


div.summary
{
	float: right;
	font-size: 8pt;
	padding-right: 5px;
	width: 50%;
	text-align: right;
}       

div.summary a
{
	white-space: nowrap;
}

div.ingroups
{
	margin-left: 5px;
	font-size: 8pt;
	padding-left: 5px;
	width: 50%;
	text-align: left;
}

div.ingroups a
{
	white-space: nowrap;
}

div.header
{
        background-image:url('nav_h.png');
        background-repeat:repeat-x;
	background-color: #F9FAFC;
	margin:  0px;
	border-bottom: 1px solid #C4CFE5;
}

div.headertitle
{
	padding: 5px 5px 5px 7px;
}

dl
{
        padding: 0 0 0 10px;
}

dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug
{
        border-left:4px solid;
        padding: 0 0 0 6px;
}

dl.note
{
        border-color: #D0C000;
}

dl.warning, dl.attention
{
        border-color: #FF0000;
}

dl.pre, dl.post, dl.invariant
{
        border-color: #00D000;
}

dl.deprecated
{
        border-color: #505050;
}

dl.todo
{
        border-color: #00C0E0;
}

dl.test
{
        border-color: #3030E0;
}

dl.bug
{
        border-color: #C08050;
}

#projectlogo
{
	text-align: center;
	vertical-align: bottom;
	border-collapse: separate;
}
 
#projectlogo img
{ 
	border: 0px none;
}
 
#projectname
{
	font: 300% Tahoma, Arial,sans-serif;
	margin: 0px;
	padding: 2px 0px;
}
    
#projectbrief
{
	font: 120% Tahoma, Arial,sans-serif;
	margin: 0px;
	padding: 0px;
}

#projectnumber
{
	font: 50% Tahoma, Arial,sans-serif;
	margin: 0px;
	padding: 0px;
}

#titlearea
{
	padding: 0px;
	margin: 0px;
	width: 100%;
	border-bottom: 1px solid #5373B4;
}

.image
{
        text-align: center;
}

.dotgraph
{
        text-align: center;
}

.mscgraph
{
        text-align: center;
}

.caption
{
	font-weight: bold;
}

div.zoom
{
	border: 1px solid #90A5CE;
}

dl.citelist {
        margin-bottom:50px;
}

dl.citelist dt {
        color:#334975;
        float:left;
        font-weight:bold;
        margin-right:10px;
        padding:5px;
}

dl.citelist dd {
        margin:2px 0;
        padding:5px 0;
}

@media print
{
  #top { display: none; }
  #side-nav { display: none; }
  #nav-path { display: none; }
  body { overflow:visible; }
  h1, h2, h3, h4, h5, h6 { page-break-after: avoid; }
  .summary { display: none; }
  .memitem { page-break-inside: avoid; }
  #doc-content
  {
    margin-left:0 !important;
    height:auto !important;
    width:auto !important;
    overflow:inherit;
    display:inline;
  }
  pre.fragment
  {
    overflow: visible;
    text-wrap: unrestricted;
    white-space: -moz-pre-wrap; /* Moz */
    white-space: -pre-wrap; /* Opera 4-6 */
    white-space: -o-pre-wrap; /* Opera 7 */
    white-space: pre-wrap; /* CSS3  */
    word-wrap: break-word; /* IE 5.5+ */
  }
}

Added dox/doxyfile.in.





























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
# Doxyfile 1.8.0

# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project
#
# All text after a hash (#) is considered a comment and will be ignored
# The format is:
#       TAG = value [value, ...]
# For lists items can also be appended using:
#       TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (" ")

#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------

# This tag specifies the encoding used for all characters in the config file 
# that follow. The default is UTF-8 which is also the encoding used for all 
# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
# iconv built into libc) for the transcoding. See 
# http://www.gnu.org/software/libiconv for the list of possible encodings.

DOXYFILE_ENCODING      = UTF-8

# The PROJECT_NAME tag is a single word (or sequence of words) that should 
# identify the project. Note that if you do not use Doxywizard you need 
# to put quotes around the project name if it contains spaces.

PROJECT_NAME           = Minx

# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
# This could be handy for archiving the generated documentation or 
# if some version control system is used.

PROJECT_NUMBER         = 

# Using the PROJECT_BRIEF tag one can provide an optional one line description 
# for a project that appears at the top of each page and should give viewer 
# a quick idea about the purpose of the project. Keep the description short.

PROJECT_BRIEF          = "API Docs"

# With the PROJECT_LOGO tag one can specify an logo or icon that is 
# included in the documentation. The maximum height of the logo should not 
# exceed 55 pixels and the maximum width should not exceed 200 pixels. 
# Doxygen will copy the logo to the output directory.

PROJECT_LOGO           = 

# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
# base path where the generated documentation will be put. 
# If a relative path is entered, it will be relative to the location 
# where doxygen was started. If left blank the current directory will be used.

OUTPUT_DIRECTORY = @CMAKE_SOURCE_DIR@/api

# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
# 4096 sub-directories (in 2 levels) under the output directory of each output 
# format and will distribute the generated files over these directories. 
# Enabling this option can be useful when feeding doxygen a huge amount of 
# source files, where putting all generated files in the same directory would 
# otherwise cause performance problems for the file system.

CREATE_SUBDIRS         = NO

# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
# documentation generated by doxygen is written. Doxygen will use this 
# information to generate all constant output in the proper language. 
# The default language is English, other supported languages are: 
# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, 
# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English 
# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, 
# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, 
# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.

OUTPUT_LANGUAGE        = English

# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
# include brief member descriptions after the members that are listed in 
# the file and class documentation (similar to JavaDoc). 
# Set to NO to disable this.

BRIEF_MEMBER_DESC      = YES

# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
# the brief description of a member or function before the detailed description. 
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
# brief descriptions will be completely suppressed.

REPEAT_BRIEF           = YES

# This tag implements a quasi-intelligent brief description abbreviator 
# that is used to form the text in various listings. Each string 
# in this list, if found as the leading text of the brief description, will be 
# stripped from the text and the result after processing the whole list, is 
# used as the annotated text. Otherwise, the brief description is used as-is. 
# If left blank, the following values are used ("$name" is automatically 
# replaced with the name of the entity): "The $name class" "The $name widget" 
# "The $name file" "is" "provides" "specifies" "contains" 
# "represents" "a" "an" "the"

ABBREVIATE_BRIEF       = "The $name class" \
                         "The $name widget" \
                         "The $name file" \
                         is \
                         provides \
                         specifies \
                         contains \
                         represents \
                         a \
                         an \
                         the

# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
# Doxygen will generate a detailed section even if there is only a brief 
# description.

ALWAYS_DETAILED_SEC    = NO

# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
# inherited members of a class in the documentation of that class as if those 
# members were ordinary class members. Constructors, destructors and assignment 
# operators of the base classes will not be shown.

INLINE_INHERITED_MEMB  = NO

# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
# path before files name in the file list and in the header files. If set 
# to NO the shortest path that makes the file name unique will be used.

FULL_PATH_NAMES        = YES

# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
# can be used to strip a user-defined part of the path. Stripping is 
# only done if one of the specified strings matches the left-hand part of 
# the path. The tag can be used to show relative paths in the file list. 
# If left blank the directory from which doxygen is run is used as the 
# path to strip.

STRIP_FROM_PATH        = 

# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
# the path mentioned in the documentation of a class, which tells 
# the reader which header file to include in order to use a class. 
# If left blank only the name of the header file containing the class 
# definition is used. Otherwise one should specify the include paths that 
# are normally passed to the compiler using the -I flag.

STRIP_FROM_INC_PATH    = 

# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
# (but less readable) file names. This can be useful if your file system 
# doesn't support long names like on DOS, Mac, or CD-ROM.

SHORT_NAMES            = NO

# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
# will interpret the first line (until the first dot) of a JavaDoc-style 
# comment as the brief description. If set to NO, the JavaDoc 
# comments will behave just like regular Qt-style comments 
# (thus requiring an explicit @brief command for a brief description.)

JAVADOC_AUTOBRIEF      = NO

# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
# interpret the first line (until the first dot) of a Qt-style 
# comment as the brief description. If set to NO, the comments 
# will behave just like regular Qt-style comments (thus requiring 
# an explicit \brief command for a brief description.)

QT_AUTOBRIEF           = NO

# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
# comments) as a brief description. This used to be the default behaviour. 
# The new default is to treat a multi-line C++ comment block as a detailed 
# description. Set this tag to YES if you prefer the old behaviour instead.

MULTILINE_CPP_IS_BRIEF = NO

# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
# member inherits the documentation from any documented member that it 
# re-implements.

INHERIT_DOCS           = YES

# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
# a new page for each member. If set to NO, the documentation of a member will 
# be part of the file/class/namespace that contains it.

SEPARATE_MEMBER_PAGES  = NO

# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
# Doxygen uses this value to replace tabs by spaces in code fragments.

TAB_SIZE               = 8

# This tag can be used to specify a number of aliases that acts 
# as commands in the documentation. An alias has the form "name=value". 
# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
# put the command \sideeffect (or @sideeffect) in the documentation, which 
# will result in a user-defined paragraph with heading "Side Effects:". 
# You can put \n's in the value part of an alias to insert newlines.

ALIASES = boostpylink="<a href=\"http://www.boost.org/libs/python/doc/\">Boost.Python</a>"

# This tag can be used to specify a number of word-keyword mappings (TCL only). 
# A mapping has the form "name=value". For example adding 
# "class=itcl::class" will allow you to use the command class in the 
# itcl::class meaning.

TCL_SUBST              = 

# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
# sources only. Doxygen will then generate output that is more tailored for C. 
# For instance, some of the names that are used will be different. The list 
# of all members will be omitted, etc.

OPTIMIZE_OUTPUT_FOR_C  = NO

# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
# sources only. Doxygen will then generate output that is more tailored for 
# Java. For instance, namespaces will be presented as packages, qualified 
# scopes will look different, etc.

OPTIMIZE_OUTPUT_JAVA   = NO

# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
# sources only. Doxygen will then generate output that is more tailored for 
# Fortran.

OPTIMIZE_FOR_FORTRAN   = NO

# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
# sources. Doxygen will then generate output that is tailored for 
# VHDL.

OPTIMIZE_OUTPUT_VHDL   = NO

# Doxygen selects the parser to use depending on the extension of the files it 
# parses. With this tag you can assign which parser to use for a given extension. 
# Doxygen has a built-in mapping, but you can override or extend it using this 
# tag. The format is ext=language, where ext is a file extension, and language 
# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, 
# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make 
# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C 
# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions 
# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.

EXTENSION_MAPPING      = 

# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all 
# comments according to the Markdown format, which allows for more readable 
# documentation. See http://daringfireball.net/projects/markdown/ for details. 
# The output of markdown processing is further processed by doxygen, so you 
# can mix doxygen, HTML, and XML commands with Markdown formatting. 
# Disable only in case of backward compatibilities issues.

MARKDOWN_SUPPORT = NO

# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
# to include (a tag file for) the STL sources as input, then you should 
# set this tag to YES in order to let doxygen match functions declarations and 
# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
# func(std::string) {}). This also makes the inheritance and collaboration 
# diagrams that involve STL classes more complete and accurate.

BUILTIN_STL_SUPPORT    = NO

# If you use Microsoft's C++/CLI language, you should set this option to YES to 
# enable parsing support.

CPP_CLI_SUPPORT        = NO

# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
# Doxygen will parse them like normal C++ but will assume all classes use public 
# instead of private inheritance when no explicit protection keyword is present.

SIP_SUPPORT            = NO

# For Microsoft's IDL there are propget and propput attributes to indicate getter 
# and setter methods for a property. Setting this option to YES (the default) 
# will make doxygen replace the get and set methods by a property in the 
# documentation. This will only work if the methods are indeed getting or 
# setting a simple type. If this is not the case, or you want to show the 
# methods anyway, you should set this option to NO.

IDL_PROPERTY_SUPPORT   = YES

# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
# tag is set to YES, then doxygen will reuse the documentation of the first 
# member in the group (if any) for the other members of the group. By default 
# all members of a group must be documented explicitly.

DISTRIBUTE_GROUP_DOC   = YES

# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
# the same type (for instance a group of public functions) to be put as a 
# subgroup of that type (e.g. under the Public Functions section). Set it to 
# NO to prevent subgrouping. Alternatively, this can be done per class using 
# the \nosubgrouping command.

SUBGROUPING            = YES

# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and 
# unions are shown inside the group in which they are included (e.g. using 
# @ingroup) instead of on a separate page (for HTML and Man pages) or 
# section (for LaTeX and RTF).

INLINE_GROUPED_CLASSES = NO

# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and 
# unions with only public data fields will be shown inline in the documentation 
# of the scope in which they are defined (i.e. file, namespace, or group 
# documentation), provided this scope is documented. If set to NO (the default), 
# structs, classes, and unions are shown on a separate page (for HTML and Man 
# pages) or section (for LaTeX and RTF).

INLINE_SIMPLE_STRUCTS  = NO

# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
# is documented as struct, union, or enum with the name of the typedef. So 
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
# with name TypeT. When disabled the typedef will appear as a member of a file, 
# namespace, or class. And the struct will be named TypeS. This can typically 
# be useful for C code in case the coding convention dictates that all compound 
# types are typedef'ed and only the typedef is referenced, never the tag name.

TYPEDEF_HIDES_STRUCT   = NO

# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 
# determine which symbols to keep in memory and which to flush to disk. 
# When the cache is full, less often used symbols will be written to disk. 
# For small to medium size projects (<1000 input files) the default value is 
# probably good enough. For larger projects a too small cache size can cause 
# doxygen to be busy swapping symbols to and from disk most of the time 
# causing a significant performance penalty. 
# If the system has enough physical memory increasing the cache will improve the 
# performance by keeping more symbols in memory. Note that the value works on 
# a logarithmic scale so increasing the size by one will roughly double the 
# memory usage. The cache size is given by this formula: 
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 
# corresponding to a cache size of 2^16 = 65536 symbols.

SYMBOL_CACHE_SIZE      = 0

# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be 
# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given 
# their name and scope. Since this can be an expensive process and often the 
# same symbol appear multiple times in the code, doxygen keeps a cache of 
# pre-resolved symbols. If the cache is too small doxygen will become slower. 
# If the cache is too large, memory is wasted. The cache size is given by this 
# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, 
# corresponding to a cache size of 2^16 = 65536 symbols.

LOOKUP_CACHE_SIZE      = 0

#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------

# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
# documentation are documented, even if no documentation was available. 
# Private class members and static file members will be hidden unless 
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES

EXTRACT_ALL            = NO

# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
# will be included in the documentation.

EXTRACT_PRIVATE        = NO

# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
# scope will be included in the documentation.

EXTRACT_PACKAGE        = NO

# If the EXTRACT_STATIC tag is set to YES all static members of a file 
# will be included in the documentation.

EXTRACT_STATIC         = NO

# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
# defined locally in source files will be included in the documentation. 
# If set to NO only classes defined in header files are included.

EXTRACT_LOCAL_CLASSES  = NO

# This flag is only useful for Objective-C code. When set to YES local 
# methods, which are defined in the implementation section but not in 
# the interface are included in the documentation. 
# If set to NO (the default) only methods in the interface are included.

EXTRACT_LOCAL_METHODS  = NO

# If this flag is set to YES, the members of anonymous namespaces will be 
# extracted and appear in the documentation as a namespace called 
# 'anonymous_namespace{file}', where file will be replaced with the base 
# name of the file that contains the anonymous namespace. By default 
# anonymous namespaces are hidden.

EXTRACT_ANON_NSPACES   = NO

# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
# undocumented members of documented classes, files or namespaces. 
# If set to NO (the default) these members will be included in the 
# various overviews, but no documentation section is generated. 
# This option has no effect if EXTRACT_ALL is enabled.

HIDE_UNDOC_MEMBERS     = YES

# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
# undocumented classes that are normally visible in the class hierarchy. 
# If set to NO (the default) these classes will be included in the various 
# overviews. This option has no effect if EXTRACT_ALL is enabled.

HIDE_UNDOC_CLASSES     = YES

# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
# friend (class|struct|union) declarations. 
# If set to NO (the default) these declarations will be included in the 
# documentation.

HIDE_FRIEND_COMPOUNDS  = YES

# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
# documentation blocks found inside the body of a function. 
# If set to NO (the default) these blocks will be appended to the 
# function's detailed documentation block.

HIDE_IN_BODY_DOCS      = NO

# The INTERNAL_DOCS tag determines if documentation 
# that is typed after a \internal command is included. If the tag is set 
# to NO (the default) then the documentation will be excluded. 
# Set it to YES to include the internal documentation.

INTERNAL_DOCS          = NO

# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
# file names in lower-case letters. If set to YES upper-case letters are also 
# allowed. This is useful if you have classes or files whose names only differ 
# in case and if your file system supports case sensitive file names. Windows 
# and Mac users are advised to set this option to NO.

CASE_SENSE_NAMES       = NO

# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
# will show members with their full class and namespace scopes in the 
# documentation. If set to YES the scope will be hidden.

HIDE_SCOPE_NAMES       = NO

# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
# will put a list of the files that are included by a file in the documentation 
# of that file.

SHOW_INCLUDE_FILES     = YES

# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen 
# will list include files with double quotes in the documentation 
# rather than with sharp brackets.

FORCE_LOCAL_INCLUDES   = NO

# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
# is inserted in the documentation for inline members.

INLINE_INFO            = YES

# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
# will sort the (detailed) documentation of file and class members 
# alphabetically by member name. If set to NO the members will appear in 
# declaration order.

SORT_MEMBER_DOCS       = YES

# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
# brief documentation of file, namespace and class members alphabetically 
# by member name. If set to NO (the default) the members will appear in 
# declaration order.

SORT_BRIEF_DOCS        = NO

# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen 
# will sort the (brief and detailed) documentation of class members so that 
# constructors and destructors are listed first. If set to NO (the default) 
# the constructors will appear in the respective orders defined by 
# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. 
# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO 
# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.

SORT_MEMBERS_CTORS_1ST = NO

# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
# hierarchy of group names into alphabetical order. If set to NO (the default) 
# the group names will appear in their defined order.

SORT_GROUP_NAMES       = NO

# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
# sorted by fully-qualified names, including namespaces. If set to 
# NO (the default), the class list will be sorted only by class name, 
# not including the namespace part. 
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. 
# Note: This option applies only to the class list, not to the 
# alphabetical list.

SORT_BY_SCOPE_NAME     = NO

# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to 
# do proper type resolution of all parameters of a function it will reject a 
# match between the prototype and the implementation of a member function even 
# if there is only one candidate or it is obvious which candidate to choose 
# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen 
# will still accept a match between prototype and implementation in such cases.

STRICT_PROTO_MATCHING  = NO

# The GENERATE_TODOLIST tag can be used to enable (YES) or 
# disable (NO) the todo list. This list is created by putting \todo 
# commands in the documentation.

GENERATE_TODOLIST      = YES

# The GENERATE_TESTLIST tag can be used to enable (YES) or 
# disable (NO) the test list. This list is created by putting \test 
# commands in the documentation.

GENERATE_TESTLIST      = YES

# The GENERATE_BUGLIST tag can be used to enable (YES) or 
# disable (NO) the bug list. This list is created by putting \bug 
# commands in the documentation.

GENERATE_BUGLIST       = YES

# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
# disable (NO) the deprecated list. This list is created by putting 
# \deprecated commands in the documentation.

GENERATE_DEPRECATEDLIST= YES

# The ENABLED_SECTIONS tag can be used to enable conditional 
# documentation sections, marked by \if sectionname ... \endif.

ENABLED_SECTIONS       = 

# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
# the initial value of a variable or macro consists of for it to appear in 
# the documentation. If the initializer consists of more lines than specified 
# here it will be hidden. Use a value of 0 to hide initializers completely. 
# The appearance of the initializer of individual variables and macros in the 
# documentation can be controlled using \showinitializer or \hideinitializer 
# command in the documentation regardless of this setting.

MAX_INITIALIZER_LINES  = 30

# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
# at the bottom of the documentation of classes and structs. If set to YES the 
# list will mention the files that were used to generate the documentation.

SHOW_USED_FILES = NO

# If the sources in your project are distributed over multiple directories 
# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
# in the documentation. The default is NO.

SHOW_DIRECTORIES       = NO

# Set the SHOW_FILES tag to NO to disable the generation of the Files page. 
# This will remove the Files entry from the Quick Index and from the 
# Folder Tree View (if specified). The default is YES.

SHOW_FILES = NO

# Set the SHOW_NAMESPACES tag to NO to disable the generation of the 
# Namespaces page.  This will remove the Namespaces entry from the Quick Index 
# and from the Folder Tree View (if specified). The default is YES.

SHOW_NAMESPACES = NO

# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
# doxygen should invoke to get the current version for each file (typically from 
# the version control system). Doxygen will invoke the program by executing (via 
# popen()) the command <command> <input-file>, where <command> is the value of 
# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
# provided by doxygen. Whatever the program writes to standard output 
# is used as the file version. See the manual for examples.

FILE_VERSION_FILTER    = 

# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed 
# by doxygen. The layout file controls the global structure of the generated 
# output files in an output format independent way. The create the layout file 
# that represents doxygen's defaults, run doxygen with the -l option. 
# You can optionally specify a file name after the option, if omitted 
# DoxygenLayout.xml will be used as the name of the layout file.

#LAYOUT_FILE = @CMAKE_CURRENT_SOURCE_DIR@/layout.xml
LAYOUT_FILE = 

# The CITE_BIB_FILES tag can be used to specify one or more bib files 
# containing the references data. This must be a list of .bib files. The 
# .bib extension is automatically appended if omitted. Using this command 
# requires the bibtex tool to be installed. See also 
# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style 
# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this 
# feature you need bibtex and perl available in the search path.

CITE_BIB_FILES         = 

#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------

# The QUIET tag can be used to turn on/off the messages that are generated 
# by doxygen. Possible values are YES and NO. If left blank NO is used.

QUIET                  = YES

# The WARNINGS tag can be used to turn on/off the warning messages that are 
# generated by doxygen. Possible values are YES and NO. If left blank 
# NO is used.

WARNINGS               = NO

# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
# automatically be disabled.

WARN_IF_UNDOCUMENTED   = NO

# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
# potential errors in the documentation, such as not documenting some 
# parameters in a documented function, or documenting parameters that 
# don't exist or using markup commands wrongly.

WARN_IF_DOC_ERROR      = YES

# The WARN_NO_PARAMDOC option can be enabled to get warnings for 
# functions that are documented, but have no documentation for their parameters 
# or return value. If set to NO (the default) doxygen will only warn about 
# wrong or incomplete parameter documentation, but not about the absence of 
# documentation.

WARN_NO_PARAMDOC       = NO

# The WARN_FORMAT tag determines the format of the warning messages that 
# doxygen can produce. The string should contain the $file, $line, and $text 
# tags, which will be replaced by the file and line number from which the 
# warning originated and the warning text. Optionally the format may contain 
# $version, which will be replaced by the version of the file (if it could 
# be obtained via FILE_VERSION_FILTER)

WARN_FORMAT            = "$file:$line: $text"

# The WARN_LOGFILE tag can be used to specify a file to which warning 
# and error messages should be written. If left blank the output is written 
# to stderr.

WARN_LOGFILE           = 

#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------

# The INPUT tag can be used to specify the files and/or directories that contain 
# documented source files. You may enter file names like "myfile.cpp" or 
# directories like "/usr/src/myproject". Separate the files or directories 
# with spaces.

INPUT = @CMAKE_SOURCE_DIR@/minxlib  \
        @CMAKE_SOURCE_DIR@/core     \
        @CMAKE_SOURCE_DIR@/layout   \
        @CMAKE_SOURCE_DIR@/dox

# This tag can be used to specify the character encoding of the source files 
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
# also the default input encoding. Doxygen uses libiconv (or the iconv built 
# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
# the list of possible encodings.

INPUT_ENCODING         = UTF-8

# If the value of the INPUT tag contains directories, you can use the 
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
# and *.h) to filter out the source-files in the directories. If left 
# blank the following patterns are tested: 
# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh 
# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py 
# *.f90 *.f *.for *.vhd *.vhdl

FILE_PATTERNS          = *.hh \
                         *.py

# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
# should be searched for input files as well. Possible values are YES and NO. 
# If left blank NO is used.

RECURSIVE              = NO

# The EXCLUDE tag can be used to specify files and/or directories that should be 
# excluded from the INPUT source files. This way you can easily exclude a 
# subdirectory from a directory tree whose root is specified with the INPUT tag. 
# Note that relative paths are relative to the directory from which doxygen is 
# run.

EXCLUDE                = __init__.py

# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or 
# directories that are symbolic links (a Unix file system feature) are excluded 
# from the input.

EXCLUDE_SYMLINKS       = NO

# If the value of the INPUT tag contains directories, you can use the 
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
# certain files from those directories. Note that the wildcards are matched 
# against the file with absolute path, so to exclude all test directories 
# for example use the pattern */test/*

EXCLUDE_PATTERNS       = 

# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
# (namespaces, classes, functions, etc.) that should be excluded from the 
# output. The symbol name can be a fully qualified name, a word, or if the 
# wildcard * is used, a substring. Examples: ANamespace, AClass, 
# AClass::ANamespace, ANamespace::*Test

EXCLUDE_SYMBOLS        = 

# The EXAMPLE_PATH tag can be used to specify one or more files or 
# directories that contain example code fragments that are included (see 
# the \include command).

EXAMPLE_PATH           = 

# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
# and *.h) to filter out the source-files in the directories. If left 
# blank all files are included.

EXAMPLE_PATTERNS       = *

# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
# searched for input files to be used with the \include or \dontinclude 
# commands irrespective of the value of the RECURSIVE tag. 
# Possible values are YES and NO. If left blank NO is used.

EXAMPLE_RECURSIVE      = NO

# The IMAGE_PATH tag can be used to specify one or more files or 
# directories that contain image that are included in the documentation (see 
# the \image command).

IMAGE_PATH             = 

# The INPUT_FILTER tag can be used to specify a program that doxygen should 
# invoke to filter for each input file. Doxygen will invoke the filter program 
# by executing (via popen()) the command <filter> <input-file>, where <filter> 
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
# input file. Doxygen will then use the output that the filter program writes 
# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
# ignored.

INPUT_FILTER           = 

# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
# basis.  Doxygen will compare the file name with each pattern and apply the 
# filter if there is a match.  The filters are a list of the form: 
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
# info on how filters are used. If FILTER_PATTERNS is empty or if 
# non of the patterns match the file name, INPUT_FILTER is applied.

FILTER_PATTERNS = *.py=@CMAKE_CURRENT_SOURCE_DIR@/doxypy --autobrief

# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
# INPUT_FILTER) will be used to filter the input files when producing source 
# files to browse (i.e. when SOURCE_BROWSER is set to YES).

FILTER_SOURCE_FILES    = NO

# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file 
# pattern. A pattern will override the setting for FILTER_PATTERN (if any) 
# and it is also possible to disable source filtering for a specific pattern 
# using *.ext= (so without naming a filter). This option only has effect when 
# FILTER_SOURCE_FILES is enabled.

FILTER_SOURCE_PATTERNS = 

#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------

# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
# be generated. Documented entities will be cross-referenced with these sources. 
# Note: To get rid of all source code in the generated output, make sure also 
# VERBATIM_HEADERS is set to NO.

SOURCE_BROWSER         = NO

# Setting the INLINE_SOURCES tag to YES will include the body 
# of functions and classes directly in the documentation.

INLINE_SOURCES         = NO

# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
# doxygen to hide any special comment blocks from generated source code 
# fragments. Normal C and C++ comments will always remain visible.

STRIP_CODE_COMMENTS    = YES

# If the REFERENCED_BY_RELATION tag is set to YES 
# then for each documented function all documented 
# functions referencing it will be listed.

REFERENCED_BY_RELATION = NO

# If the REFERENCES_RELATION tag is set to YES 
# then for each documented function all documented entities 
# called/used by that function will be listed.

REFERENCES_RELATION    = NO

# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will 
# link to the source code.  Otherwise they will link to the documentation.

REFERENCES_LINK_SOURCE = YES

# If the USE_HTAGS tag is set to YES then the references to source code 
# will point to the HTML generated by the htags(1) tool instead of doxygen 
# built-in source browser. The htags tool is part of GNU's global source 
# tagging system (see http://www.gnu.org/software/global/global.html). You 
# will need version 4.8.6 or higher.

USE_HTAGS              = NO

# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
# will generate a verbatim copy of the header file for each class for 
# which an include is specified. Set to NO to disable this.

VERBATIM_HEADERS = NO

#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------

# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
# of all compounds will be generated. Enable this if the project 
# contains a lot of classes, structs, unions or interfaces.

ALPHABETICAL_INDEX     = YES

# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
# in which this list will be split (can be a number in the range [1..20])

COLS_IN_ALPHA_INDEX    = 5

# In case all classes in a project start with a common prefix, all 
# classes will be put under the same header in the alphabetical index. 
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
# should be ignored while generating the index headers.

IGNORE_PREFIX          = 

#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------

# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
# generate HTML output.

GENERATE_HTML          = YES

# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
# put in front of it. If left blank `html' will be used as the default path.

HTML_OUTPUT = .

# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
# doxygen will generate files with .html extension.

HTML_FILE_EXTENSION    = .html

# The HTML_HEADER tag can be used to specify a personal HTML header for 
# each generated HTML page. If it is left blank doxygen will generate a 
# standard header. Note that when using a custom header you are responsible  
# for the proper inclusion of any scripts and style sheets that doxygen 
# needs, which is dependent on the configuration options used. 
# It is advised to generate a default header using "doxygen -w html 
# header.html footer.html stylesheet.css YourConfigFile" and then modify 
# that header. Note that the header is subject to change so you typically 
# have to redo this when upgrading to a newer version of doxygen or when 
# changing the value of configuration settings such as GENERATE_TREEVIEW!

HTML_HEADER = @CMAKE_CURRENT_SOURCE_DIR@/header.html

# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
# each generated HTML page. If it is left blank doxygen will generate a 
# standard footer.

HTML_FOOTER = @CMAKE_CURRENT_SOURCE_DIR@/footer.html

# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
# style sheet that is used by each HTML page. It can be used to 
# fine-tune the look of the HTML output. If the tag is left blank doxygen 
# will generate a default style sheet. Note that doxygen will try to copy 
# the style sheet file to the HTML output directory, so don't put your own 
# style sheet in the HTML output directory as well, or it will be erased!

HTML_STYLESHEET = @CMAKE_CURRENT_SOURCE_DIR@/dox.css

# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or 
# other source files which should be copied to the HTML output directory. Note 
# that these files will be copied to the base HTML output directory. Use the 
# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these 
# files. In the HTML_STYLESHEET file, use the file name only. Also note that 
# the files will be copied as-is; there are no commands or markers available.

HTML_EXTRA_FILES       = 

# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. 
# Doxygen will adjust the colors in the style sheet and background images 
# according to this color. Hue is specified as an angle on a colorwheel, 
# see http://en.wikipedia.org/wiki/Hue for more information. 
# For instance the value 0 represents red, 60 is yellow, 120 is green, 
# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. 
# The allowed range is 0 to 359.

HTML_COLORSTYLE_HUE    = 220

# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of 
# the colors in the HTML output. For a value of 0 the output will use 
# grayscales only. A value of 255 will produce the most vivid colors.

HTML_COLORSTYLE_SAT    = 100

# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to 
# the luminance component of the colors in the HTML output. Values below 
# 100 gradually make the output lighter, whereas values above 100 make 
# the output darker. The value divided by 100 is the actual gamma applied, 
# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, 
# and 100 does not change the gamma.

HTML_COLORSTYLE_GAMMA  = 80

# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML 
# page will contain the date and time when the page was generated. Setting 
# this to NO can help when comparing the output of multiple runs.

HTML_TIMESTAMP = NO

# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
# files or namespaces will be aligned in HTML using tables. If set to 
# NO a bullet list will be used.

HTML_ALIGN_MEMBERS     = YES

# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
# documentation will contain sections that can be hidden and shown after the 
# page has loaded. For this to work a browser that supports 
# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).

HTML_DYNAMIC_SECTIONS  = NO

# If the GENERATE_DOCSET tag is set to YES, additional index files 
# will be generated that can be used as input for Apple's Xcode 3 
# integrated development environment, introduced with OSX 10.5 (Leopard). 
# To create a documentation set, doxygen will generate a Makefile in the 
# HTML output directory. Running make will produce the docset in that 
# directory and running "make install" will install the docset in 
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
# it at startup. 
# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html 
# for more information.

GENERATE_DOCSET        = NO

# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
# feed. A documentation feed provides an umbrella under which multiple 
# documentation sets from a single provider (such as a company or product suite) 
# can be grouped.

DOCSET_FEEDNAME        = "Doxygen generated docs"

# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
# should uniquely identify the documentation set bundle. This should be a 
# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
# will append .docset to the name.

DOCSET_BUNDLE_ID       = org.doxygen.Project

# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify 
# the documentation publisher. This should be a reverse domain-name style 
# string, e.g. com.mycompany.MyDocSet.documentation.

DOCSET_PUBLISHER_ID    = org.doxygen.Publisher

# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.

DOCSET_PUBLISHER_NAME  = Publisher

# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
# will be generated that can be used as input for tools like the 
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
# of the generated HTML documentation.

GENERATE_HTMLHELP      = NO

# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
# be used to specify the file name of the resulting .chm file. You 
# can add a path in front of the file if the result should not be 
# written to the html output directory.

CHM_FILE               = 

# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
# be used to specify the location (absolute path including file name) of 
# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
# the HTML help compiler on the generated index.hhp.

HHC_LOCATION           = 

# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
# controls if a separate .chi index file is generated (YES) or that 
# it should be included in the master .chm file (NO).

GENERATE_CHI           = NO

# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING 
# is used to encode HtmlHelp index (hhk), content (hhc) and project file 
# content.

CHM_INDEX_ENCODING     = 

# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
# controls whether a binary table of contents is generated (YES) or a 
# normal table of contents (NO) in the .chm file.

BINARY_TOC             = NO

# The TOC_EXPAND flag can be set to YES to add extra items for group members 
# to the contents of the HTML help documentation and to the tree view.

TOC_EXPAND             = NO

# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and 
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated 
# that can be used as input for Qt's qhelpgenerator to generate a 
# Qt Compressed Help (.qch) of the generated HTML documentation.

GENERATE_QHP           = NO

# If the QHG_LOCATION tag is specified, the QCH_FILE tag can 
# be used to specify the file name of the resulting .qch file. 
# The path specified is relative to the HTML output folder.

QCH_FILE               = 

# The QHP_NAMESPACE tag specifies the namespace to use when generating 
# Qt Help Project output. For more information please see 
# http://doc.trolltech.com/qthelpproject.html#namespace

QHP_NAMESPACE          = org.doxygen.Project

# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 
# Qt Help Project output. For more information please see 
# http://doc.trolltech.com/qthelpproject.html#virtual-folders

QHP_VIRTUAL_FOLDER     = doc

# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to 
# add. For more information please see 
# http://doc.trolltech.com/qthelpproject.html#custom-filters

QHP_CUST_FILTER_NAME   = 

# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the 
# custom filter to add. For more information please see 
# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> 
# Qt Help Project / Custom Filters</a>.

QHP_CUST_FILTER_ATTRS  = 

# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this 
# project's 
# filter section matches. 
# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> 
# Qt Help Project / Filter Attributes</a>.

QHP_SECT_FILTER_ATTRS  = 

# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 
# be used to specify the location of Qt's qhelpgenerator. 
# If non-empty doxygen will try to run qhelpgenerator on the generated 
# .qhp file.

QHG_LOCATION           = 

# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files  
# will be generated, which together with the HTML files, form an Eclipse help 
# plugin. To install this plugin and make it available under the help contents 
# menu in Eclipse, the contents of the directory containing the HTML and XML 
# files needs to be copied into the plugins directory of eclipse. The name of 
# the directory within the plugins directory should be the same as 
# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before 
# the help appears.

GENERATE_ECLIPSEHELP   = NO

# A unique identifier for the eclipse help plugin. When installing the plugin 
# the directory name containing the HTML and XML files should also have 
# this name.

ECLIPSE_DOC_ID         = org.doxygen.Project

# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) 
# at top of each HTML page. The value NO (the default) enables the index and 
# the value YES disables it. Since the tabs have the same information as the 
# navigation tree you can set this option to NO if you already set 
# GENERATE_TREEVIEW to YES.

DISABLE_INDEX          = YES

# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index 
# structure should be generated to display hierarchical information. 
# If the tag value is set to YES, a side panel will be generated 
# containing a tree-like index structure (just like the one that 
# is generated for HTML Help). For this to work a browser that supports 
# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). 
# Windows users are probably better off using the HTML help feature. 
# Since the tree basically has the same information as the tab index you 
# could consider to set DISABLE_INDEX to NO when enabling this option.

GENERATE_TREEVIEW      = NO

# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values 
# (range [0,1..20]) that doxygen will group on one line in the generated HTML 
# documentation. Note that a value of 0 will completely suppress the enum 
# values from appearing in the overview section.

ENUM_VALUES_PER_LINE   = 4

# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, 
# and Class Hierarchy pages using a tree view instead of an ordered list.

USE_INLINE_TREES       = NO

# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
# used to set the initial width (in pixels) of the frame in which the tree 
# is shown.

TREEVIEW_WIDTH         = 250

# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open 
# links to external symbols imported via tag files in a separate window.

EXT_LINKS_IN_WINDOW    = NO

# Use this tag to change the font size of Latex formulas included 
# as images in the HTML documentation. The default is 10. Note that 
# when you change the font size after a successful doxygen run you need 
# to manually remove any form_*.png images from the HTML output directory 
# to force them to be regenerated.

FORMULA_FONTSIZE       = 10

# Use the FORMULA_TRANPARENT tag to determine whether or not the images 
# generated for formulas are transparent PNGs. Transparent PNGs are 
# not supported properly for IE 6.0, but are supported on all modern browsers. 
# Note that when changing this option you need to delete any form_*.png files 
# in the HTML output before the changes have effect.

FORMULA_TRANSPARENT    = YES

# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax 
# (see http://www.mathjax.org) which uses client side Javascript for the 
# rendering instead of using prerendered bitmaps. Use this if you do not 
# have LaTeX installed or if you want to formulas look prettier in the HTML 
# output. When enabled you may also need to install MathJax separately and 
# configure the path to it using the MATHJAX_RELPATH option.

USE_MATHJAX            = NO

# When MathJax is enabled you need to specify the location relative to the 
# HTML output directory using the MATHJAX_RELPATH option. The destination 
# directory should contain the MathJax.js script. For instance, if the mathjax 
# directory is located at the same level as the HTML output directory, then 
# MATHJAX_RELPATH should be ../mathjax. The default value points to 
# the MathJax Content Delivery Network so you can quickly see the result without 
# installing MathJax.  However, it is strongly recommended to install a local 
# copy of MathJax from http://www.mathjax.org before deployment.

MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest

# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension 
# names that should be enabled during MathJax rendering.

MATHJAX_EXTENSIONS     = 

# When the SEARCHENGINE tag is enabled doxygen will generate a search box 
# for the HTML output. The underlying search engine uses javascript 
# and DHTML and should work on any modern browser. Note that when using 
# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets 
# (GENERATE_DOCSET) there is already a search function so this one should 
# typically be disabled. For large projects the javascript based search engine 
# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.

SEARCHENGINE = NO

# When the SERVER_BASED_SEARCH tag is enabled the search engine will be 
# implemented using a PHP enabled web server instead of at the web client 
# using Javascript. Doxygen will generate the search PHP script and index 
# file to put on the web server. The advantage of the server 
# based approach is that it scales better to large projects and allows 
# full text search. The disadvantages are that it is more difficult to setup 
# and does not have live searching capabilities.

SERVER_BASED_SEARCH    = NO

#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------

# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
# generate Latex output.

GENERATE_LATEX         = NO

# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
# put in front of it. If left blank `latex' will be used as the default path.

LATEX_OUTPUT           = latex

# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
# invoked. If left blank `latex' will be used as the default command name. 
# Note that when enabling USE_PDFLATEX this option is only used for 
# generating bitmaps for formulas in the HTML output, but not in the 
# Makefile that is written to the output directory.

LATEX_CMD_NAME         = latex

# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
# generate index for LaTeX. If left blank `makeindex' will be used as the 
# default command name.

MAKEINDEX_CMD_NAME     = makeindex

# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
# LaTeX documents. This may be useful for small projects and may help to 
# save some trees in general.

COMPACT_LATEX          = NO

# The PAPER_TYPE tag can be used to set the paper type that is used 
# by the printer. Possible values are: a4, letter, legal and 
# executive. If left blank a4wide will be used.

PAPER_TYPE             = a4

# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
# packages that should be included in the LaTeX output.

EXTRA_PACKAGES         = 

# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
# the generated latex document. The header should contain everything until 
# the first chapter. If it is left blank doxygen will generate a 
# standard header. Notice: only use this tag if you know what you are doing!

LATEX_HEADER           = 

# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for 
# the generated latex document. The footer should contain everything after 
# the last chapter. If it is left blank doxygen will generate a 
# standard footer. Notice: only use this tag if you know what you are doing!

LATEX_FOOTER           = 

# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
# contain links (just like the HTML output) instead of page references 
# This makes the output suitable for online browsing using a pdf viewer.

PDF_HYPERLINKS         = YES

# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
# plain latex in the generated Makefile. Set this option to YES to get a 
# higher quality PDF documentation.

USE_PDFLATEX           = YES

# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
# command to the generated LaTeX files. This will instruct LaTeX to keep 
# running if errors occur, instead of asking the user for help. 
# This option is also used when generating formulas in HTML.

LATEX_BATCHMODE        = NO

# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
# include the index chapters (such as File Index, Compound Index, etc.) 
# in the output.

LATEX_HIDE_INDICES     = NO

# If LATEX_SOURCE_CODE is set to YES then doxygen will include 
# source code with syntax highlighting in the LaTeX output. 
# Note that which sources are shown also depends on other settings 
# such as SOURCE_BROWSER.

LATEX_SOURCE_CODE      = NO

# The LATEX_BIB_STYLE tag can be used to specify the style to use for the 
# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See 
# http://en.wikipedia.org/wiki/BibTeX for more info.

LATEX_BIB_STYLE        = plain

#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------

# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
# The RTF output is optimized for Word 97 and may not look very pretty with 
# other RTF readers or editors.

GENERATE_RTF           = NO

# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
# put in front of it. If left blank `rtf' will be used as the default path.

RTF_OUTPUT             = rtf

# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
# RTF documents. This may be useful for small projects and may help to 
# save some trees in general.

COMPACT_RTF            = NO

# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
# will contain hyperlink fields. The RTF file will 
# contain links (just like the HTML output) instead of page references. 
# This makes the output suitable for online browsing using WORD or other 
# programs which support those fields. 
# Note: wordpad (write) and others do not support links.

RTF_HYPERLINKS         = NO

# Load style sheet definitions from file. Syntax is similar to doxygen's 
# config file, i.e. a series of assignments. You only have to provide 
# replacements, missing definitions are set to their default value.

RTF_STYLESHEET_FILE    = 

# Set optional variables used in the generation of an rtf document. 
# Syntax is similar to doxygen's config file.

RTF_EXTENSIONS_FILE    = 

#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------

# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
# generate man pages

GENERATE_MAN           = NO

# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
# put in front of it. If left blank `man' will be used as the default path.

MAN_OUTPUT             = man

# The MAN_EXTENSION tag determines the extension that is added to 
# the generated man pages (default is the subroutine's section .3)

MAN_EXTENSION          = .3

# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
# then it will generate one additional man file for each entity 
# documented in the real man page(s). These additional files 
# only source the real man page, but without them the man command 
# would be unable to find the correct page. The default is NO.

MAN_LINKS              = NO

#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------

# If the GENERATE_XML tag is set to YES Doxygen will 
# generate an XML file that captures the structure of 
# the code including all documentation.

GENERATE_XML           = NO

# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
# put in front of it. If left blank `xml' will be used as the default path.

XML_OUTPUT             = xml

# The XML_SCHEMA tag can be used to specify an XML schema, 
# which can be used by a validating XML parser to check the 
# syntax of the XML files.

XML_SCHEMA             = 

# The XML_DTD tag can be used to specify an XML DTD, 
# which can be used by a validating XML parser to check the 
# syntax of the XML files.

XML_DTD                = 

# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
# dump the program listings (including syntax highlighting 
# and cross-referencing information) to the XML output. Note that 
# enabling this will significantly increase the size of the XML output.

XML_PROGRAMLISTING     = YES

#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------

# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
# generate an AutoGen Definitions (see autogen.sf.net) file 
# that captures the structure of the code including all 
# documentation. Note that this feature is still experimental 
# and incomplete at the moment.

GENERATE_AUTOGEN_DEF   = NO

#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------

# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
# generate a Perl module file that captures the structure of 
# the code including all documentation. Note that this 
# feature is still experimental and incomplete at the 
# moment.

GENERATE_PERLMOD       = NO

# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
# to generate PDF and DVI output from the Perl module output.

PERLMOD_LATEX          = NO

# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
# nicely formatted so it can be parsed by a human reader.  This is useful 
# if you want to understand what is going on.  On the other hand, if this 
# tag is set to NO the size of the Perl module output will be much smaller 
# and Perl will parse it just the same.

PERLMOD_PRETTY         = YES

# The names of the make variables in the generated doxyrules.make file 
# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
# This is useful so different doxyrules.make files included by the same 
# Makefile don't overwrite each other's variables.

PERLMOD_MAKEVAR_PREFIX = 

#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------

# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
# evaluate all C-preprocessor directives found in the sources and include 
# files.

ENABLE_PREPROCESSING   = YES

# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
# names in the source code. If set to NO (the default) only conditional 
# compilation will be performed. Macro expansion can be done in a controlled 
# way by setting EXPAND_ONLY_PREDEF to YES.

MACRO_EXPANSION        = NO

# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
# then the macro expansion is limited to the macros specified with the 
# PREDEFINED and EXPAND_AS_DEFINED tags.

EXPAND_ONLY_PREDEF     = NO

# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
# pointed to by INCLUDE_PATH will be searched when a #include is found.

SEARCH_INCLUDES        = YES

# The INCLUDE_PATH tag can be used to specify one or more directories that 
# contain include files that are not input files but should be processed by 
# the preprocessor.

INCLUDE_PATH           = 

# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
# patterns (like *.h and *.hpp) to filter out the header-files in the 
# directories. If left blank, the patterns specified with FILE_PATTERNS will 
# be used.

INCLUDE_FILE_PATTERNS  = 

# The PREDEFINED tag can be used to specify one or more macro names that 
# are defined before the preprocessor is started (similar to the -D option of 
# gcc). The argument of the tag is a list of macros of the form: name 
# or name=definition (no spaces). If the definition and the = are 
# omitted =1 is assumed. To prevent a macro definition from being 
# undefined via #undef or recursively expanded use the := operator 
# instead of the = operator.

PREDEFINED             = @minxdoc_PREDEFINED@

# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
# this tag can be used to specify a list of macro names that should be expanded. 
# The macro definition that is found in the sources will be used. 
# Use the PREDEFINED tag if you want to use a different macro definition that 
# overrules the definition found in the source code.

EXPAND_AS_DEFINED      = 

# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
# doxygen's preprocessor will remove all references to function-like macros 
# that are alone on a line, have an all uppercase name, and do not end with a 
# semicolon, because these will confuse the parser if not removed.

SKIP_FUNCTION_MACROS   = YES

#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------

# The TAGFILES option can be used to specify one or more tagfiles. For each 
# tag file the location of the external documentation should be added. The 
# format of a tag file without this location is as follows: 
#   TAGFILES = file1 file2 ... 
# Adding location for the tag files is done as follows: 
#   TAGFILES = file1=loc1 "file2 = loc2" ... 
# where "loc1" and "loc2" can be relative or absolute paths 
# or URLs. Note that each tag file must have a unique name (where the name does 
# NOT include the path). If a tag file is not located in the directory in which 
# doxygen is run, you must also specify the path to the tagfile here.

TAGFILES               = 

# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
# a tag file that is based on the input files it reads.

GENERATE_TAGFILE       = 

# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
# in the class index. If set to NO only the inherited external classes 
# will be listed.

ALLEXTERNALS           = NO

# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
# in the modules index. If set to NO, only the current project's groups will 
# be listed.

EXTERNAL_GROUPS        = YES

# The PERL_PATH should be the absolute path and name of the perl script 
# interpreter (i.e. the result of `which perl').

PERL_PATH              = /usr/bin/perl

#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------

# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
# or super classes. Setting the tag to NO turns the diagrams off. Note that 
# this option also works with HAVE_DOT disabled, but it is recommended to 
# install and use dot, since it yields more powerful graphs.

CLASS_DIAGRAMS         = NO

# You can define message sequence charts within doxygen comments using the \msc 
# command. Doxygen will then run the mscgen tool (see 
# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
# the mscgen tool resides. If left empty the tool is assumed to be found in the 
# default search path.

MSCGEN_PATH            = 

# If set to YES, the inheritance and collaboration graphs will hide 
# inheritance and usage relations if the target is undocumented 
# or is not a class.

HIDE_UNDOC_RELATIONS   = YES

# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
# available from the path. This tool is part of Graphviz, a graph visualization 
# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
# have no effect if this option is set to NO (the default)

HAVE_DOT               = NO

# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is 
# allowed to run in parallel. When set to 0 (the default) doxygen will 
# base this on the number of processors available in the system. You can set it 
# explicitly to a value larger than 0 to get control over the balance 
# between CPU load and processing speed.

DOT_NUM_THREADS        = 0

# By default doxygen will use the Helvetica font for all dot files that 
# doxygen generates. When you want a differently looking font you can specify 
# the font name using DOT_FONTNAME. You need to make sure dot is able to find 
# the font, which can be done by putting it in a standard location or by setting 
# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the 
# directory containing the font.

DOT_FONTNAME           = Helvetica

# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. 
# The default size is 10pt.

DOT_FONTSIZE           = 10

# By default doxygen will tell dot to use the Helvetica font. 
# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to 
# set the path where dot can find it.

DOT_FONTPATH           = 

# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
# will generate a graph for each documented class showing the direct and 
# indirect inheritance relations. Setting this tag to YES will force the 
# CLASS_DIAGRAMS tag to NO.

CLASS_GRAPH            = NO

# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
# will generate a graph for each documented class showing the direct and 
# indirect implementation dependencies (inheritance, containment, and 
# class references variables) of the class with other documented classes.

COLLABORATION_GRAPH    = NO

# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
# will generate a graph for groups, showing the direct groups dependencies

GROUP_GRAPHS           = NO

# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
# collaboration diagrams in a style similar to the OMG's Unified Modeling 
# Language.

UML_LOOK               = NO

# If the UML_LOOK tag is enabled, the fields and methods are shown inside 
# the class node. If there are many fields or methods and many nodes the 
# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS 
# threshold limits the number of items for each type to make the size more 
# managable. Set this to 0 for no limit. Note that the threshold may be 
# exceeded by 50% before the limit is enforced.

UML_LIMIT_NUM_FIELDS   = 10

# If set to YES, the inheritance and collaboration graphs will show the 
# relations between templates and their instances.

TEMPLATE_RELATIONS     = NO

# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
# tags are set to YES then doxygen will generate a graph for each documented 
# file showing the direct and indirect include dependencies of the file with 
# other documented files.

INCLUDE_GRAPH          = NO

# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
# documented header file showing the documented files that directly or 
# indirectly include this file.

INCLUDED_BY_GRAPH      = NO

# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
# doxygen will generate a call dependency graph for every global function 
# or class method. Note that enabling this option will significantly increase 
# the time of a run. So in most cases it will be better to enable call graphs 
# for selected functions only using the \callgraph command.

CALL_GRAPH             = NO

# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
# doxygen will generate a caller dependency graph for every global function 
# or class method. Note that enabling this option will significantly increase 
# the time of a run. So in most cases it will be better to enable caller 
# graphs for selected functions only using the \callergraph command.

CALLER_GRAPH           = NO

# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
# will generate a graphical hierarchy of all classes instead of a textual one.

GRAPHICAL_HIERARCHY    = NO

# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
# then doxygen will show the dependencies a directory has on other directories 
# in a graphical way. The dependency relations are determined by the #include 
# relations between the files in the directories.

DIRECTORY_GRAPH        = NO

# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
# generated by dot. Possible values are svg, png, jpg, or gif. 
# If left blank png will be used. If you choose svg you need to set 
# HTML_FILE_EXTENSION to xhtml in order to make the SVG files 
# visible in IE 9+ (other browsers do not have this requirement).

DOT_IMAGE_FORMAT       = png

# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to 
# enable generation of interactive SVG images that allow zooming and panning. 
# Note that this requires a modern browser other than Internet Explorer. 
# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you 
# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files 
# visible. Older versions of IE do not have SVG support.

INTERACTIVE_SVG        = NO

# The tag DOT_PATH can be used to specify the path where the dot tool can be 
# found. If left blank, it is assumed the dot tool can be found in the path.

DOT_PATH               = 

# The DOTFILE_DIRS tag can be used to specify one or more directories that 
# contain dot files that are included in the documentation (see the 
# \dotfile command).

DOTFILE_DIRS           = 

# The MSCFILE_DIRS tag can be used to specify one or more directories that 
# contain msc files that are included in the documentation (see the 
# \mscfile command).

MSCFILE_DIRS           = 

# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
# nodes that will be shown in the graph. If the number of nodes in a graph 
# becomes larger than this value, doxygen will truncate the graph, which is 
# visualized by representing a node as a red box. Note that doxygen if the 
# number of direct children of the root node in a graph is already larger than 
# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.

DOT_GRAPH_MAX_NODES    = 50

# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
# graphs generated by dot. A depth value of 3 means that only nodes reachable 
# from the root by following a path via at most 3 edges will be shown. Nodes 
# that lay further from the root node will be omitted. Note that setting this 
# option to 1 or 2 may greatly reduce the computation time needed for large 
# code bases. Also note that the size of a graph can be further restricted by 
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.

MAX_DOT_GRAPH_DEPTH    = 0

# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
# background. This is disabled by default, because dot on Windows does not 
# seem to support this out of the box. Warning: Depending on the platform used, 
# enabling this option may lead to badly anti-aliased labels on the edges of 
# a graph (i.e. they become hard to read).

DOT_TRANSPARENT        = NO

# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
# files in one run (i.e. multiple -o and -T options on the command line). This 
# makes dot run faster, but since only newer versions of dot (>1.8.10) 
# support this, this feature is disabled by default.

DOT_MULTI_TARGETS      = NO

# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
# generate a legend page explaining the meaning of the various boxes and 
# arrows in the dot generated graphs.

GENERATE_LEGEND        = NO

# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
# remove the intermediate dot files that are used to generate 
# the various graphs.

DOT_CLEANUP            = YES

Added dox/doxypy.











































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
#!/usr/bin/env python

########################################################################
#                                                                      #
# This file is distributed with Minx but is not written by the Minx    #
# Project Developers. This file's original authors and their contact   #
# information are provided below in the __author__ and __website__     #
# variables. The Minx Project Developers would like to thank the       #
# authors of this program for making it available under the terms of   #
# the GPL, which allows us to bundle it with the Minx sources.         #
#                                                                      #
# NOTE: Recent versions of Debian (e.g., squeeze) and Ubuntu (e.g.,    #
# 12.04), make this program available in the python-doxypy package.    #
# However, it has not yet made its way into the FreeBSD ports          #
# collection (as of version 9). To simplify Minx development across    #
# these two platforms, we simply bundle doxypy with Minx. If and when  #
# doxypy becomes part of the package repositories of both these        #
# operating systems, we should no longer need to distribute doxypy     #
# along with Minx's source code.                                       #
#                                                                      #
# NOTE 2: This notice is the only change made to this file by the Minx #
# Project. Everything else is identical to the upstream version.       #
#                                                                      #
########################################################################

__applicationName__ = "doxypy"
__blurb__ = """
doxypy is an input filter for Doxygen. It preprocesses python
files so that docstrings of classes and functions are reformatted
into Doxygen-conform documentation blocks.
"""

__doc__ = __blurb__ + \
"""
In order to make Doxygen preprocess files through doxypy, simply
add the following lines to your Doxyfile:
	FILTER_SOURCE_FILES = YES
	INPUT_FILTER = "python /path/to/doxypy.py"
"""

__version__ = "0.4.2"
__date__ = "14th October 2009"
__website__ = "http://code.foosel.org/doxypy"

__author__ = (
	"Philippe 'demod' Neumann (doxypy at demod dot org)",
	"Gina 'foosel' Haeussge (gina at foosel dot net)" 
)

__licenseName__ = "GPL v2"
__license__ = """This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

import sys
import re

from optparse import OptionParser, OptionGroup

class FSM(object):
	"""Implements a finite state machine.
	
	Transitions are given as 4-tuples, consisting of an origin state, a target
	state, a condition for the transition (given as a reference to a function
	which gets called with a given piece of input) and a pointer to a function
	to be called upon the execution of the given transition. 
	"""
	
	"""
	@var transitions holds the transitions
	@var current_state holds the current state
	@var current_input holds the current input
	@var current_transition hold the currently active transition
	"""
	
	def __init__(self, start_state=None, transitions=[]):
		self.transitions = transitions
		self.current_state = start_state
		self.current_input = None
		self.current_transition = None
		
	def setStartState(self, state):
		self.current_state = state

	def addTransition(self, from_state, to_state, condition, callback):
		self.transitions.append([from_state, to_state, condition, callback])
		
	def makeTransition(self, input):
		"""Makes a transition based on the given input.
		
		@param	input	input to parse by the FSM
		"""
		for transition in self.transitions:
			[from_state, to_state, condition, callback] = transition
			if from_state == self.current_state:
				match = condition(input)
				if match:
					self.current_state = to_state
					self.current_input = input
					self.current_transition = transition
					if options.debug:
						print >>sys.stderr, "# FSM: executing (%s -> %s) for line '%s'" % (from_state, to_state, input)
					callback(match)
					return

class Doxypy(object):
	def __init__(self):
		string_prefixes = "[uU]?[rR]?"
		
		self.start_single_comment_re = re.compile("^\s*%s(''')" % string_prefixes)
		self.end_single_comment_re = re.compile("(''')\s*$")
		
		self.start_double_comment_re = re.compile("^\s*%s(\"\"\")" % string_prefixes)
		self.end_double_comment_re = re.compile("(\"\"\")\s*$")
		
		self.single_comment_re = re.compile("^\s*%s(''').*(''')\s*$" % string_prefixes)
		self.double_comment_re = re.compile("^\s*%s(\"\"\").*(\"\"\")\s*$" % string_prefixes)
		
		self.defclass_re = re.compile("^(\s*)(def .+:|class .+:)")
		self.empty_re = re.compile("^\s*$")
		self.hashline_re = re.compile("^\s*#.*$")
		self.importline_re = re.compile("^\s*(import |from .+ import)")

		self.multiline_defclass_start_re = re.compile("^(\s*)(def|class)(\s.*)?$")
		self.multiline_defclass_end_re = re.compile(":\s*$")
		
		## Transition list format
		#  ["FROM", "TO", condition, action]
		transitions = [
			### FILEHEAD
			
			# single line comments
			["FILEHEAD", "FILEHEAD", self.single_comment_re.search, self.appendCommentLine],
			["FILEHEAD", "FILEHEAD", self.double_comment_re.search, self.appendCommentLine],
			
			# multiline comments
			["FILEHEAD", "FILEHEAD_COMMENT_SINGLE", self.start_single_comment_re.search, self.appendCommentLine],
			["FILEHEAD_COMMENT_SINGLE", "FILEHEAD", self.end_single_comment_re.search, self.appendCommentLine],
			["FILEHEAD_COMMENT_SINGLE", "FILEHEAD_COMMENT_SINGLE", self.catchall, self.appendCommentLine],
			["FILEHEAD", "FILEHEAD_COMMENT_DOUBLE", self.start_double_comment_re.search, self.appendCommentLine],
			["FILEHEAD_COMMENT_DOUBLE", "FILEHEAD", self.end_double_comment_re.search, self.appendCommentLine],
			["FILEHEAD_COMMENT_DOUBLE", "FILEHEAD_COMMENT_DOUBLE", self.catchall, self.appendCommentLine],
			
			# other lines
			["FILEHEAD", "FILEHEAD", self.empty_re.search, self.appendFileheadLine],
			["FILEHEAD", "FILEHEAD", self.hashline_re.search, self.appendFileheadLine],
			["FILEHEAD", "FILEHEAD", self.importline_re.search, self.appendFileheadLine],
			["FILEHEAD", "DEFCLASS", self.defclass_re.search, self.resetCommentSearch],
			["FILEHEAD", "DEFCLASS_MULTI", self.multiline_defclass_start_re.search, self.resetCommentSearch],			
			["FILEHEAD", "DEFCLASS_BODY", self.catchall, self.appendFileheadLine],

			### DEFCLASS
			
			# single line comments
			["DEFCLASS", "DEFCLASS_BODY", self.single_comment_re.search, self.appendCommentLine],
			["DEFCLASS", "DEFCLASS_BODY", self.double_comment_re.search, self.appendCommentLine],
			
			# multiline comments
			["DEFCLASS", "COMMENT_SINGLE", self.start_single_comment_re.search, self.appendCommentLine],
			["COMMENT_SINGLE", "DEFCLASS_BODY", self.end_single_comment_re.search, self.appendCommentLine],
			["COMMENT_SINGLE", "COMMENT_SINGLE", self.catchall, self.appendCommentLine],
			["DEFCLASS", "COMMENT_DOUBLE", self.start_double_comment_re.search, self.appendCommentLine],
			["COMMENT_DOUBLE", "DEFCLASS_BODY", self.end_double_comment_re.search, self.appendCommentLine],
			["COMMENT_DOUBLE", "COMMENT_DOUBLE", self.catchall, self.appendCommentLine],

			# other lines
			["DEFCLASS", "DEFCLASS", self.empty_re.search, self.appendDefclassLine],
			["DEFCLASS", "DEFCLASS", self.defclass_re.search, self.resetCommentSearch],
			["DEFCLASS", "DEFCLASS_MULTI", self.multiline_defclass_start_re.search, self.resetCommentSearch],
			["DEFCLASS", "DEFCLASS_BODY", self.catchall, self.stopCommentSearch],
			
			### DEFCLASS_BODY
			
			["DEFCLASS_BODY", "DEFCLASS", self.defclass_re.search, self.startCommentSearch],
			["DEFCLASS_BODY", "DEFCLASS_MULTI", self.multiline_defclass_start_re.search, self.startCommentSearch],
			["DEFCLASS_BODY", "DEFCLASS_BODY", self.catchall, self.appendNormalLine],

			### DEFCLASS_MULTI
			["DEFCLASS_MULTI", "DEFCLASS", self.multiline_defclass_end_re.search, self.appendDefclassLine],
			["DEFCLASS_MULTI", "DEFCLASS_MULTI", self.catchall, self.appendDefclassLine],
		]
		
		self.fsm = FSM("FILEHEAD", transitions)
		self.outstream = sys.stdout
		
		self.output = []
		self.comment = []
		self.filehead = []
		self.defclass = []
		self.indent = ""

	def __closeComment(self):
		"""Appends any open comment block and triggering block to the output."""
		
		if options.autobrief:
			if len(self.comment) == 1 \
			or (len(self.comment) > 2 and self.comment[1].strip() == ''):
				self.comment[0] = self.__docstringSummaryToBrief(self.comment[0])
			
		if self.comment:
			block = self.makeCommentBlock()
			self.output.extend(block)
			
		if self.defclass:
			self.output.extend(self.defclass)

	def __docstringSummaryToBrief(self, line):
		"""Adds \\brief to the docstrings summary line.
		
		A \\brief is prepended, provided no other doxygen command is at the
		start of the line.
		"""
		stripped = line.strip()
		if stripped and not stripped[0] in ('@', '\\'):
			return "\\brief " + line
		else:
			return line
	
	def __flushBuffer(self):
		"""Flushes the current outputbuffer to the outstream."""
		if self.output:
			try:
				if options.debug:
					print >>sys.stderr, "# OUTPUT: ", self.output
				print >>self.outstream, "\n".join(self.output)
				self.outstream.flush()
			except IOError:
				# Fix for FS#33. Catches "broken pipe" when doxygen closes 
				# stdout prematurely upon usage of INPUT_FILTER, INLINE_SOURCES 
				# and FILTER_SOURCE_FILES.
				pass
		self.output = []

	def catchall(self, input):
		"""The catchall-condition, always returns true."""
		return True
	
	def resetCommentSearch(self, match):
		"""Restarts a new comment search for a different triggering line.
		
		Closes the current commentblock and starts a new comment search.
		"""
		if options.debug:
			print >>sys.stderr, "# CALLBACK: resetCommentSearch" 
		self.__closeComment()
		self.startCommentSearch(match)
	
	def startCommentSearch(self, match):
		"""Starts a new comment search.
		
		Saves the triggering line, resets the current comment and saves
		the current indentation.
		"""
		if options.debug:
			print >>sys.stderr, "# CALLBACK: startCommentSearch"
		self.defclass = [self.fsm.current_input]
		self.comment = []
		self.indent = match.group(1)
	
	def stopCommentSearch(self, match):
		"""Stops a comment search.
		
		Closes the current commentblock, resets	the triggering line and
		appends the current line to the output.
		"""
		if options.debug:
			print >>sys.stderr, "# CALLBACK: stopCommentSearch" 
		self.__closeComment()
		
		self.defclass = []
		self.output.append(self.fsm.current_input)
	
	def appendFileheadLine(self, match):
		"""Appends a line in the FILEHEAD state.
		
		Closes the open comment	block, resets it and appends the current line.
		""" 
		if options.debug:
			print >>sys.stderr, "# CALLBACK: appendFileheadLine" 
		self.__closeComment()
		self.comment = []
		self.output.append(self.fsm.current_input)

	def appendCommentLine(self, match):
		"""Appends a comment line.
		
		The comment delimiter is removed from multiline start and ends as
		well as singleline comments.
		"""
		if options.debug:
			print >>sys.stderr, "# CALLBACK: appendCommentLine" 
		(from_state, to_state, condition, callback) = self.fsm.current_transition
		
		# single line comment
		if (from_state == "DEFCLASS" and to_state == "DEFCLASS_BODY") \
		or (from_state == "FILEHEAD" and to_state == "FILEHEAD"):
			# remove comment delimiter from begin and end of the line
			activeCommentDelim = match.group(1)
			line = self.fsm.current_input
			self.comment.append(line[line.find(activeCommentDelim)+len(activeCommentDelim):line.rfind(activeCommentDelim)])

			if (to_state == "DEFCLASS_BODY"):
				self.__closeComment()
				self.defclass = []
		# multiline start
		elif from_state == "DEFCLASS" or from_state == "FILEHEAD":
			# remove comment delimiter from begin of the line
			activeCommentDelim = match.group(1)
			line = self.fsm.current_input
			self.comment.append(line[line.find(activeCommentDelim)+len(activeCommentDelim):])
		# multiline end
		elif to_state == "DEFCLASS_BODY" or to_state == "FILEHEAD":
			# remove comment delimiter from end of the line
			activeCommentDelim = match.group(1)
			line = self.fsm.current_input
			self.comment.append(line[0:line.rfind(activeCommentDelim)])
			if (to_state == "DEFCLASS_BODY"):
				self.__closeComment()
				self.defclass = []
		# in multiline comment
		else:
			# just append the comment line
			self.comment.append(self.fsm.current_input)
	
	def appendNormalLine(self, match):
		"""Appends a line to the output."""
		if options.debug:
			print >>sys.stderr, "# CALLBACK: appendNormalLine" 
		self.output.append(self.fsm.current_input)
		
	def appendDefclassLine(self, match):
		"""Appends a line to the triggering block."""
		if options.debug:
			print >>sys.stderr, "# CALLBACK: appendDefclassLine" 
		self.defclass.append(self.fsm.current_input)
	
	def makeCommentBlock(self):
		"""Indents the current comment block with respect to the current
		indentation level.

		@returns a list of indented comment lines
		"""
		doxyStart = "##"
		commentLines = self.comment
		
		commentLines = map(lambda x: "%s# %s" % (self.indent, x), commentLines)
		l = [self.indent + doxyStart]
		l.extend(commentLines)
			 
		return l
	
	def parse(self, input):
		"""Parses a python file given as input string and returns the doxygen-
		compatible representation.
		
		@param	input	the python code to parse
		@returns the modified python code
		""" 
		lines = input.split("\n")
		
		for line in lines:
			self.fsm.makeTransition(line)
			
		if self.fsm.current_state == "DEFCLASS":
			self.__closeComment()
		
		return "\n".join(self.output)
	
	def parseFile(self, filename):
		"""Parses a python file given as input string and returns the doxygen-
		compatible representation.
		
		@param	input	the python code to parse
		@returns the modified python code
		""" 
		f = open(filename, 'r')
		
		for line in f:
			self.parseLine(line.rstrip('\r\n'))
		if self.fsm.current_state == "DEFCLASS":
			self.__closeComment()
			self.__flushBuffer()
		f.close()
	
	def parseLine(self, line):
		"""Parse one line of python and flush the resulting output to the 
		outstream.
		
		@param	line	the python code line to parse
		"""
		self.fsm.makeTransition(line)
		self.__flushBuffer()
	
def optParse():
	"""Parses commandline options."""
	parser = OptionParser(prog=__applicationName__, version="%prog " + __version__)
	
	parser.set_usage("%prog [options] filename")
	parser.add_option("--autobrief",
		action="store_true", dest="autobrief",
		help="use the docstring summary line as \\brief description"
	)
	parser.add_option("--debug",
		action="store_true", dest="debug",
		help="enable debug output on stderr"
	)
	
	## parse options
	global options
	(options, filename) = parser.parse_args()
	
	if not filename:
		print >>sys.stderr, "No filename given."
		sys.exit(-1)
	
	return filename[0]

def main():
	"""Starts the parser on the file given by the filename as the first 
	argument on the commandline.
	"""
	filename = optParse()
	fsm = Doxypy()
	fsm.parseFile(filename)

if __name__ == "__main__":
	main()

Added dox/footer.html.





>
>
1
2
</body>
</html>

Added dox/header.html.

















































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<link href="$relpath$tabs.css" rel="stylesheet" type="text/css"/>
<link href="$relpath$dox.css" rel="stylesheet" type="text/css" />
$treeview
$search
$mathjax
</head>
<body>
<div id="top"><!-- do not remove this div! -->

<!--BEGIN TITLEAREA-->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <!--BEGIN PROJECT_LOGO-->
  <td id="projectlogo"><img alt="Logo" src="$relpath$$projectlogo"/></td>
  <!--END PROJECT_LOGO-->
  <!--BEGIN PROJECT_NAME-->
  <td style="padding-left: 0.5em;">
   <div id="projectname">
     <a href="../wiki/home.wiki">$projectname</a>
     <!--BEGIN PROJECT_NUMBER-->
     &#160;<span id="projectnumber">$projectnumber</span>
     <!--END PROJECT_NUMBER-->
   </div>
   <!--BEGIN PROJECT_BRIEF-->
   <div id="projectbrief">
     <a href="index.html">$projectbrief</a>
   </div>
   <!--END PROJECT_BRIEF-->
  </td>
  <!--END PROJECT_NAME-->
  <!--BEGIN !PROJECT_NAME-->
   <!--BEGIN PROJECT_BRIEF-->
    <td style="padding-left: 0.5em;">
    <div id="projectbrief">$projectbrief</div>
    </td>
   <!--END PROJECT_BRIEF-->
  <!--END !PROJECT_NAME-->
  <!--BEGIN DISABLE_INDEX-->
   <!--BEGIN SEARCHENGINE-->
   <td>$searchbox</td>
   <!--END SEARCHENGINE-->
  <!--END DISABLE_INDEX-->
 </tr>
 </tbody>
</table>
</div>
<!--END TITLEAREA-->

Added dox/mainpage.hh.

























































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/**
    @file  mainpage.hh
    @brief Contents of main page of API docs.

    This file exists only to be able to put stuff on the
    Doxygen-generated docs' main page. It is not actually used by
    minxlib or any other part of Minx.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

//----------------------- API DOCS MAIN PAGE ---------------------------

/**
    @mainpage Minx API Documentation

    Minx is not really a tiling window manager. Rather it is a library
    that allows you to write your own tiling window manager. However, in
    case you don't want to write your own window manager, it provides a
    default configuration so that it can be used with minimal effort.
    Minx also tries to make it easy to change the defaults to suit your
    tastes.

    However, since it is impossible to anticipate everyone's
    preferences, Minx provides the necessary infrastructure to radically
    alter its behaviour. These pages document the various classes and
    functions that Minx implements to enable end-users to write a highly
    customized window manager.

    <hr>

    @section sec_core Minx Core

    Here are the different classes in Minx's Python core:

        @li @ref minx.core.wm.wm "wm"
        @li @ref minx.core.config.config "config"
        @li @ref grp_minx_core_hooks "hooks"
        @li @ref grp_minx_core_layman "layman"
        @li @ref grp_minx_version "version"
        @li @ref grp_minx_core_window "window"
        @li @ref minx.core.focus_list.focus_list "focus_list"
        @li @ref minx.core.xevents.xevents "xevents"

    Not all of the above classes are meant to be used directly by
    end-users. At this time, in fact, only the @ref minx.core.wm.wm "wm",
    @ref minx.core.config.config "config", and
    @ref grp_minx_core_hooks "hooks" classes are for public
    consumption. The @ref grp_minx_version "minx.version" object may
    also be used. Everything else should be considered internal to Minx.

    <hr>

    @section sec_layouts Minx Layouts

    Minx comes with the following layout classes:

        @li @ref minx.layout.base.base "base"
        @li @ref minx.layout.full.full "full"

    You can implement your own layouts by deriving from the
    @ref minx.layout.base.base "minx.layout.base" class and overriding
    some of its methods.

    <hr>

    @section sec_minxlib minxlib

    As you can tell from the above, Minx is written in Python and is
    largely concerned with the details of laying out windows,
    circulating input focus, and so on. However, in order to be able to
    actually achieve that functionality, it needs to talk to the
    underlying display server, which it does using minxlib, a custom
    Xlib wrapper written in C++.

    minxlib provides the Python parts of Minx a high-level,
    object-oriented API for talking to the X server. In general,
    end-users will rely on Minx's Python classes to effect various
    customizations and should not need to use minxlib directly.
    Nonetheless, the following pages document its public interface:

        @li @ref minxlib::display "display"
        @li @ref minxlib::window "window"
        @li @ref grp_minxlib_events "Event Classes"
        @li @ref grp_minxlib_exceptions "Exception Classes"
        @li @ref grp_minxlib_keymap "Key Bindings API"
        @li @ref minxlib::logging "logging"
        @li @ref minxlib::version "version"
*/

//----------------------------------------------------------------------

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added layout/__init__.py.











































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#
# __init__.py -- initialization for minx.layout module
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki in the top-level directory of the Minx source
# distribution for the full list of authors who have contributed to this
# project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

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

# Pull in various classes from minx.layout so that end-users see them,
# for example, as minx.layout.full instead of minx.layout.full.full, and
# so on.
from base import base
from full import full

#------------------------------- EXPORTS --------------------------------

__all__ = ["base", "full"]

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

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

Added layout/base.py.















































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
#
# base.py -- base class for Minx layouts
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki in the top-level directory of the Minx source
# distribution for the full list of authors who have contributed to this
# project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

#-------------------------- MODULE DOC STRING ---------------------------

"""@package minx.layout.base
Base class for Minx layouts.

This module implements a base class for layouts.

"""

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

# Standard library
import logging

# Minx
import minx.core.layman
from minx.core import minxlib

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

logger = logging.getLogger(__name__)

#--------------------------- EVENT HANDLERS -----------------------------

# Since layouts use X windows to manage their windows, the layout window
# itself will be visible when a layout has no windows to manage. We don't
# want that; we want layouts to be invisible. To effect that
# invisibility, we map the layout's window when a window is added to the
# layout and unmap it when it no longer has any visible windows.
#
# The following event handlers take care of the above-mentioned strategy
# for keeping layouts invisible.
#
# NOTE: Rather than rely on the event dispatching implemented in xevents,
# we add our own hooks for the relevant X events because we don't want
# layout subclasses to be able to override this mechanism nor require
# them to have to call base class methods in order to ensure correct
# operation of things such as layout invisibility.

# Need the layout manager maintained by the main window manager object so
# that we can find the layouts for different windows.
_layouts = None

# When a window is reparented, show its layout if the layout isn't
# already visible and then let the layout object know so it can readjust
# window geometries as required.
def _on_reparent(e):
    try:
        logger.debug('window {} reparented by {}'.
                     format(e.target.id, e.new_parent.id))

        layout = _layouts.find(e.new_parent)
        logger.debug('window {} being managed by layout {}'.
                     format(e.target.id, layout))

        if not layout.window.is_mapped():
           logger.debug('showing layout {}'.format(layout))
           layout.window.show()

        layout.reparented(e.target)

    except minx.core.layman.unknown_layout:
        logger.warning('no layout corresponding to window {}'.
                       format(e.new_parent))
        logger.debug('window {} not being managed (bogus reparent_notify?)'.
                     format(e.target.id))

# When a window is unmapped, also unmap its layout if the layout has no
# more visible windows.
def _on_unmap(e):
    try:
        logger.debug('window {} unmapped'.format(e.target.id))

        layout = _layouts.find(e.parent)
        logger.debug('window {} being managed by layout {}'.
                     format(e.target.id, layout))

        for w in layout.window.children():
            if w.is_mapped():
               logger.debug('layout {} has visible child {}; no need to hide'.
                            format(layout, w.id))
               return

        logger.debug('hiding layout {} because it has no visible children'.
                     format(layout))
        layout.window.hide()

    except minx.core.layman.unknown_layout:
        pass

# Whenever focus changes, inform the layouts managing the affected
# windows (in case they need to readjust window geometries to take
# un/focused border sizes into account).
def _on_focus_in(e):
    try:
        _layouts.find(e.target.parent()).focused(e.target)
    except minx.core.layman.unknown_layout:
        pass

def _on_focus_out(e):
    try:
        _layouts.find(e.target.parent()).unfocused(e.target)
    except minx.core.layman.unknown_layout:
        pass

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

class base:
    """A base class for Minx layouts.

    This class implements a base class from which all Minx layout classes
    must be derived. This class is not meant to be instantiated; instead,
    you should instantiate one of the layout subclasses provided by Minx
    (or one of the custom layouts you implement yourself).

    """

    # Constructor
    def __init__(self, m, p, r = None):
        """Layout base class constructor.

        @param m The @ref minx.core.wm.wm "main window manager object".
        @param p The layout's parent @ref minxlib::window "minxlib.window".
        @param r The rectangle within parent window assigned to this layout.

        Each layout class's constructor must call this base class
        constructor, passing it at least the parameters m and p, which we
        need because a layout is basically an X window encapsulated by a
        Python object with some additional methods tacked on. Thus, in
        order to be able to create the layout window, we need the display
        connection (which is in the @ref minx.core.wm.wm "wm" class) and
        the parent window of the layout window.

        The parameter r is optional. It specifies the rectangle within
        the parent window that the layout will occupy. It should be a
        tuple of four integers. The first two integers in this tuple
        specify the x and y coordinates respectively of the layout
        window's top-left corner; the third and fourth integers are the
        layout window's width and height respectively.

        If r is not supplied by the subclass constructor, the layout will
        occupy the entire area of the parent window.

        After creating the layout's window, this method sets some
        properties on the newly created window and then maps it on screen.

        @note As mentioned earlier, this class is not meant to be
        instantiated directly. Thus, this constructor must only be called
        by subclasses.

        """
        global _layouts
        if _layouts == None:
           _layouts = m.layouts
           m.hooks.add('x_reparent_notify', _on_reparent, m.hooks.MAX_PRIORITY)
           m.hooks.add(   'x_unmap_notify', _on_unmap,    m.hooks.MAX_PRIORITY)
           m.hooks.add('x_focus_in',  _on_focus_in )
           m.hooks.add('x_focus_out', _on_focus_out)

        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)

    # Convert layout to string
    def __str__(self):
        """Return layout's name.

        This method will convert the layout object to a human-readable
        string representation (which is useful for debugging as well as
        identifying layouts).

        """
        prop = self.window.properties()
        return prop['name']

    # Check if layout will manage window
    def will_manage(self, w):
        """Check if this layout is willing to manage specified window.

        @param w The @ref minxlib::window "minxlib.window" to be managed.

        This method returns True if the layout is willing to manage the
        window w, False otherwise.

        The intent of this function is to allow layouts to decide whether
        or not they want to accept a window. For example, if a layout is
        written to expressly work with a particular application, it can
        return True for that application's windows and False for all the
        others.

        This method may be overridden by layout subclasses. The base
        class implementation returns True. Thus, unless a subclass
        overrides this function, it will be taken as willing to manage
        all windows.

        """
        logger.debug('layout {} will manage window {}'.format(self, w.id))
        return True

    # Manage specified window
    def add(self, w):
        """Add a window to be managed by this layout.

        @param w The @ref minxlib::window "minxlib.window" to be managed.

        This method tells the layout that it should manage the given
        window, which involves, among other things, reparenting the
        client window so that this layout becomes its parent.

        """
        w.select_events(minxlib.focus_change_mask)
        w.reparent(self.window)

    # Reparent notification
    def reparented(self, w):
        """Reparent notification.

        @param w The @ref minxlib::window "minxlib.window" that was reparented.

        When the @ref minx.core.wm.wm "main window manager object"
        receives a <tt>reparent_notify</tt> message in its event loop, it
        will eventually end up calling this method on the layout object
        that has reparented the window w.

        This method is meant to be overridden by layout subclasses. The
        base class implementation does nothing.

        """
        logger.warning('unhandled reparent_notify by layout ({})'.
                       format(self))

    # Configure requests
    def configure_request(self, n, x, y, w, h):
        """Decide window geometry on configure requests for top-level windows.

        @param  n The @ref minxlib::window "minxlib.window" to be configured.
        @param  x x-coordinate of window's top-left corner.
        @param  y y-coordinate of window's top-left corner.
        @param  w Window width.
        @param  h Window height.
        @return Tuple containing new geometry.

        When the @ref minx.core.wm.wm "main window manager object"
        receives a <tt>configure_request</tt> message in its event loop,
        it will eventually end up calling this method on the layout
        object that has reparented the window n. This method is meant to
        be overridden by layout subclasses; the base class implementation
        does nothing.

        Subclasses should return a 4-tuple of integers containing the new
        window geometry to apply in accordance with their particular
        layout policies. The first two numbers in this tuple specify the
        x and y coordinates of the window's top-left corner; the third
        and fourth numbers are the window's width and height
        respectively.

        The @ref minx.core.wm.wm "wm" object's <tt>configure_request</tt>
        event handler will use the returned tuple to honour the window's
        configure request. To clarify, layouts should not directly add a
        hook for <tt>x_configure_request</tt>; instead, they should let
        the main window manager object do that and override this method
        to let the main <tt>wm</tt> object know how to configure the
        windows they are managing.

        """
        logger.warning('unhandled configure_request by layout ({})'.
                       format(self))
        return (x, y, w, h)

    # Map requests
    def map_request(self, w):
        """Resize top-level window before it gets mapped to screen.

        @param w The @ref minxlib::window "minxlib.window" to be mapped.

        When the @ref minx.core.wm.wm "main window manager object"
        receives a <tt>map_request</tt> message in its event loop, it
        will eventually end up calling this method on the layout object
        that has reparented the window w. This method is meant to be
        overridden by layout subclasses; the base class implementation
        does nothing.

        The intent of this method is to give layouts an opportunity to
        move and resize the windows they are managing just before a
        window gets mapped. Layouts should not themselves map the window
        (though no harm should come from that). Rather, they should let
        the @ref minx.core.wm.wm "main window manager object" map windows
        and, in this method, if necessary, restrict themselves to
        reconfiguring their windows to match their layout policy.

        """
        logger.warning('unhandled map_request by layout ({})'.
                       format(self))

    # Focus change events
    def focused(self, w):
        """Focus-in notification.

        @param w The focused @ref minxlib::window "minxlib.window".

        When the @ref minx.core.wm.wm "main window manager object"
        receives a <tt>focus_in</tt> message in its event loop, it will
        eventually end up calling this method on the layout object that
        has reparented the window w. This method is meant to be
        overridden by layout subclasses; the base class implementation
        does nothing.

        The intent of this method is to inform layouts about changes in
        the input focus. When a window receives the input focus, the
        window manager may change its border color and size. And when
        that happens, the layout managing the newly focused window may
        well have to adjust the geometries of one/more/all of the windows
        it is managing to take into account the new border size.

        """
        logger.warning('unhandled focus_in for window {} by layout {}'.
                       format(w.id, self))

    def unfocused(self, w):
        """Focus-out notification.

        @param w The @ref minxlib::window "minxlib.window" that lost focus.

        When the @ref minx.core.wm.wm "main window manager object"
        receives a <tt>focus_out</tt> message in its event loop, it will
        eventually end up calling this method on the layout object that
        has reparented the window w. This method is meant to be
        overridden by layout subclasses; the base class implementation
        does nothing.

        The intent of this method is to inform layouts about changes in
        the input focus. When a window loses the input focus, the window
        manager may change its border color and size. Of course, when
        that happens, the layout managing the newly unfocused window may
        well have to adjust the geometries of one/more/all of the windows
        it is managing to take into account the new border size.

        """
        logger.warning('unhandled focus_out for window {} by layout {}'.
                       format(w.id, self))

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

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

Added layout/full.py.

































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
#
# full.py -- layout that occupies the entire area of its parent window
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki in the top-level directory of the Minx source
# distribution for the full list of authors who have contributed to this
# project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

#-------------------------- MODULE DOC STRING ---------------------------

"""@package minx.layout.full
Layout that occupies the entire area of its parent window.

This module implements a layout that resizes all the windows it manages
so that they occupy the entire area of the layout's parent window.

"""

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

# Standard library
import logging

# Minx
from base import base

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

logger = logging.getLogger(__name__)

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

class full(base):
    """Layout to occupy full area of parent window.

    This layout resizes all the windows it manages so that they occupy
    the entire area of the layout's parent window. Obviously, this
    strategy means that only one application window will be visible at a
    time.

    """

    # Create layout object
    def __init__(self, m, p, r = None):
        """Create a full layout object.

        @param m The @ref minx.core.wm.wm "main window manager object."
        @param p The layout's parent @ref minxlib::window "minxlib.window".
        @param r The rectangle within parent window assigned to this layout.

        When you create a full layout object, you should supply the main
        window manager object so that the layout can access the X server
        connection, any config settings it needs, etc. Additionally, the
        layout needs to know its parent window.

        The optional parameter r specifies the rectangle within the
        parent window that the layout will occupy. If it is not supplied,
        the layout will occupy the entire area of the parent window. If
        it is given, it should be a tuple containing four integers, the
        first two of which are the x and y coordinates of the layout's
        target area's top-left corner and the remaining two are the
        rectangle's width and height.

        Since Minx layouts are X windows, this constructor will create a
        child window of the specified parent, set appropriate properties
        to mark it as a layout, set the event mask, etc.

        """
        base.__init__(self, m, p, r)

    # Reparent notification
    def reparented(self, w):
        """Reparent notification.

        @param w The @ref minxlib::window "minxlib.window" that was reparented.

        When this layout manages a window, in the resulting reparent
        notification, we ensure that the size of the managed window w
        matches the size of the layout itself.

        """
        logger.info('window {} reparented by full layout ({})'.
                    format(w.id, self.window.id))
        self._resize(w)

    # Configure request
    def configure_request(self, n, x, y, w, h):
        """Configure request handler.

        @param  n The @ref minxlib::window "minxlib.window" to be configured.
        @param  x x-coordinate of window's top-left corner.
        @param  y y-coordinate of window's top-left corner.
        @param  w Window width.
        @param  h Window height.
        @return Tuple containing new geometry.

        This layout resizes the windows it manages to always occupy the
        entire area available to the layout. Thus, in response to a
        configure request for one of its windows, it will return the
        layout's geometry (adjusted to take into account the target
        window's border width).

        """
        logger.debug('full layout {} configuring top-level window {}'.
                     format(self.window.id, n.id))

        b = n.geometry()[4] # window's border width
        d = self.window.geometry()[:4]
        logger.debug('window {} border width = {}, '.format(n.id, b) +
                     'layout geometry = {}x{}+{}+{}'.format(d[2], d[3],
                                                            d[0], d[1]))
        d[2] -= 2*b # reduce window width  to ensure borders are visible
        d[3] -= 2*b # reduce window height to ensure borders are visible
        return (0, 0, d[2], d[3])

    # Map request
    def map_request(self, w):
        """Resize top-level window before it gets mapped to screen.

        @param w The @ref minxlib::window "minxlib.window" to be mapped.

        Before the full layout maps a window, it will compare the
        window's geometry against its own. If the two don't match, it
        will resize the window to make it fill the layout's entire area.

        """
        logger.debug('full layout {} resizing window {} before mapping'.
                     format(self.window.id, w.id))
        self._resize(w)

    # Focus change events
    def focused(self, w):
        """Focus-in notification.

        @param w The focused @ref minxlib::window "minxlib.window".

        When a window receives the input focus, resize it to account for
        potentially new border size.

        """
        logger.debug('full layout {} resizing focused window {}'.
                     format(self.window.id, w.id))
        self._resize(w)

    def unfocused(self, w):
        """Focus-out notification.

        @param w The unfocused @ref minxlib::window "minxlib.window".

        When a window loses the input focus, resize it to account for
        potentially new border size.

        """
        logger.debug('full layout {} resizing unfocused window {}'.
                     format(self.window.id, w.id))
        self._resize(w)

    # Resize window to fill layout
    def _resize(self, w):
        """Resize top-level window to fill entire layout area.

        @param w The @ref minxlib::window "minxlib.window" to be mapped.

        This is a helper method that compares the window w's geometry
        against the full layout's geometry and, if the two don't match,
        resizes w to make it fill the layout's entire area (taking into
        account the border width of w).

        @note This is a private method meant to be used only by the full
        layout class itself and should not be called directly by clients.

        """
        b = w.geometry() # window geometry with border width
        g = b[:4]        # window geometry w/o  border width
        d = self.window.geometry()
        logger.debug('window geometry: {}x{}+{}+{} [{}], '.
                     format(b[2], b[3], b[0], b[1], b[4]) +
                     'full layout {} geometry: {}x{}+{}+{}'.
                     format(self.window.id, d[2], d[3], d[0], d[1]))

        d[2] -= 2*b[4] # reduce window width  to ensure borders are visible
        d[3] -= 2*b[4] # reduce window height to ensure borders are visible
        if g[2:] == d[2:4]: # window and layout have the same size
           pass
        else: # need to adjust window size to match layout
           logger.info('full layout {} resetting window {} '.
                       format(self.window.id, w.id) +
                       'geometry to {}x{}+0+0'.format(d[2], d[3]))
           w.move_resize(0, 0, d[2], d[3])

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

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

Added minxlib/CMakeLists.txt.

























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
#
# minxlib build spec
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki in the top-level directory of the Minx source
# distribution for the full list of authors who have contributed to this
# project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

# Min cmake version
cmake_minimum_required(VERSION 2.8)

# Project name
project(minxlib)

# Library checks
find_package(X11 REQUIRED)
find_package(PythonLibs REQUIRED)
find_package(Boost COMPONENTS python REQUIRED)

# Compiler flags
add_definitions(-Wall -Wextra)
include_directories(${X11_INCLUDE_DIR}
                    ${Boost_INCLUDE_DIRS}
                    ${PYTHON_INCLUDE_DIRS})

# Check if we have Xinerama
if(X11_Xinerama_FOUND)
    set(X11_LIBRARIES ${X11_LIBRARIES} ${X11_Xinerama_LIB})
    add_definitions(-DMINXLIB_HAS_XINERAMA)
    set(minxlib_DOXYGEN_DEFINES MINXLIB_HAS_XINERAMA)
endif()

# Libraries we need to link against
set(minxlib_LIBS ${minxlib_LIBS}
    ${X11_LIBRARIES} ${Boost_LIBRARIES} ${PYTHON_LIBRARIES})

# Sources
set(minxlib_SOURCES python.cc type_info.cc util.cc logging.cc keymap.cc
                    exception.cc event.cc display.cc
                    window.cc root_window.cc)

# Add version.cc to source list if we're on the release branch (version
# numbering API does not exist on development branches).
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/version.cc")
    set(minxlib_SOURCES ${minxlib_SOURCES} version.cc)
    add_definitions(-DMINXLIB_HAS_VERSION_API)
endif()

# Final output from sources
add_library(minxlib SHARED ${minxlib_SOURCES})
target_link_libraries(minxlib ${minxlib_LIBS})

# Since minxlib is meant to be a Python module usable by the Minx core,
# we have to adjust some of its output parameters. Firstly, we have to
# send it to the minx.core directory. And, we have to elide the lib
# prefix from the name of the .so file to allow Python modules to import
# it as "minxlib" rather than "libminxlib".
set_target_properties(minxlib PROPERTIES
                      LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/core)
set_target_properties(minxlib PROPERTIES PREFIX "") # don't want "lib" prefix

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

Added minxlib/display.cc.





















































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
/*
    @file  display.cc
    @brief Implementation of API defined in display.hh.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

//----------------------------- HEADERS --------------------------------

// minxlib
#include "display.hh"
#include "root_window.hh"
#include "window.hh"
#include "event.hh"
#include "logging.hh"
#include "python.hh"

// Xlib
#ifdef MINXLIB_HAS_XINERAMA
#include <X11/extensions/Xinerama.h>
#endif

// Standard C++
#include <set>

//------------------ INITIALIZATION AND CLEAN-UP -----------------------

namespace minxlib {

// Interface object for taking advantage of Python's standard logging
// module's facilities.
static logging logger ;

// For keeping track of which minxlib display object corresponds to
// which Xlib Display object (because Xlib error handlers don't pass
// back any client data).
std::map<Display*, display*> display::m_display_map ;

// Constructor: connect to X server and setup error handlers
display::display(const std::string& name, bool sync)
    : m_display(XOpenDisplay(const_cast<char*>(name.c_str()))),
      m_fatal(true) // wait to check above connection before declaring okay
{
    if (!m_display) {
        std::string server(XDisplayName(const_cast<char*>(name.c_str()))) ;
        logger.critical() << "unable to connect to X server " << server ;
        connection_error::raise(server) ;
    }

    m_fatal = false ;
    m_display_map[m_display] = this ;
    logger.debug() << "registered display object "
                   << reinterpret_cast<unsigned long>(m_display) << " -> "
                   << reinterpret_cast<unsigned long>(this) ;

    if (sync) {
        logger.info() << "synchronizing Xlib";
        XSynchronize(m_display, True) ;
    }
    XSetErrorHandler(report_protocol_errors) ;
    XSetIOErrorHandler( report_fatal_errors) ;
}

// Destructor: close connection to X server
display::~display()
{
    if (!m_fatal) {
        logger.info() << "closing connection to X server" ;
        XCloseDisplay(m_display) ;
    }

    logger.debug() << "erasing display object ["
                   << reinterpret_cast<unsigned long>(m_display)
                   << ", "
                   << reinterpret_cast<unsigned long>(this)
                   << "] from internal registry" ;
    m_display_map.erase(m_display) ;
}

//------------------------- ERROR HANDLING -----------------------------

// DEVNOTE: We should not throw a protocol_error exception from this
// callback function. In fact, we should not throw any C++ exceptions
// from this callback because it is called by Xlib, a C library that
// likely cannot and does not play well with exceptions, stack unwinding
// etc. See, for example,
// http://stackoverflow.com/questions/10318363/is-it-safe-for-xs-error-handler-to-throw-exceptions.
//
// In fact, throwing an exception in this callback results in the Minx
// process going into some weird state where it starts consuming 100%
// CPU. So, really, that's a very bad idea...
//
// Since minxlib is meant to be used from Python, what we really want to
// do is inform the Python interpreter of an error condition and have it
// raise an exception. We can still leverage the Python interface
// provided by Boost.Python as long as we don't throw an exception,
// i.e., no calls to boost::python::throw_error_already_set().
//
// This is why minxlib's exception classes hide their constructors and
// require clients (such as the minxlib::display class) call a raise
// method to deliver exceptions to the Python core of Minx. That way,
// each exception class can implement an appropriate way to report
// errors to the Python side of Minx (whether that is using the Python C
// API or actually throwing a C++ exception).
int display::report_protocol_errors(Display*, XErrorEvent* e)
{
    protocol_error::raise(e) ;
    return 0 ;
}

// See comment preceding previous function, viz.,
// display::report_protocol_errors(). The same applies to this one.
int display::report_fatal_errors(Display* d)
{
    m_display_map[d]->m_fatal = true ;
    fatal_error::raise() ;
    return -1 ;
}

//---------------------------- Xlib API --------------------------------

window
display::
create_window(const window& parent, int x, int y, int width, int height)
{
    throw_fatal() ;

    Window w = XCreateSimpleWindow(m_display, parent,
                                   x, y, width, height, 0, 0, 0) ;
    return window(m_display, w) ;
}

std::vector<root_window> display::get_root_windows()
{
    throw_fatal() ;

    std::vector<root_window> root_windows ;

    int n = 0 ;
#ifdef MINXLIB_HAS_XINERAMA
    XineramaScreenInfo* screens = XineramaQueryScreens(m_display, &n) ;
    if (n > 0)
    {
        logger.info() << "Xinerama enabled; " << n << " screens" ;
        root_windows.reserve(n) ;
        for (int i = 0; i < n; ++i)
            root_windows.push_back(root_window(m_display, i, screens[i])) ;
        XFree(screens) ;
    }
    else
#endif
    {
        n = ScreenCount(m_display) ;
        logger.info() << "no Xinerama; " << n << " independent screens" ;
        root_windows.reserve(n) ;
        for (int i = 0; i < n; ++i)
            root_windows.push_back(root_window(m_display, i)) ;
    }
    return root_windows ;
}

std::vector<window> display::get_top_level_windows()
{
    throw_fatal() ;

    std::vector<window> windows ;
    int num_screens = ScreenCount(m_display) ;
    for (int screen = 0; screen < num_screens; ++screen)
    {
        logger.debug() << "getting top-level windows on screen " << screen ;
        Window  root, parent ;
        Window* children = 0 ;
        unsigned int num_children ;
        Status s = XQueryTree(m_display, RootWindow(m_display, screen),
                              &root, &parent, &children, &num_children) ;
        if (!s) {
            logger.warning() << "unable to query screen " << screen ;
            continue ;
        }
        if (children) {
            for (unsigned int i = 0; i < num_children; ++i) {
                logger.debug() << "screen "   << screen
                               << ", window " << i << " = " << children[i] ;
                windows.push_back(window(m_display, children[i])) ;
            }
            XFree(children) ;
        }
    }
    logger.info() << "total number of top-level windows = " << windows.size() ;
    return windows ;
}

window display::get_focused_window()
{
    throw_fatal() ;

    Window w ; int r ;
    XGetInputFocus(m_display, &w, &r) ;
    logger.debug() << "currently focused window = " << w ;
    return  window(m_display, (w == PointerRoot || w == None) ? 0 : w) ;
}

std::vector<std::string> display::get_keyboard_mapping()
{
    throw_fatal() ;

    int min_keycode, max_keycode ;
    XDisplayKeycodes(m_display, &min_keycode, &max_keycode) ;
    logger.debug() << "keycode range = ["
                   << min_keycode << ' ' << max_keycode << ']' ;

    const int keycode_count = max_keycode - min_keycode + 1 ;
    int keysyms_per_keycode ;
    KeySym* keysyms =
       XGetKeyboardMapping(m_display, min_keycode, keycode_count,
                           &keysyms_per_keycode) ;
    logger.debug() << "keysyms per keycode = " << keysyms_per_keycode ;

    std::set<std::string> mapping ;
    if (keysyms) {
        const int n = keycode_count * keysyms_per_keycode ;
        logger.debug() << "converting " << n << " total keysyms to strings" ;
        for (int i = 0; i < n; ++i) {
            char*p = XKeysymToString(keysyms[i]) ;
            if (p != NULL)
                mapping.insert(p) ;
        }
        XFree(keysyms) ;
    }
    else
        logger.warning() << "XGetKeyboardMapping() returned no keysyms" ;
    return std::vector<std::string>(mapping.begin(), mapping.end()) ;
}

boost::shared_ptr<event> display::get_event()
{
    throw_fatal() ;

    XEvent e ;
    XNextEvent(m_display, &e) ;
    return event::create(e, m_display) ;
}

//------------------------ PYTHON INTERFACE ----------------------------

// Export display class to Python
void display::pythonize()
{
    py::class_<display, boost::noncopyable>("display",
        py::init<std::string, bool>((py::arg("name") = std::string(""),
                                     py::arg("sync") = false ))).
        def("create_window",         &display::create_window   ).
        def("get_root_windows",      &display::get_root_windows).
        def("get_top_level_windows", &display::get_top_level_windows).
        def("get_focused_window",    &display::get_focused_window   ).
        def("get_keyboard_mapping",  &display::get_keyboard_mapping ).
        def("get_event",             &display::get_event) ;

    logger = logging::get_logger("display") ;
}

} // namespace minxlib

//----------------------------------------------------------------------

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/display.hh.



















































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
/**
    @file  display.hh
    @brief Encapsulation of connection to X server.

    This file defines a class that takes care of the details of
    connecting to the X server and provides an API for the rest of Minx
    to interface with the relevant aspects of Xlib.

    DEVNOTE: Since Minx is implemented in Python, the minxlib API is
    exported from C++ to Python using Boost.Python. We could have used
    python-xlib instead of writing a custom Xlib wrapper for Minx.
    Unfortunately, python-xlib is not very well documented, which makes
    it difficult to use. Since the C interface to Xlib is reasonably
    well documented, it is much easier to create an appropriate wrapper
    around that.

    Furthermore, a custom wrapper allows us to abstract away the
    interface to the display server, thus, making it easier to port Minx
    to, say, Wayland (if and when that becomes necessary). The Python
    parts of Minx can remain unchanged; all we would have to do is
    implement the appropriate interfaces to the new display server
    protocol in minxlib. At least, that is the hope...

    NOTE: minxlib is not meant to be a generic Xlib wrapper. It is
    designed specifically to be used by Minx. So, only those aspects of
    Xlib that Minx needs are wrapped. Moreover, the wrapping provides
    high-level API's that are only sensible for Minx.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MINXLIB_DISPLAY_DOT_HH
#define MINXLIB_DISPLAY_DOT_HH

//----------------------------- HEADERS --------------------------------

// minxlib
#include "exception.hh"

// Xlib
#include <X11/Xlib.h>

// Boost
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>

// Standard C++
#include <map>
#include <vector>
#include <string>

//------------------------- CLASS DEFINITION ---------------------------

namespace minxlib {

// Forward declarations
class event ;
class window;
class root_window ;

/**
    @brief Encapsulate the details of the connection to the X server.

    This class provides an API for the Python parts of Minx to be able
    to talk to the display server. It wraps around the relevant parts of
    Xlib and exposes its functionality to Python via @boostpylink.

    This class is meant to be used by the @ref minx.core.wm.wm
    "minx.core.wm" Python class. When end-user Minx configs start-up the
    window manager, they will instantiate minx.core.wm, which, in turn,
    will create an instance of minxlib::display to establish the
    connection to the X server.

    @note This class should only be instantiated once and really should
    not be subclassed. However, there is nothing in its implementation
    to prevent you from creating multiple minxlib::display objects or
    from subclassing it.

    @par
    Nonetheless, it is rare to ever want to have more than one instance
    of this class, to subclass it, or to want to access it from multiple
    thread contexts. If you need to do such things, you will have to
    take care of the details of tracking the multiple connections,
    accessing them from different threads, etc.

    @par
    In short, don't do these funky things; minxlib and the minx library
    are not designed for it and you really shouldn't need such
    functionality anyway (multithreaded window manager with multiple
    connections to the X server? really? why? don't you have enough
    problems in your life already?).
*/
class display: boost::noncopyable {
    // A display object's basic purpose is to wrap around the Xlib
    // Display structure.
    Display* m_display ;

    // Keep track of the instances of this class and their corresponding
    // X connections. We need this because the Xlib error handler
    // callbacks don't support passing back any client data. Thus, if we
    // encounter a fatal error, there's no way to have Xlib pass back
    // the display object corresponding to the Display pointer that we
    // can then readily mark as being in an unusable state.
    // Consequently, we have to keep track of this ourselves.
    //
    // DEVNOTE: We're maintaining this map so that in case of fatal X
    // errors, we can set a fatal flag in the display object. Then, if
    // some smartass end-user decides to ignore the fatal error
    // condition and tries to continue using the display object, we can
    // keep throwing fatal_error exceptions to foil this attempt at
    // abuse.
    //
    // DEVNOTE 2: Usually, there will only be one connection to the X
    // server. So, we may be able to get away with a single static
    // Display*. However, we cannot be guaranteed that there will only
    // ever be one instance of this class. Explicitly guaranteeing it
    // ourselves by limiting the number of display objects that can be
    // created will complicate the implementation and, potentially, the
    // interface of this class. Much easier to just use a map and be
    // done with it even though the map will pretty much always contain
    // just a single element.
    static std::map<Display*, display*> m_display_map ;

    // Flag to indicate whether or not a fatal error has occurred on
    // this connection to the X server.
    bool m_fatal ;

    // Helper function to check fatal flag and throw a fatal_error in
    // case it is set. This function should be called at the beginning
    // of each public API.
    void throw_fatal() {if (m_fatal) fatal_error::throw_it() ;}

public:
    /**
        @brief  Open a connection to the X server.
        @param  name Name of the X server.
        @param  sync Flag for synchronizing Xlib requests.
        @return A valid connection to the display server.

        Instantiating a minxlib::display object automatically sets up a
        connection to the X server. If the connection fails, a
        connection_error will be thrown.

        The name parameter will usually be an empty string, in which
        case, the contructor will connect to the X server specified by
        the DISPLAY environment variable. If specified, it should be
        something like "host:0.0". Look up X server and Xlib
        documentation to get the low-down on this.

        The sync flag indicates whether we want Xlib requests to be
        synchronous or not. By default, it is false, i.e., Xlib requests
        are buffered. Turning synchronization on is useful for
        debugging. Note that the choice between synchronous and buffered
        mode of operation is decided at creation time. That is, it
        cannot be toggled after a display object has been instantiated.

        In addition to establishing the connection to the display
        server, this constructor will also setup Xlib error handlers.
        When the X server flags errors by invoking the handlers, they
        will be reported to Python clients via appropriate
        @ref grp_minxlib_exceptions "Python exceptions".

        In case a fatal error is reported, clients are expected to
        clean-up and then terminate the process. The display object will
        become unusable after a fatal_error exception is thrown. Any
        attempt to use it after a fatal error will result in continued
        fatal_error exceptions.
    */
    display(const std::string& name = std::string(), bool sync = false) ;

    /**
        @brief  Close the connection to the X server.
        @return Nothing.

        When a display object is destroyed, it will automatically sever
        its connection to the display server.
    */
    ~display() ;

    /**
        @brief  Export the display class to minxlib Python module.
        @return Nothing.

        This function exposes the display class's interface so that it
        can be used by the Python parts of Minx. It is meant to be
        called by the Boost.Python initialization code in python.cc.
    */
    static void pythonize() ;

    /**
        @brief  Create a window.
        @param  p The new window's parent window.
        @param  x The x-coordinate of the new window's origin.
        @param  y The y-coordinate of the new window's origin.
        @param  w The new window's width.
        @param  h The new window's height.
        @return The newly created window.

        This function creates a new window by calling
        XCreateSimpleWindow(), wraps the result in a minxlib::window
        object and returns that.

        The parameter p <b>must</b> be an existing window; x and y are
        relative to the parent's origin.

        @note Although this function can churn out arbitrary windows
        parented by arbitrary other windows, end-user code should most
        definitely not abuse it in that manner. It is meant to be used
        only to create layouts.
    */
    window create_window(const window& p, int x, int y, int w, int h) ;

    /**
        @brief  Retrieve the list of root windows.
        @return List of root windows.

        This function queries the X server for all its screens and their
        corresponding root windows. The returned list holds the root
        windows in the screen order, i.e., the first element of the list
        is the root window for the first screen, the second is the root
        window for the second screen, so on and so forth.

        @note On multi-head setups with Xinerama, there is only one
        screen, and, thus, only one root window as far as the X server is
        concerned. Nonetheless, this function will still return as many
        root windows as there are physical monitors; each of these root
        windows will have the same window ID, but their geometries will
        be different.
    */
    std::vector<root_window> get_root_windows() ;

    /**
        @brief  Retrieve top-level windows across all screens.
        @return List of top-level windows.

        This function queries the X server for all the top-level windows
        on all screens. Do not rely on the returned list being in any
        particular order.

        This function is meant to be used by
        @ref minx.core.wm.wm "minx.core.wm" just before it enters its
        event loop so that Minx can manage any extant top-level windows
        that were created before Minx was started.
    */
    std::vector<window> get_top_level_windows() ;

    /**
        @brief  Get the window with the input focus.
        @return Currently focused window.

        This function uses XGetInputFocus() to determine which X window
        currently has the input focus and returns that wrapped in a
        @ref minxlib::window "minxlib::window" object.

        If no window has the input focus, this function will return a
        window with the ID zero.
    */
    window get_focused_window() ;

    /**
        @brief  Retrieve currently supported keysyms in string form.
        @return List of strings containing current keysyms.

        The X server assigns unique integer codes to each physical key
        on the keyboard. However, since different keyboard models and
        brands can have different keycodes, applications usually deal
        with keysyms, which are the symbols on the key caps (this is an
        oversimplification, but good enough for explanatory purposes).

        This function queries the X server for its mapping between
        keycodes and keysyms, converts the keysyms to strings, and
        returns the resulting list.
    */
    std::vector<std::string> get_keyboard_mapping() ;

    /**
        @brief  Retrieve the next event from the X server.
        @return A minxlib::event object describing the X event.

        This function removes the next event from the X event queue and
        returns it to its caller via an instance of a subclass of
        minxlib::event. This function is meant to be used by
        @ref minx.core.wm.wm "minx.core.wm" in its event loop.
    */
    boost::shared_ptr<event> get_event() ;

private:
    /**
        @brief  Report protocol errors via an exception.
        @param  d The connection to the X server.
        @param  e The Xlib error structure.
        @return Nothing.

        This function serves as the callback for the Xlib error handler.
        It simply raises an exception so that Python clients are
        informed of X protocol errors.

        In some cases, it may be possible to recover from protocol
        errors. In others, you may have little choice but to clean-up
        and quit.
    */
    static int report_protocol_errors(Display* d, XErrorEvent* e) ;

    /**
        @brief  Report fatal X errors via an exception.
        @param  d The connection to the X server.
        @return Nothing.

        This function serves as the callback for the Xlib I/O error
        handler. It simply raises an exception so that Python clients
        are informed of fatal X errors. When a client receives a
        fatal_error exception, it is expected to clean-up and terminate
        its process. Making further Xlib calls via minxlib will result
        in continued fatal_error exceptions.

        DEVNOTE: Since this Xlib callback does not support passing back
        arbitrary client data, we have to resort to using the
        m_display_map defined above to be able to keep throwing
        fatal_error exceptions after an X fatal error.
    */
    static int report_fatal_errors(Display* d) ;
} ; // class display

} // namespace minxlib

//----------------------------------------------------------------------

#endif // #ifndef MINXLIB_DISPLAY_DOT_HH

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/event.cc.















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
/*
    @file  event.cc
    @brief Implementation of the API defined in event.hh.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

//----------------------------- HEADERS --------------------------------

// minxlib
#include "event.hh"
#include "logging.hh"
#include "python.hh"
#include "keymap.hh"

// Xlib
#include <X11/XKBlib.h>

// Boost
#include <boost/foreach.hpp>

// Standard C++
#include <iomanip>
#include <ostream>
#include <stdexcept>

//------------------------ EVENTS BASE CLASS ---------------------------

namespace minxlib {

static logging logger ;

// Public API for creating event objects
boost::shared_ptr<event> event::create(const XEvent& e, Display* d)
{
    typedef factory<event, int, cr_func, registry> event_factory ;
    try
    {
        boost::shared_ptr<event> p(event_factory::create(e.type, e, d)) ;
        return p ;
    }
    catch (event_factory::unknown_type&)
    {
        logger.warning() << "unknown event type " << e.type
                         << " on window " << e.xany.window ;
        boost::shared_ptr<event> p(new event(e, d, e.xany.window)) ;
        return p ;
    }
}

// Protected constructor
event::event(const XEvent& e, Display* d, Window w)
    : type(e.type),
      serial(e.xany.serial),
      send_event(e.xany.send_event == True),
      target(d, w)
{}

// Virtual destructor
event::~event(){}

// Base class exposed to Python
void event::pythonize()
{
    py::class_<event, boost::shared_ptr<event> >("event", py::no_init).
        def_readonly("type",       &event::type      ).
        def_readonly("serial",     &event::serial    ).
        def_readonly("send_event", &event::send_event).
        def_readonly("target",     &event::target    ).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__

    // Call pythonize for all the subclasses to export the event class
    // hierarchy to Python.
    BOOST_FOREACH(py_func p, registry::range())
        p() ;

    // Create logger for the events module
    logger = logging::get_logger("event") ;
}

// For Boost.Python to generate __str__
std::ostream& operator<<(std::ostream& os, const event&)
{
    return os << "x_any_event" ;
}

// Helper macro to generate the boilerplate code for registering event
// subclasses with the event factory and defining a stream output
// operator so Boost.Python can generate __str__.
#define register_minxlib_event(xlib_code, subclass)                     \
    std::ostream& operator<<(std::ostream& os, const subclass&) {       \
        return os << "x_" #subclass ;                                   \
    }                                                                   \
    bool subclass::registered = event::registry::add(xlib_code,         \
             create_object<event, subclass, const XEvent&, Display*>,   \
             subclass::pythonize)

//---------------- SUBSTRUCTURE REDIRECTION EVENTS ---------------------

// Map request events
register_minxlib_event(MapRequest, map_request) ;

map_request::map_request(const XEvent& e, Display* d)
    : event (e, d, e.xmaprequest.window),
      parent(d, e.xmaprequest.parent)
{}

void map_request::pythonize()
{
    py::class_<map_request, py::bases<event> >("map_request", py::no_init).
        def_readonly("parent", &map_request::parent).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

// Configure request events
register_minxlib_event(ConfigureRequest, configure_request) ;

configure_request::configure_request(const XEvent& e, Display* d)
    : event (e, d, e.xconfigurerequest.window),
      parent(d, e.xconfigurerequest.parent),
      x(e.xconfigurerequest.x), y(e.xconfigurerequest.y),
      width(e.xconfigurerequest.width), height(e.xconfigurerequest.height),
      border_width(e.xconfigurerequest.border_width),
      above(d, e.xconfigurerequest.above),
      stack_mode(e.xconfigurerequest.detail),
      value_mask(e.xconfigurerequest.value_mask)
{}

void configure_request::pythonize()
{
    py::class_<configure_request, py::bases<event> >("configure_request",
                                                     py::no_init     ).
        def_readonly("parent",       &configure_request::parent      ).
        def_readonly("x",            &configure_request::x           ).
        def_readonly("y",            &configure_request::y           ).
        def_readonly("width",        &configure_request::width       ).
        def_readonly("height",       &configure_request::height      ).
        def_readonly("border_width", &configure_request::border_width).
        def_readonly("above",        &configure_request::above       ).
        def_readonly("stack_mode",   &configure_request::stack_mode  ).
        def_readonly("value_mask",   &configure_request::value_mask  ).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

// Circulate request events
register_minxlib_event(CirculateRequest, circulate_request) ;

circulate_request::circulate_request(const XEvent& e, Display* d)
    : event (e, d, e.xcirculaterequest.window),
      parent(d, e.xcirculaterequest.parent),
      place(e.xcirculaterequest.place)
{}

void circulate_request::pythonize()
{
    py::class_<circulate_request, py::bases<event> >("circulate_request",
                                                     py::no_init).
        def_readonly("parent", &circulate_request::parent).
        def_readonly("place",  &circulate_request::place ).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

//------------- STRUCTURE AND SUBSTRUCTURE NOTIFICATIONS ---------------

// Window creation
register_minxlib_event(CreateNotify, create_notify) ;

create_notify::create_notify(const XEvent& e, Display* d)
    : event (e, d, e.xcreatewindow.window),
      parent(d, e.xcreatewindow.parent),
      x(e.xcreatewindow.x), y(e.xcreatewindow.y),
      width(e.xcreatewindow.width), height(e.xcreatewindow.height),
      border_width(e.xcreatewindow.border_width),
      override_redirect(e.xcreatewindow.override_redirect == True)
{}

void create_notify::pythonize()
{
    py::class_<create_notify, py::bases<event> >("create_notify", py::no_init).
        def_readonly("parent",            &create_notify::parent             ).
        def_readonly("x",                 &create_notify::x                  ).
        def_readonly("y",                 &create_notify::y                  ).
        def_readonly("width",             &create_notify::width              ).
        def_readonly("height",            &create_notify::height             ).
        def_readonly("border_width",      &create_notify::border_width       ).
        def_readonly("override_redirect", &create_notify::override_redirect  ).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

// Window reparenting
register_minxlib_event(ReparentNotify, reparent_notify) ;

reparent_notify::reparent_notify(const XEvent& e, Display* d)
    : event (e, d, e.xreparent.window),
      parent(d, e.xreparent.event ),
      new_parent(d, e.xreparent.parent),
      x(e.xreparent.x), y(e.xreparent.y),
      override_redirect(e.xreparent.override_redirect == True)
{}

void reparent_notify::pythonize()
{
    py::class_<reparent_notify, py::bases<event> >("reparent_notify",
                                                    py::no_init).
        def_readonly("parent",            &reparent_notify::parent           ).
        def_readonly("new_parent",        &reparent_notify::new_parent       ).
        def_readonly("x",                 &reparent_notify::x                ).
        def_readonly("y",                 &reparent_notify::y                ).
        def_readonly("override_redirect", &reparent_notify::override_redirect).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

// Window configuration
register_minxlib_event(ConfigureNotify, configure_notify) ;

configure_notify::configure_notify(const XEvent& e, Display* d)
    : event (e, d, e.xconfigure.window),
      parent(d, e.xconfigure.event ),
      x(e.xconfigure.x), y(e.xconfigure.y),
      width(e.xconfigure.width), height(e.xconfigure.height),
      border_width(e.xconfigure.border_width),
      above(d, e.xconfigure.above),
      override_redirect(e.xconfigure.override_redirect == True)
{}

void configure_notify::pythonize()
{
    py::class_<configure_notify, py::bases<event> >("configure_notify",
                                                    py::no_init).
        def_readonly("parent",           &configure_notify::parent           ).
        def_readonly("x",                &configure_notify::x                ).
        def_readonly("y",                &configure_notify::y                ).
        def_readonly("width",            &configure_notify::width            ).
        def_readonly("height",           &configure_notify::height           ).
        def_readonly("border_width",     &configure_notify::border_width     ).
        def_readonly("above",            &configure_notify::above            ).
        def_readonly("override_redirect",&configure_notify::override_redirect).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

// Gravity notifications
register_minxlib_event(GravityNotify, gravity_notify) ;

gravity_notify::gravity_notify(const XEvent& e, Display* d)
    : event (e, d, e.xgravity.window),
      parent(d, e.xgravity.event ),
      x(e.xgravity.x), y(e.xgravity.y)
{}

void gravity_notify::pythonize()
{
    py::class_<gravity_notify, py::bases<event> >("gravity_notify",
                                                  py::no_init).
        def_readonly("parent", &gravity_notify::parent).
        def_readonly("x",      &gravity_notify::x     ).
        def_readonly("y",      &gravity_notify::y     ).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

// Window mapping
register_minxlib_event(MapNotify, map_notify) ;

map_notify::map_notify(const XEvent& e, Display* d)
    : event (e, d, e.xmap.window),
      parent(d, e.xmap.event ),
      override_redirect(e.xmap.override_redirect == True)
{}

void map_notify::pythonize()
{
    py::class_<map_notify, py::bases<event> >("map_notify", py::no_init ).
        def_readonly("parent",            &map_notify::parent           ).
        def_readonly("override_redirect", &map_notify::override_redirect).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

// Window unmapping
register_minxlib_event(UnmapNotify, unmap_notify) ;

unmap_notify::unmap_notify(const XEvent& e, Display* d)
    : event (e, d, e.xunmap.window),
      parent(d, e.xunmap.event ),
      from_configure(e.xunmap.from_configure == True)
{}

void unmap_notify::pythonize()
{
    py::class_<unmap_notify, py::bases<event> >("unmap_notify", py::no_init).
        def_readonly("parent",         &unmap_notify::parent        ).
        def_readonly("from_configure", &unmap_notify::from_configure).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

// Circulate notifications
register_minxlib_event(CirculateNotify, circulate_notify) ;

circulate_notify::circulate_notify(const XEvent& e, Display* d)
    : event (e, d, e.xcirculate.window),
      parent(d, e.xcirculate.event ),
      place (e.xcirculate.place)
{}

void circulate_notify::pythonize()
{
    py::class_<circulate_notify, py::bases<event> >("circulate_notify",
                                                    py::no_init).
        def_readonly("parent", &circulate_notify::parent).
        def_readonly("place",  &circulate_notify::place ).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

// Window destruction
register_minxlib_event(DestroyNotify, destroy_notify) ;

destroy_notify::destroy_notify(const XEvent& e, Display* d)
    : event (e, d, e.xdestroywindow.window),
      parent(d, e.xdestroywindow.event )
{}

void destroy_notify::pythonize()
{
    py::class_<destroy_notify, py::bases<event> >("destroy_notify",
                                                  py::no_init).
        def_readonly("parent", &destroy_notify::parent).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

//------------------- KEYBOARD AND FOCUS EVENTS ------------------------

// If a given keycode and modifier mask correspond to a key binding,
// we'll return the hook name supplied by user for the passive grab for
// that keystroke. Otherwise, we'll simply translate the keycode to a
// string (via translation to a keysym).
static std::string keycode_to_string(Display* d, KeyCode k, unsigned int m)
{
    using std::dec ; using std::hex ; using std::setw ; using std::setfill ;
    logger.debug() << "key event: key code = " << dec << static_cast<int>(k)
                   << ", modifier mask = 0x"
                   << hex << setw(4) << setfill('0') << m ;
    try
    {
        return keymap::get(k, m) ; // user-defined name for a key binding
    }
    catch (std::out_of_range&) // no key binding
    {
        logger.debug() << "no key binding for [0x"
                       << hex << setw(4) << setfill('0') << m << " + 0x"
                       << hex << setw(4) << setfill('0')
                       << static_cast<int>(k) << ']' ;
        return XKeysymToString(XkbKeycodeToKeysym(d, k, 0, 0)) ;
    }
}

// Common attributes of keyboard events
key_event_details::key_event_details(const XKeyEvent& e, Display* d)
    : root(d, e.root), child(d, e.subwindow),
      time(e.time),
      x(e.x), y(e.y), x_root(e.x_root), y_root(e.y_root),
      mask(e.state), keycode(e.keycode),
      key(keycode_to_string(d, e.keycode, e.state)),
      same_screen(e.same_screen == True)
{}

// Key presses
register_minxlib_event(KeyPress, key_press) ;

key_press::key_press(const XEvent& e, Display* d)
    : event(e, d, e.xkey.window),
      key_event_details(e.xkey, d)
{}

void key_press::pythonize()
{
    py::class_<key_press, py::bases<event> >("key_press", py::no_init).
        def_readonly("root",        &key_press::root       ).
        def_readonly("child",       &key_press::child      ).
        def_readonly("time",        &key_press::time       ).
        def_readonly("x",           &key_press::x          ).
        def_readonly("y",           &key_press::y          ).
        def_readonly("x_root",      &key_press::x_root     ).
        def_readonly("y_root",      &key_press::y_root     ).
        def_readonly("mask",        &key_press::mask       ).
        def_readonly("keycode",     &key_press::keycode    ).
        def_readonly("key",         &key_press::key        ).
        def_readonly("same_screen", &key_press::same_screen).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

// Key releases
register_minxlib_event(KeyRelease, key_release) ;

key_release::key_release(const XEvent& e, Display* d)
    : event(e, d, e.xkey.window),
      key_event_details(e.xkey, d)
{}

void key_release::pythonize()
{
    py::class_<key_release, py::bases<event> >("key_release", py::no_init).
        def_readonly("root",        &key_release::root       ).
        def_readonly("child",       &key_release::child      ).
        def_readonly("time",        &key_release::time       ).
        def_readonly("x",           &key_release::x          ).
        def_readonly("y",           &key_release::y          ).
        def_readonly("x_root",      &key_release::x_root     ).
        def_readonly("y_root",      &key_release::y_root     ).
        def_readonly("mask",        &key_release::mask       ).
        def_readonly("keycode",     &key_release::keycode    ).
        def_readonly("key",         &key_release::key        ).
        def_readonly("same_screen", &key_release::same_screen).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

// Common attributes of focus change events
focus_change_details::focus_change_details(const XFocusChangeEvent& e)
    : mode(e.mode), detail(e.detail)
{}

// FocusIn
register_minxlib_event(FocusIn, focus_in) ;

focus_in::focus_in(const XEvent& e, Display* d)
    : event(e, d, e.xfocus.window),
      focus_change_details(e.xfocus)
{}

void focus_in::pythonize()
{
    py::class_<focus_in, py::bases<event> >("focus_in", py::no_init).
        def_readonly("mode",   &focus_in::mode  ).
        def_readonly("detail", &focus_in::detail).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

// FocusOut
register_minxlib_event(FocusOut, focus_out) ;

focus_out::focus_out(const XEvent& e, Display* d)
    : event(e, d, e.xfocus.window),
      focus_change_details(e.xfocus)
{}

void focus_out::pythonize()
{
    py::class_<focus_out, py::bases<event> >("focus_out", py::no_init).
        def_readonly("mode",   &focus_out::mode  ).
        def_readonly("detail", &focus_out::detail).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
}

} // namespace minxlib

//----------------------------------------------------------------------

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/event.hh.









































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
/**
    @file  event.hh
    @brief Encapsulation of X events.
    @defgroup grp_minxlib_events Minxlib's Event Hierarchy

    This file defines classes that wrap around the various X event
    structures and provide a Python interface to these structures for
    the rest of Minx to use.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MINXLIB_EVENT_DOT_HH
#define MINXLIB_EVENT_DOT_HH

//----------------------------- HEADERS --------------------------------

// minxlib
#include "window.hh"
#include "factory.hh"

// Xlib
#include <X11/Xlib.h>

// Boost
#include <boost/shared_ptr.hpp>

// Standard C++
#include <string>

//--------------------- BASE CLASS FOR X EVENTS ------------------------

namespace minxlib {

/**
    @ingroup grp_minxlib_events
    @brief A generic X event, i.e., XAnyEvent.

    This is a base class for the @ref grp_minxlib_events "event hierarchy"
    exposed by minxlib to the Python parts (i.e., the rest) of Minx. The
    "main" window manager object, viz., @ref minx.core.wm.wm
    "minx.core.wm", will receive instances of subclasses of this class
    in its event loop when it calls minxlib.display.get_event().

    If the Minx core receives an instance of this class itself, that
    means the event in question is an unregistered type. For registered
    event types, when an event is retrieved from the X event queue, we
    examine the event structure's type field and then create an object
    corresponding to that type and return the resulting object via a
    pointer to this class.

    For example, if we get a key press event from the X server, the
    XEvent will be used to create a minxlib::key_press object (which is
    derived from minxlib::event) and, then, we will return the key_press
    as a minxlib::event*.

    This module, viz., event.hh, uses an object factory to achieve the
    subclass object creation procedure described above. Unregistered
    event types are simply those <tt>XEvent::type</tt> values for which
    minxlib has no corresponding wrapper class derived from
    minxlib::event.

    It should be alright for the Minx core to ignore such unregistered
    events because, in all likelihood, the window manager won't care for
    them. However, if it becomes necessary to respond to an event that
    is not properly wrapped by minxlib, then the correct way to effect
    that would be to implement the wrapper class in this module so that
    the Python parts of Minx see an event object derived from
    minxlib.event rather than an instance of minxlib.event itself.

    On the Python side of Minx, the event type can, of course, be
    determined using the <tt>isinstance()</tt> function or the object's
    <tt>__class__</tt> attribute. However, it may be more convenient to
    simply use the <tt>str()</tt> function to get a string
    representation of the event object and use that instead.

    All minxlib.event objects have names of the form "x_something". For
    example, a key press event is called "x_key_press"; map requests are
    "x_map_request"; so on and so forth. The "x" in these object names
    indicate that the events are X events.
*/
struct event {
    /**
        @brief Event type as specified in X11/X.h.

        This field specifies the type of event using one of the codes in
        the X11/X.h header. The minxlib @ref grp_minxlib_events "event
        hierarchy" uses the value of this field in conjunction with an
        object factory to create instances of subclasses of the
        minxlib::event class.
    */
    const int type ;

    /**
        @brief Last request number processed by X server.

        The X server "tags" each event it generates with a serial
        number. This field records that number. It is not really used in
        minxlib or in Minx's Python core.
    */
    const unsigned long serial ;

    /**
        @brief True if triggered by SendEvent request.

        This flag will be true if the event is an "artificial" one,
        i.e., generated by an application calling the SendEvent function
        rather than by an actual key press, mouse move, etc.
    */
    const bool send_event ;

    /**
        @brief Event's target window.

        This field specifies the window on which the event occurred.
        Note that it is a minxlib::window object, which wraps around the
        Xlib notion of an X window.
    */
    const window target ;

protected:
    /**
        @brief  Create a wrapper object for an X event.
        @param  e The X event structure.
        @param  d The display object associated with the event.
        @param  w The Xlib ID of the target window for the event.
        @return A properly constructed event object.

        A protected constructor because event objects are meant to be
        instantiated using the create() factory method with only
        subclasses constructing the base data members.

        @note The fifth member of all Xlib event structures is a Window
        ID. However, in some of them, this field refers to the event's
        target window, while, in others, it refers to the target
        window's parent.

        @par
        In this base class, we don't know exactly which Xlib event
        structure to use from the XEvent union; only the subclasses that
        wrap around specific event types have that information.
        Therefore, we require all subclasses to specify the correct ID
        to use for the target window and ignore whatever is in
        XEvent::xany.
    */
    event(const XEvent& e, Display* d, Window w) ;

    /**
        @brief Signature of factory functions for creating events.

        Each event subclass is instantiated by a factory function that
        takes an XEvent structure and a display pointer and returns a
        subclass instance upcast to minxlib::event. This type provides a
        convenient name for factory functions matching the
        above-mentioned signature.

        All minxlib::event subclasses are required to implement a
        factory function matching this signature and to register it with
        the base class's
        @ref minxlib::event::registry "registry of subclass object factories".
        Usually, the factory function will simply be the appropriate
        create_object function from minxlib's
        @ref grp_factory "factory infrastructure".

    */
    typedef event* (*cr_func)(const XEvent&, Display*) ;

    /**
        @brief Signature of Pythonize functions.

        In addition to a factory function, each subclass of
        minxlib::event has to define a Pythonize function that will have
        the appropriate @boostpylink incantations in order to export its
        interface to minxlib's Python module.

        All subclass Pythonize functions will be called by
        event::pythonize(), which is invoked by the main Python
        initialization module python.cc. Pythonize functions take no
        parameters and return nothing.

        Like the factory functions, subclasses must register their
        Pythonize functions with the
        @ref event::registry "base class's registry of object factories",
        which stores pointers to the Pythonize functions in addition to
        the factory functions.

        @note Subclass Pythonize functions are usually static member
        functions in their respective classes.
    */
    typedef void (*py_func)() ;

    /**
        @brief Registry of subclass object factories and Pythonize functions.

        This type defines the event object factory's registry, which
        maps the Xlib event type codes to the corresponding event
        subclass's factory function. Additionally, we store the
        Pythonize functions in the registry as well, which obviates the
        need for another map to hold them.

        For the @ref grp_factory "factory pattern" to work, event
        subclasses must define a static boolean data member and, in its
        initializer, call event::registry::add(), passing it the
        appropriate Xlib event code, the subclass's factory function,
        and its Pythonize function.
    */
    typedef factory_map<int, cr_func, py_func> registry ;

public:
    /**
        @brief  Factory method for creating events.
        @param  e The X event structure for which we want a wrapper object.
        @param  d The display object associated with the event.
        @return Event object created on heap and wrapped in a smart pointer.

        We would like to expose the Xlib event types in such a way that
        the Python parts of Minx see a high-level, object-oriented
        interface to event processing instead of having to deal with
        low-level integers describing event types, etc. To achieve that,
        we use the @ref grp_factory "factory design pattern" to create
        objects based on the XEvent::type field.

        This method provides the public interface to the above-mentioned
        event object factory. It is meant to be used by
        minxlib::display::get_event() in order to convert low-level X
        event structures into appropriate object types belonging to
        minxlib's @ref grp_minxlib_events "event hierarchy".

        @note minxlib does not provide wrapper classes for all Xlib
        event types. Unwrapped event types will be reported via an
        instance of this, i.e., the event base class.

        @par
        @boostpylink has all sorts of magic in it to convert C++
        objects to their Python equivalents and vice versa. Since
        instances of minxlib::event are created using an object factory,
        i.e., on the heap and accessed via pointers, we need to wrap
        event objects in a boost::shared_ptr to make the Boost.Python
        conversion magic work with minimal effort.
    */
    static boost::shared_ptr<event> create(const XEvent& e, Display* d) ;

    /**
        @brief  Export event class to minxlib Python module.
        @return Nothing.

        This function exposes the event class's interface so that it
        can be used by the Python parts of Minx. It is meant to be
        called by the @boostpylink initialization code in python.cc.

        @note This function will call the Pythonize functions of all the
        minxlib::event subclasses, thus, exporting the entire @ref
        grp_minxlib_events "minxlib event hierarchy" to Python. For this to
        work, all subclasses must register their Pythonize routines with
        the @ref minxlib::event::registry "base class object factory registry"
        as described earlier.
    */
    static void pythonize() ;

    /**
        @brief  Event object clean-up.
        @return Nothing.

        Because minxlib::event is a base class for other event types, it
        is a good idea for it to have a virtual destructor.  This is
        especially necessary for the event class hierarchy because all
        events are created using a polymorphic factory that upcasts all
        subclass instances to minxlib::event*. Consequently, we have to
        provide a virtual destructor to ensure subclass objects are
        properly cleaned up when the base class pointers are deleted.

        Furthermore, to get the magic conversions in @boostpylink to
        work properly, we need at least one virtual method in the
        minxlib::event base class. Otherwise, on the Python side,
        instances of subclasses of this class will not have the correct
        type; the Python interpreter will see those objects as instances
        of minxlib.event rather than their actual derived types.
    */
    virtual ~event() ;
} ; // class event

// Each event subclass follows the same pattern: it has some public data
// members corresponding to the relevant fields of the XEvent type and
// then a constructor, a Pythonize function, a static boolean data
// member, and a friend declaration for the appropriate create_event
// factory function.
//
// Instead of typing out all of that over and over, we use the following
// macro to do it for us.
#define MINXLIB_EVENT_SUBCLASS_BOILERPLATE(subclass_name)                   \
    private:                                                                \
        subclass_name(const XEvent&, Display*) ;                            \
        static void pythonize();                                            \
        static bool registered ;                                            \
        friend event* create_object<event, subclass_name,                   \
                                    const XEvent&, Display*>(const XEvent&, \
                                                             Display*)

//---------------- SUBSTRUCTURE REDIRECTION EVENTS ---------------------

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of MapRequest events.

    We can ask the X server to redirect requests to show windows to Minx
    so that the window manager can decide what to do. These redirections
    are delivered via MapRequest events, which are wrapped by minxlib
    and delivered to Minx's Python core via instances of this class.
*/
struct map_request: public event {
    /**
        @brief The parent window of the window to be mapped.

        Since window managers are usually only concerned with top-level
        windows, we check this field to determine how to handle the map
        request. If it is equal to the root window of some screen, the
        target window is a top-level window that may need to be handled
        in a special way. Non top-level windows will usually have their
        map requests honoured "as-is."
    */
    const window parent ;

    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(map_request) ;
} ;

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of ConfigureRequest events.

    We can ask the X server to redirect requests to move and resize
    windows to Minx so that the window manager can decide exactly how to
    honour these configuration requests. These redirections are
    delivered via ConfigureRequest events, which are wrapped by minxlib
    and delivered to Minx's Python core via instances of this class.
*/
struct configure_request: public event {
    /**
        @brief The parent window of the window to be mapped.

        Since window managers are usually only concerned with top-level
        windows, we check this field to determine how to handle the
        configure request. If it is equal to the root window of some
        screen, the target window is a top-level window that may need to
        be handled in a special way (e.g., subject to the current layout
        policy).  Non top-level windows will usually have their
        configure requests honoured "as-is."
    */
    const window parent ;

    const int x ;            ///< Origin x-coordinate relative to parent.
    const int y ;            ///< Origin y-coordinate relative to parent.
    const int width ;        ///< Window width.
    const int height;        ///< Window height.
    const int border_width ; ///< Size of window border.

    const window above  ; ///< Sibling for stacking.
    const int stack_mode; ///< Above, Below, TopIf, BottomIf, Opposite.

    /**
        @brief Bit mask indicating what has to be configured.

        This field specifies which of the above fields are relevant to
        the configure request. Consult Xlib documentation for more
        information.
    */
    const unsigned long value_mask ;

    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(configure_request) ;
} ;

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of CirculateRequest events.

    When an application tries to circulate windows, we can have the X
    server redirect these requests to Minx to allow the window manager
    to handle them as it sees fit. These requests are delivered by
    minxlib to Minx's Python core via instances of this class.

    @note Since Minx is a tiling window manager and window circulation
    is mostly related to restacking windows, this event type is not very
    relevant to us.
*/
struct circulate_request: public event {
    /**
        @brief Parent of window requesting circulation.

        Since window managers are usually only concerned with top-level
        windows, we check this field to determine how to handle the
        circulate request. If it is equal to the root window of some
        screen, the target window is a top-level window that may need to
        be handled in a special way. Non top-level windows will usually
        have their circulate requests honoured "as-is."

        @note As mentioned earlier, being a tiling window manager,
        window circulation and stacking are not things Minx cares about.
    */
    const window parent ;

    /**
        @brief Window stack placement (PlaceOnTop, PlaceOnBottom).

        This field specifies whether the target window should be placed
        at the top or the bottom of the stack, which, for Minx (it being
        a tiling window manager and all), is pretty much useless.
    */
    const int place ;

    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(circulate_request) ;
} ;

//------------- STRUCTURE AND SUBSTRUCTURE NOTIFICATIONS ---------------

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of CreateNotify events.

    Minx's Python core can use these notifications to know when a new
    window is created.
*/
struct create_notify: public event {
    /**
        @brief Parent of new window.

        This field specifies the parent window of the new window. If it
        is equal to the root window of some screen, the target window is
        a top-level window that we need to be concerned with. We usually
        don't care about non top-level windows.
    */
    const window parent ;

    const int x ;            ///< Origin x-coordinate relative to parent.
    const int y ;            ///< Origin y-coordinate relative to parent.
    const int width ;        ///< Window width.
    const int height;        ///< Window height.
    const int border_width ; ///< Size of window border.

    /**
        @brief Should the window manager ignore this window?

        If this flag is on, the window manager should ignore the new
        window.
    */
    const bool override_redirect ;

    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(create_notify) ;
} ;

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of ReparentNotify events.

    When a window is reparented (typically by window managers), the X
    server notifies interested clients using these events.
*/
struct reparent_notify: public event {
    // Additional attributes of a reparent notify event
    const window parent ;          ///< Target window's old or new parent.
    const window new_parent ;      ///< Target window's new parent.
    const int x ;                  ///< Window origin x-coordinate.
    const int y ;                  ///< Window origin y-coordinate.
    const bool override_redirect ; ///< Window managers should ignore if true.

    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(reparent_notify) ;
} ;

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of ConfigureNotify events.

    The X server sends these events after a window has been moved,
    resized, or otherwise configured.
*/
struct configure_notify: public event {
    /**
        @brief Target window's parent.

        This field specifies the parent window of the configured window.
        If it is equal to the root window of some screen, the target
        window is a top-level window that we need to be concerned with.
        We usually don't care about non top-level windows.
    */
    const window parent ;

    const int x ;            ///< Origin x-coordinate relative to parent.
    const int y ;            ///< Origin y-coordinate relative to parent.
    const int width ;        ///< Window width.
    const int height;        ///< Window height.
    const int border_width ; ///< Size of window border.

    /**
        @brief Sibling for stacking.

        This has something to do with stacking operations, which, for
        Minx, has pretty much no use.
    */
    const window above ;

    /**
        @brief Should the window manager ignore this window?

        If this flag is on, the window manager should ignore the
        configured window.
    */
    const bool override_redirect ;

    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(configure_notify) ;
} ;

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of GravityNotify events.

    Who the heck knows what the hell this is about! Look at the relevant
    Xlib documentation for the gory details. We don't care about it in
    Minx. But, because it's easy, minxlib provides the encapsulation
    anyway...
*/
struct gravity_notify: public event {
    // Additional attributes of a gravity notify event
    const window parent ; ///< Target window's old or new parent.
    const int x ;                  ///< Window origin x-coordinate.
    const int y ;                  ///< Window origin y-coordinate.

    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(gravity_notify) ;
} ;

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of MapNotify events.

    The X server sends these events after a window is shown on the
    screen. This is an important event for window managers because
    windows cannot be focused until they have been mapped.
*/
struct map_notify: public event {
    /**
        @brief Target window's parent.

        This field specifies the parent window of the event's target
        window. If that's the root window of some screen, we have
        ourselves a top-level window that the window manager cares
        about; otherwise, it's some application's child window that we
        need not bother with.
    */
    const window parent ;

    /**
        @brief Should the window manager ignore this window?

        If this flag is on, the window manager should ignore the
        configured window.
    */
    const bool override_redirect ;

    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(map_notify) ;
} ;

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of UnmapNotify events.

    The X server sends these events after a window is hidden. This is an
    important event for window managers because a window can no longer
    be focused after it has been unmapped.
*/
struct unmap_notify: public event {
    /**
        @brief Target window's parent.

        This field specifies the parent window of the unmap
        notification's target window. If that's the root window of some
        screen, we have ourselves a top-level window that the window
        manager cares about; otherwise, it's some application's child
        window that we need not bother with.
    */
    const window parent ;

    /**
        @brief True if unmap notification is due to parent window resize.

        Not really sure what this is about; consult Xlib documentation
        for details. Maybe we don't care too much about this for Minx?
    */
    const bool from_configure ;

    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(unmap_notify) ;
} ;

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of CirculateNotify events.

    These events are sent by the X server after window circulation is
    complete. Minx does not worry about these events too much.
*/
struct circulate_notify: public event {
    // Additional attributes of a circulate notify event
    const window parent; ///< Target window's parent.
    const int    place ; ///< New position in stacking order: top, bottom.

    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(circulate_notify) ;
} ;

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of DestroyNotify events.

    These events are sent when windows are destroyed.
*/
struct destroy_notify: public event {
    /**
        @brief Parent window (for SubstructureNotify).

        XDestroyWindowEvent::event refers to either the destroyed window
        or its parent depending on whether we chose StructureNotify or
        SubstructureNotify in the event mask. Minx usually cares about
        substructure notifications for root windows. Thus, we interpret
        the XDestroyWindowEvent::event value as the target window's
        parent.
    */
    const window parent ;

    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(destroy_notify) ;
} ;

//------------------- KEYBOARD AND FOCUS EVENTS ------------------------

/**
    @ingroup grp_minxlib_events
    @brief Various attributes common to both key presses and releases.

    Xlib reports the same stuff for KeyPress and KeyRelease events and
    uses a typedef to alias the two event structures. Since minxlib uses
    two different types for the two event types, we put the relevant
    fields into this base class and have the relevant event subclasses
    derive from this class as well as minxlib::event.

    @note Xlib's XKeyEvent structure contains a modifier mask and a
    keycode, which we copy into this structure. Additionally, if the
    keyboard event's modifier mask and keycode correspond to a named key
    binding (configured by end-users), we "translate" that into the
    user-defined name and return it via this structure's key field. If,
    however, the event does not correspond to a user-defined key
    binding, the key field will simply be a string representing the
    keycode.
*/
struct key_event_details {
    const window root ;         ///< Target window's root window.
    const window child;         ///< Target's child that received event.
    const Time   time ;         ///< Millisecond timestamp of event.
    const int    x, y ;         ///< Mouse coords relative to target window.
    const int    x_root, y_root;///< Mouse coords relative to root.
    const unsigned int mask;    ///< State of mouse buttons & modifier keys.
    const unsigned int keycode; ///< Number representing physical key.
    const std::string  key ;    ///< String representation of key pressed.
    const bool same_screen ;    ///< True if target and root on same screen.

protected:
    /**
        @brief  Initialize keyboard event attributes.
        @param  e The XEvent structure detailing the keyboard event.
        @param  d The X server connection associated with the event.
        @return A properly constructed key_event_details object.

        A protected constructor because only key_press and key_release
        objects should construct instances of this class.
    */
    key_event_details(const XKeyEvent& e, Display* d) ;
} ;

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of KeyPress events.
*/
struct key_press: public event, public key_event_details {
    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(key_press) ;
} ;

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of KeyRelease events.
*/
struct key_release: public event, public key_event_details {
    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(key_release) ;
} ;

/**
    @ingroup grp_minxlib_events
    @brief Various attributes common to both focus-in and focus-out events.

    Xlib reports the same stuff for FocusIn and FocusOut events and
    uses a typedef to alias the two event structures. Since minxlib uses
    two different types for the two event types, we put the relevant
    fields into this base class and have the relevant event subclasses
    derive from this class as well as minxlib::event.
*/
struct focus_change_details {
    const int mode ;   ///< Normal or grab mode (see Xlib documentation).
    const int detail ; ///< More mode related info (see Xlib documentation).

protected:
    /**
        @brief  Initialize focus change event attributes.
        @param  e The Xlib structure detailing the focus change event.
        @return A properly constructed focus_change_details object.

        A protected constructor because only focus_in and focus_out
        objects should construct instances of this class.
    */
    focus_change_details(const XFocusChangeEvent& e) ;
} ;

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of FocusIn events.
*/
struct focus_in: public event, public focus_change_details {
    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(focus_in) ;
} ;

/**
    @ingroup grp_minxlib_events
    @brief Encapsulation of FocusOut events.
*/
struct focus_out: public event, public focus_change_details {
    MINXLIB_EVENT_SUBCLASS_BOILERPLATE(focus_out) ;
} ;

// Get rid of the boilerplate macro to ensure it can't be used outside
// this file.
#undef MINXLIB_EVENT_SUBCLASS_BOILERPLATE

} // namespace minxlib

//----------------------------------------------------------------------

#endif // #ifndef MINXLIB_EVENT_DOT_HH

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/exception.cc.







































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
/*
    @file  exception.cc
    @brief Implementation of API defined in excpetion.hh.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

//----------------------------- HEADERS --------------------------------

// minxlib
#include "exception.hh"
#include "util.hh"

// Boost
#include <boost/foreach.hpp>

//---------------------- EXCEPTION BASE CLASS --------------------------

namespace minxlib {

// Initialization and clean-up
exception::exception(const std::string& msg)
    : std::runtime_error(msg)
{}

exception::~exception() throw() {}

/*
    @brief  Create Python exception class.
    @param  name Name of the Python class.
    @param  base Base class from which to derive new exception class.
    @return The PyObject representing the new Python exception class.

    This function is lifted from:
        http://code.activestate.com/lists/python-cplusplus-sig/16646/

    See also:
        http://stackoverflow.com/questions/9620268/boost-python-custom-exception-class
*/
static PyObject* create_py_exception(const char* name, PyObject* base)
{
    // Figure out fully scoped class name
    std::string scope_name =
        py::extract<std::string>(py::scope().attr("__name__")) ;
    std::string qualified_name = scope_name + "." + name ;

    // Create the exception class
    PyObject* py_exception =
        PyErr_NewException(const_cast<char*>(qualified_name.c_str()), base, 0) ;
    if (!py_exception)
        py::throw_error_already_set() ;

    // Inject new class into Python interpreter
    py::scope().attr(name) = py::handle<>(py::borrowed(py_exception)) ;
    return py_exception ;
}

// Map for the pythonize routines of direct subclasses of
// minxlib::exception.
exception::pythonize_map exception::m_pythonize_map ;

// For direct subclasses: register your pythonize function
bool exception::register_pythonize(type_info t, exception::py_func f)
{
    m_pythonize_map[t] = f ;
    return true ;
}

// Map to store all Python exception class objects for the minxlib
// exception hierarchy.
exception::py_exception_map exception::m_py_exception_map ;

// For all subclasses: register your Python exception class
void exception::set_py_exception(type_info t, PyObject* e)
{
    m_py_exception_map[t] = e ;
}

// For all subclasses: retrieve the Python exception class corresponding
// to your type.
PyObject* exception::get_py_exception(type_info t)
{
    py_exception_map::const_iterator it = m_py_exception_map.find(t) ;
    if ( it == m_py_exception_map.end()) // unregistered subclass! BUG!
        return m_py_exception_map[typeid(exception)] ;
    return it->second ;
}

// Expose C++ exception class to Python
void exception::pythonize()
{
    const char* py_name = "exception";

    register_translator<exception>() ;
    py::class_<exception>(py_name, py::no_init) ;
    m_py_exception_map[typeid(exception)] =
        create_py_exception(py_name, PyExc_Exception) ;

    // Call pythonize for all the direct subclasses to export the
    // minxlib exception hierarchy to Python.
    BOOST_FOREACH(pythonize_map::value_type& p, m_pythonize_map)
        p.second() ;
}

/*
    @brief  Output operator for minxlib::exception objects.
    @param  s The output stream to which the exception should be sent.
    @param  e The exception object to be output.
    @return The output stream.

    This function converts the given minxlib::exception object to a
    human-readable form. Boost.Python uses it to define the __str__
    methods for the Python classes that represent minxlib exceptions.
    That way, when the Python parts of Minx receive minxlib exceptions,
    they can print something comprehensible instead of hex addresses and
    other such gobbledygook.

    NOTE: Defining this operator for the exception base class makes it
    available for all minxlib exception types and obviates the need to
    define the operator for all minxlib::exception subclasses. Of
    course, if the conversion to string provided by this function is
    inadequate for some particular subclass, we can always overload this
    function for that class.

    Alternatively, we could override std::exception::what() in the
    subclass and avoid overloading this operator.
*/
std::ostream& operator<<(std::ostream& os, const exception& e)
{
    return os << e.what() ;
}

//---------------------- X CONNECTION ERRORS ---------------------------

// This error will usually be reported when the window manager starts up
// and fails to connect to the X server. Since it is not triggered in an
// Xlib callback, but rather from a "straight" C++/Python context, we
// can throw this exception and have Boost.Python perform the necessary
// translation between the language run-time boundaries.
void connection_error::raise(const std::string& display_name)
{
    throw connection_error(display_name) ;
}

connection_error::connection_error(const std::string& display_name)
    : exception(std::string("unable to connect to display ") + display_name)
{}

bool connection_error::register_me =
                 register_pythonize(typeid(connection_error),
                                    &connection_error::pythonize) ;

void connection_error::pythonize()
{
    const char* py_name = "connection_error" ;
    PyObject*   py_base = get_py_exception(typeid(exception)) ;

    register_translator<connection_error>() ;
    py::class_<connection_error, py::bases<exception> >(py_name, py::no_init) ;
    set_py_exception(typeid(connection_error),
                     create_py_exception(py_name, py_base)) ;
}

//------------------------- FATAL X ERRORS -----------------------------

// Fatal X errors are reported via an Xlib callback (see
// minxlib::display::report_fatal_errors()). We cannot and should not
// throw an exception from that callback because it wreaks all sorts of
// havoc. However, we can raise a Python error without any problems...
void fatal_error::raise()
{
    fatal_error f ;
    py::object except(f) ;
    PyErr_SetObject(get_py_exception(typeid(fatal_error)),
                    py::incref(except.ptr())) ;
}

// In some situations, it may be okay to throw a fatal_error and let
// Boost.Python take care of translating the exception at the Python/C++
// boundary.
void fatal_error::throw_it()
{
    throw fatal_error() ;
}

fatal_error::fatal_error()
    : exception("fatal X error")
{}

bool fatal_error::register_me =
                 register_pythonize(typeid(fatal_error),
                                    &fatal_error::pythonize) ;

void fatal_error::pythonize()
{
    const char* py_name = "fatal_error" ;
    PyObject*   py_base = get_py_exception(typeid(exception)) ;

    register_translator<fatal_error>() ;
    py::class_<fatal_error, py::bases<exception> >(py_name, py::no_init).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__
    set_py_exception(typeid(fatal_error),
                     create_py_exception(py_name, py_base)) ;
}

//----------------------- X PROTOCOL ERRORS ----------------------------

// Public API for raising X protocol errors. These errors are reported
// via an Xlib callback (see minxlib::display::report_protocol_errors())
// and, so, cannot and should not be thrown. Instead, we inform Python
// clients by raising an appropriate Python exception without generating
// a corresponding C++ exception.
void protocol_error::raise(const XErrorEvent* e)
{
    // Use factory to create appropriate protocol_error sub-type based
    // on the protocol error's request code.
    boost::shared_ptr<protocol_error> p(create(e)) ;
    py::object except(p) ; // Python wrapper for above object

    // Get Python exception class corresponding to protocol error
    PyObject* py_exc_raw = get_py_exception(typeid(*p)) ;
    py::object py_exc_wrapped(py::handle<>(py::borrowed(py_exc_raw))) ;

    // Set protocol error attributes using their values from the actual
    // exception instance...
    py_exc_wrapped.attr("serial")       = p->serial       ;
    py_exc_wrapped.attr("error_code")   = p->error_code   ;
    py_exc_wrapped.attr("request_code") = p->request_code ;
    py_exc_wrapped.attr("minor_code")   = p->minor_code   ;
    py_exc_wrapped.attr("resource_id")  = p->resource_id  ;

    // That's it; now we can inform the Python side that some X protocol
    // request resulted in an X protocol error...
    //
    // NOTE: Thanks to the above attributes in the protocol_error class,
    // on the Python side, we can get the protocol error's request code,
    // error code, etc., directly from the exception object. Moreover,
    // since the exception object's value is set to the protocol_error
    // (sub-type) instance with the following call to PyErr_SetObject(),
    // we can also access these attributes from the args member of the
    // exception object.
    //
    // That is, on the Python side, we can do either:
    //      catch minxlib.protocol_error as e:
    //          print(e.error_code, e.request_code, e.resource_id)
    //
    // or:
    //      catch minxlib.protocol_error as e:
    //          print(e.args[0].error_code, e.args[0].request_code,
    //                e.args[0].resource_id)
    //
    // Obviously, the first approach is the preferred one because it
    // involves less typing.
    PyErr_SetObject(py_exc_raw, py::incref(except.ptr())) ;
}

// Factory method for creating different types of protocol errors
boost::shared_ptr<protocol_error> protocol_error::create(const XErrorEvent* e)
{
    typedef factory<protocol_error, unsigned long, cr_func, registry>
            error_factory ;
    try
    {
        boost::shared_ptr<protocol_error>
            p(error_factory::create(e->request_code, e)) ;
        return p ;
    }
    catch (error_factory::unknown_type&)
    {
        boost::shared_ptr<protocol_error> p(new protocol_error(e)) ;
        return p ;
    }
}

// "Generic" protocol error constructor
protocol_error::protocol_error(const XErrorEvent* e)
    : exception(to_str(e)),
      serial(e->serial),
      error_code(e->error_code),
      request_code(e->request_code),
      minor_code(e->minor_code),
      resource_id(e->resourceid)
{}

bool protocol_error::register_me =
    register_pythonize(typeid(protocol_error),
                       &protocol_error::pythonize) ;

// Expose protocol_error and its subclasses to Python
void protocol_error::pythonize()
{
    const char* py_name = "protocol_error" ;

    // Create Boost.Python wrapper for protocol_error class
    register_translator<protocol_error>() ;
    py::class_<protocol_error, py::bases<exception>,
               boost::shared_ptr<protocol_error> >(py_name, py::no_init).
        def_readonly("serial",       &protocol_error::serial      ).
        def_readonly("error_code",   &protocol_error::error_code  ).
        def_readonly("request_code", &protocol_error::request_code).
        def_readonly("minor_code",   &protocol_error::minor_code  ).
        def_readonly("resource_id",  &protocol_error::resource_id ).
        def(py::self_ns::str(py::self_ns::self)) ; // __str__

    // Create Python exception class for protocol errors
    PyObject* py_exc_raw =
        create_py_exception(py_name, get_py_exception(typeid(exception))) ;
    py::object py_exc_wrapped(py::handle<>(py::borrowed(py_exc_raw))) ;

    // All protocol errors have certain common attributes (serial,
    // error_code, etc.). So, let's create those attributes in the
    // Python protocol_error class...
    //
    // NOTE: Here, we initialize these attributes to zero. When we
    // actually raise a protocol error, we'll copy their values from the
    // protocol error's instance (which will be created with the
    // protocol_error factory).
    py_exc_wrapped.attr("serial")       = 0UL ;
    py_exc_wrapped.attr("error_code")   = 0UL ;
    py_exc_wrapped.attr("request_code") = 0UL ;
    py_exc_wrapped.attr("minor_code")   = 0UL ;
    py_exc_wrapped.attr("resource_id")  = 0UL ;

    // Register Python protocol_error class with base class map
    set_py_exception(typeid(protocol_error), py_exc_raw) ;

    // Call pythonize for all the subclasses to export the
    // protocol_error exception hierarchy to Python.
    BOOST_FOREACH(py_func p, registry::range())
        p() ;

    // Export the enumeration for the error code's possible values
    py::enum_<failed_request_reason>("failed_request_reason").
        value("bad_access",         bad_access        ).
        value("bad_alloc",          bad_alloc         ).
        value("bad_atom",           bad_atom          ).
        value("bad_color",          bad_color         ).
        value("bad_cursor",         bad_cursor        ).
        value("bad_drawable",       bad_drawable      ).
        value("bad_font",           bad_font          ).
        value("bad_gc",             bad_gc            ).
        value("bad_id_choice",      bad_id_choice     ).
        value("bad_implementation", bad_implementation).
        value("bad_length",         bad_length        ).
        value("bad_match",          bad_match         ).
        value("bad_name",           bad_name          ).
        value("bad_pixmap",         bad_pixmap        ).
        value("bad_request",        bad_request       ).
        value("bad_value",          bad_value         ).
        value("bad_window",         bad_window        ).
        export_values() ;
}

// As mentioned in exception.hh, each protocol_error subclass follows
// the exact same pattern:
//
//      - a constructor
//      - a Pythonize function
//      - a static bool data member for registering with base class factory
//      - a friend declaration for the factory function
//
// exception.hh uses a macro for the above boilerplate. We do the same
// here because definitions of the above functions and data member all
// do pretty much the exact same thing except that the class names are
// different. This avoids unnecessary repetition and is, therefore, less
// error-prone. Defining a new protocol_error subclass is a simple
// matter of using the macros in the header file and here.
#define DEFINE_PROTOCOL_ERROR_SUBCLASS(subclass, request_code)              \
                                                                            \
    subclass::subclass(const XErrorEvent* e): protocol_error(e) {}          \
                                                                            \
    void subclass::pythonize()                                              \
    {                                                                       \
        const char* py_name = #subclass ;                                   \
        PyObject*   py_base = get_py_exception(typeid(protocol_error)) ;    \
                                                                            \
        register_translator<subclass>() ;                                   \
        py::class_<subclass, py::bases<protocol_error> >(py_name,           \
                                                         py::no_init).      \
            def(py::self_ns::str(py::self_ns::self)) ;                      \
        set_py_exception(typeid(subclass),                                  \
                         create_py_exception(py_name, py_base)) ;           \
    }                                                                       \
                                                                            \
    bool subclass::registered = protocol_error::registry::                  \
            add(request_code,                                               \
                create_object<protocol_error, subclass, const XErrorEvent*>,\
                subclass::pythonize)

// Various subclasses of protocol_error
DEFINE_PROTOCOL_ERROR_SUBCLASS(query_tree_error, X_QueryTree) ;
DEFINE_PROTOCOL_ERROR_SUBCLASS( set_focus_error, X_SetInputFocus) ;
DEFINE_PROTOCOL_ERROR_SUBCLASS(change_window_attributes,
                               X_ChangeWindowAttributes) ;

// Get rid of boilerplate macro
#undef DEFINE_PROTOCOL_ERROR_SUBCLASS

} // namespace minxlib

//----------------------------------------------------------------------

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/exception.hh.





















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
/**
    @file  exception.hh
    @brief Various classes for exceptions generated by minxlib.
    @defgroup grp_minxlib_exceptions minxlib's Exception Classes

    This file defines classes for minxlib exceptions. These exception
    classes are exposed as Python classes derived from Python's standard
    Exception class.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MINXLIB_EXCEPTION_DOT_HH
#define MINXLIB_EXCEPTION_DOT_HH

//----------------------------- HEADERS --------------------------------

// minxlib
#include "factory.hh"
#include "type_info.hh"
#include "python.hh"

// Xlib
#include <X11/Xlib.h>
#include <X11/Xproto.h>

// Boost
#include <boost/shared_ptr.hpp>

// Standard C++
#include <ostream>
#include <map>
#include <stdexcept>
#include <string>
#include <utility>

//---------------------- EXCEPTION BASE CLASS --------------------------

namespace minxlib {

/**
    @ingroup grp_minxlib_exceptions
    @brief Base class for minxlib exceptions.

    This class acts as a base for the various exceptions thrown by
    minxlib. This class is exposed as a Python class that is derived
    from Python's standard Exception class. Thus, subclasses of this one
    inherit Python's Exception interface.

    @note This class cannot be instantiated directly by client code
    (neither inside minxlib nor in the Python side of Minx). It is meant
    to be a common base from which other, specific types of errors are
    derived.
*/
class exception: public std::runtime_error {
protected:
    /**
        @brief Signature for Pythonize functions.

        Each subclass has to define a static Pythonize function that
        will export its interface to minxlib's Python module using the
        appropriate @boostpylink incantations. All the Pythonize
        functions of direct subclasses will be called by
        exception::pythonize(), which is called by the main Python
        initialization module python.cc.

        @note The Pythonize functions of indirect subclasses, i.e.,
        subclasses of subclasses of minxlib::exception, should be called
        by the Pythonize functions of their respective direct base
        classes. To clarify, if we have two classes foo and bar derived
        from some_error, which is derived from minxlib::exception,
        exception::pythonize() will call some_error::pythonize(), which
        should, in turn, call foo::pythonize() and bar::pythonize().
    */
    typedef void (*py_func)() ;

private:
    // python.cc's Boost.Python module initialization sequence calls
    // this class's Pythonize routine to expose this class's Python
    // interface. To keep python.cc's dependencies small, it expects
    // exception::pythonize() to setup the Python interfaces for itelf
    // as well as its subclasses.
    //
    // Of course, we don't want the exception base class to have to know
    // all the classes derived from it because every time we add a new
    // exception type, we will have to update the base class Pythonize
    // function. Instead, we use this map to store the Pythonize
    // functions for all the subclasses and require them to register
    // themselves by adding their Pythonize functions to this map.
    //
    // NOTE: This map of Pythonize functions is meant to be used by
    // direct subclasses of the exception class. An exception subclass
    // that has its own subclasses should provide its own mechanism for
    // registration of subclass Pythonize functions.
    //
    // If indirect subclasses were to use this map, it is possible that
    // their Pythonize functions will get called before their direct
    // base class's Pythonize. For example, the protocol_error has
    // subclasses (set_focus_error, etc.). If set_focus_error were to
    // use this map itself, its Pythonize could be called before
    // protocol_error::pythonize(), which would be problematic because
    // Boost.Python needs to export the base class interface before
    // getting to a subclass.
    //
    // Therefore, only direct subclasses should register their Pythonize
    // functions in this map. Subclasses of subclasses of exception
    // should rely on registration mechanisms provided by their direct
    // base classes and not use this map.
    typedef std::map<type_info, py_func> pythonize_map ;
    static pythonize_map m_pythonize_map ;

    // For each C++ exception type, we need a corresponding Python class
    // object to represent it on the Python side of Minx. This map stores
    // references to these Python class objects for all of minxlib's
    // different exception types. All subclasses (direct and indirect)
    // are expected to create their Python exception classes in their
    // respective Pythonize routines and add that class object to this
    // map.
    typedef std::map<type_info, PyObject*> py_exception_map ;
    static py_exception_map m_py_exception_map ;

protected:
    /**
        @brief  Construct base exception object.
        @param  msg An error message describing the problem.
        @return A properly constructed minxlib::exception object.

        A protected constructor to ensure that only subclasses can
        construct objects of this type. The msg parameter is simply
        passed as-is to the std::runtime_error constructor.
    */
    exception(const std::string& msg) ;

    /**
        @brief  Register subclass's pythonize function.
        @param  t Subclass typeid.
        @param  f Pointer to subclass's pythonize function.
        @return Nothing really.

        The main Python initialization module, python.cc, calls
        exception::pythonize() to export the entire @ref grp_minxlib_exceptions
        "minxlib exception class hierarchy" to the Python parts of Minx.
        All subclasses of minxlib::exception are expected to implement a
        Pythonize function that takes care of exporting their respective
        Python interfaces.  To ensure that
        minxlib::exception::pythonize() can call the Pythonize functions
        of subclasses, all direct subclasses of minxlib::exception
        should call this function to let the base exception class know
        the address of the subclass's Pythonize function.

        @note Only direct subclasses of minxlib::exception should use
        this function. If a subclass of a subclass of minxlib::exception
        registers its Pythonize function using this routine, it could
        happen that the indirect subclass's Pythonize function gets
        called before its base class's Pythonize function, which can
        mess up the @boostpylink interface initialization sequence. Base
        classes of subclasses of subclasses of minxlib::exception should
        provide their own mechanisms for registering the Pythonize
        functions of their subclasses.

        To make the registration mechanism described above work, direct
        subclasses of minxlib::exception should declare a static bool
        variable and in its initializer, call this function.
    */
    static bool register_pythonize(type_info t, py_func f) ;

    /**
        @brief  Register Python exception class object for a subclass.
        @param  t Subclass typeid.
        @param  e The subclass's Python exception class.
        @return Nothing.

        Each minxlib exception class must have a corresponding Python
        exception class object, which must be registered with the
        minxlib::exception base class. In their respective Pythonize
        functions, all subclasses of minxlib::exception have to create a
        Python exception class corresponding to their C++ types and then
        call this function to insert that Python class object into the
        base class's registry of exception classes.

        @note Unlike register_pythonize(), which is meant only for
        direct subclasses of minxlib::exception, this function can and
        should be used by all subclasses (direct or indirect).
    */
    static void set_py_exception(type_info t, PyObject* e) ;

    /**
        @brief  Retrieve Python exception class for specified C++ type.
        @param  t C++ exception class/subclass typeid.
        @return Python exception class object corresponding to t.

        When we raise a minxlib exception to inform the Python side of
        Minx of some problem, we need the Python exception class
        corresponding to the C++ exception type. This function retrieves
        the desired Python exception class object from the registry
        maintained by the minxlib::exception base class.

        If a (direct or indirect) subclass of minxlib::exception fails to
        register a Python exception class corresponding to its C++ type,
        this function will return the Python exception class
        corresponding to the minxlib::exception class. If this ever
        happens, it indicates a bug in the implementation of type t!
    */
    static PyObject* get_py_exception(type_info t) ;

    /**
        @brief  Generic Boost.Python exception translator.
        @param  e C++ exception object that needs to be translated to Python.
        @return Nothing.

        This function sets up an exception translator for an exception
        of type T, which is expected to be either minxlib::exception or
        one of its subclasses.

        All these translators follow the same pattern, viz., calling
        PyErr_SetString() using the Python exception class corresponding
        to type T as stored in exception::m_py_exception_map. Thus, we
        can use a generic function for this purpose.
    */
    template<typename T>
    static void translate(const T& e) ;

    /**
        @brief  Register @boostpylink exception translator for type T.
        @return Nothing.

        This function is meant to be used in the Pythonize routines of
        minxlib::exception and its subclasses that need an exception
        translator for their type. It simply generates a translator for
        type T (which is the exception::translate<T>() function) and calls
        the appropriate @boostpylink API to register
        exception::translate<T>() as the exception translator for type T.
    */
    template<typename T>
    static void register_translator() {
        py::register_exception_translator<T>(translate<T>) ;
    }

public:
    /**
        @brief  Expose exception interface to Python.
        @return Nothing.

        This function is meant to be called as part of the @boostpylink
        module initialization. It will call the Pythonize functions of
        all minxlib::exception subclasses in order to export the entire
        @ref grp_minxlib_exceptions "minxlib exception hierarchy" to Python.
    */
    static void pythonize() ;

    /**
        @brief  Virtual destructor.
        @return Nothing.

        Since this is a base class, it's good to have a virtual
        destructor in place.

        @note std::runtime_error already has a virtual destructor.
        However, if we skip this definition, the compiler complains
        about this class's auto-generated destructor having looser throw
        specifications than the base class.
    */
    virtual ~exception() throw() ;
} ; // class exception

// Generic exception translator that can be used by minxlib::exception
// and all its subclasses.
template<typename T>
void exception::translate(const T& e)
{
    PyErr_SetString(get_py_exception(typeid(T)), e.what()) ;
}

//---------------------- X CONNECTION ERRORS ---------------------------

/**
    @ingroup grp_minxlib_exceptions
    @brief An exception object to indicate failure to connect to X server.

    When a minxlib::display object is created, if it fails to connect to
    the X server, the display class's constructor will throw an instance
    of this class to indicate the failure. On the Python side of Minx,
    this class is derived from minxlib.exception, which, in turn, is
    derived from the standard Python Exception class.
*/
struct connection_error: public exception {
    /**
        @brief  Throw a connection error.
        @param  display_name Name of display to which connection failed.
        @return Nothing.

        This function throws a connection_error. Clients cannot directly
        instantiate this class and throw it. Instead, they must call
        this function to have the object created and thrown.

        When raising a connection_error, the client must specify the
        name of X display to which the connection attempt failed.
        XDisplayName(), for example, will return something usable; refer
        to the Xlib documentation for further details.

        @note All the minxlib exception classes hide their constructors
        and require clients to call a raise() function instead. This is
        because, in some cases (errors to be reported from Xlib
        callbacks), throwing a C++ exception has very undesirable
        effects (e.g., the Minx process consuming 100% CPU). For those
        cases, we want to simply raise a Python exception without
        generating the corresponding C++ exception. Hiding the exception
        class constructors ensures that clients can only generate
        exceptions in the appropriate way.

        @par
        For connection errors, since they occur from a normal C++/Python
        context rather than from inside an Xlib callback, it is alright
        to throw a C++ exception and have Boost.Python perform the
        necessary translations. However, to keep minxlib's exception
        interface uniform, we hide this class's constructor as well and
        require clients to use raise(), which, internally, instantiates
        and throws a connection_error.
    */
    static void raise(const std::string& display_name) ;

private:
    /**
        @brief  Construct a connection_error object.
        @return Properly constructed connection_error object.

        Clients should specify the appropriate display name when
        creating a connection_error. XDisplayName(), for example, will
        return something usable.
    */
    connection_error(const std::string& display_name) ;

    /**
        @brief  Expose connection_error exception interface to Python.
        @return Nothing.

        This function is meant to be called as part of the Boost.Python
        module initialization.
    */
    static void pythonize() ;

    // Register with base class so its pythonize calls this subclass's
    // pythonize.
    static bool register_me ;
} ; // struct connection_error

//------------------------- FATAL X ERRORS -----------------------------

/**
    @ingroup grp_minxlib_exceptions
    @brief An exception object to indicate a fatal X error.

    When something fatal happens (such as losing the connection to the X
    server), minxlib will notify its Python clients by raising an
    instance of this class as an exception. Like all minxlib exceptions,
    on the Python side of Minx, this class is derived from
    minxlib.exception, which, in turn, is derived from the standard
    Python Exception class.

    After a fatal_error is raised, clients should clean-up and
    terminate. Attempting further use of Xlib via minxlib will result in
    continued fatal_error exceptions.
*/
struct fatal_error: public exception {
    /**
        @brief  Report a fatal X error.
        @return Nothing.

        This function raises a minxlib.fatal_error so the Python side of
        Minx is informed of catastrophic failures such as losing the
        connection to the X server.

        @note C++ clients cannot directly instantiate this class and
        throw it. Instead, they must call this function to have the
        error properly reported to the Python side.

        @par
        All the minxlib exception classes hide their constructors and
        require clients to call a raise() function instead. This is
        because, in some cases (errors to be reported from Xlib
        callbacks), throwing a C++ exception has very undesirable
        effects (e.g., the Minx process consuming 100% CPU). For those
        cases, we want to simply raise a Python exception without
        generating the corresponding C++ exception. Hiding the exception
        class constructors ensures that clients can only generate
        exceptions in the appropriate way.
    */
    static void raise() ;

    /**
        @brief  Throw a fatal_error in C++ rather than raising it in Python.
        @return Nothing.

        When a fatal X error is encountered,
        minxlib::display::report_fatal_errors() will raise a
        minxlib.fatal_error on the Python side without throwing a
        minxlib::fatal_error C++ exception because we cannot throw C++
        exceptions from Xlib callbacks.

        After that, minxlib::display will set an internal flag to
        indicate that a fatal error has been encountered and that its
        connection to the X server can no longer be used. Clients that
        try to ignore the first fatal_error and keep using minxlib's X
        API will then keep receiving more fatal_error exceptions.

        However, in this situation, it should be okay to throw a C++
        fatal_error and let @boostpylink perform the necessary exception
        translation at the Python/C++ boundary because the exception is
        not generated from inside an Xlib callback.

        This method allows the minxlib::display class and other minxlib
        clients to report a fatal error by throwing the exception rather
        than simply raising it in the Python interpreter.
    */
    static void throw_it() ;

private:
    /**
        @brief  Construct a fatal_error object.
        @return Properly constructed fatal_error object.

        A private constructor because the exception represented by this
        class is meant to be generated within the Xlib I/O error handler
        and we cannot throw C++ exceptions from inside Xlib callbacks.
        Therefore, we hide the constructor to ensure that clients
        generate this type of error in the proper way.
    */
    fatal_error() ;

    /**
        @brief  Expose fatal_error exception interface to Python.
        @return Nothing.

        This function is meant to be called as part of the Boost.Python
        module initialization.
    */
    static void pythonize() ;

    // Register with base class so its pythonize calls this subclass's
    // pythonize.
    static bool register_me ;
} ; // struct fatal_error

//----------------------- X PROTOCOL ERRORS ----------------------------

/**
    @ingroup grp_minxlib_exceptions
    @brief A base class to indicate X protocol errors.

    When an X protocol request fails, minxlib will notify its Python
    clients by raising an instance of this class or one of its
    subclasses as an exception. Like all minxlib exceptions, on the
    Python side of Minx, this class is derived from minxlib.exception,
    which, in turn, is derived from the standard Python Exception class.
*/
struct protocol_error: public exception {
    /**
        @brief Serial number of failed request.

        All requests to the X server have a serial number that starts at
        one. This field contains the request number corresponding to the
        protocol request that failed, thus, resulting in a
        protocol_error.

        @note This is a low-level detail of the X protocol and is not
        really used in Minx.
    */
    const unsigned long serial ;

    /**
        @brief Names for different error codes.

        This enumeration specifies the reason for a failed protocol
        request. It is simply the Xlib names converted from CamelCase to
        a saner naming convention:

            <table>
                <tr><th>minxlib           </th><th>Xlib             </th></tr>
                <tr><td>bad_access        </td><td>BadAccess        </td></tr>
                <tr><td>bad_alloc         </td><td>BadAlloc         </td></tr>
                <tr><td>bad_atom          </td><td>BadAtom          </td></tr>
                <tr><td>bad_color         </td><td>BadColor         </td></tr>
                <tr><td>bad_cursor        </td><td>BadCursor        </td></tr>
                <tr><td>bad_drawable      </td><td>BadDrawable      </td></tr>
                <tr><td>bad_font          </td><td>BadFont          </td></tr>
                <tr><td>bad_gc            </td><td>BadGC            </td></tr>
                <tr><td>bad_id_choice     </td><td>BadIDChoice      </td></tr>
                <tr><td>bad_implementation</td><td>BadImplementation</td></tr>
                <tr><td>bad_length        </td><td>BadLength        </td></tr>
                <tr><td>bad_match         </td><td>BadMatch         </td></tr>
                <tr><td>bad_name          </td><td>BadName          </td></tr>
                <tr><td>bad_pixmap        </td><td>BadPixmap        </td></tr>
                <tr><td>bad_request       </td><td>BadRequest       </td></tr>
                <tr><td>bad_value         </td><td>BadValue         </td></tr>
                <tr><td>bad_window        </td><td>BadWindow        </td></tr>
            </table>
    */
    enum failed_request_reason {
        bad_access         = BadAccess,
        bad_alloc          = BadAlloc,
        bad_atom           = BadAtom,
        bad_color          = BadColor,
        bad_cursor         = BadCursor,
        bad_drawable       = BadDrawable,
        bad_font           = BadFont,
        bad_gc             = BadGC,
        bad_id_choice      = BadIDChoice,
        bad_implementation = BadImplementation,
        bad_length         = BadLength,
        bad_match          = BadMatch,
        bad_name           = BadName,
        bad_pixmap         = BadPixmap,
        bad_request        = BadRequest,
        bad_value          = BadValue,
        bad_window         = BadWindow,
    } ;

    /**
        @brief Error code of failed request.

        This value specifies the reason for the failed request and will
        be one of the values of the failed_request_reason enumeration.
    */
    const unsigned long error_code ;

    /**
        @brief Major opcode of failed request.

        This member is the opcode of the failed X protocol request as
        defined in X11/Xproto.h.

        minxlib does not provide an enumeration for the different
        protocol request codes. However, some of the request codes are
        made available as specific exception types derived from
        protocol_error. Those that are not wrapped thusly can only be
        gleaned from the string representation of protocol_error, which
        will contain an appropriate name for the request code.
    */
    const unsigned long request_code ;

    /**
        @brief Minor opcode of failed request.

        No idea what the hell this is. Not used in Minx anyway.
    */
    const unsigned long minor_code ;

    /**
        @brief Resource ID associated with failed request.

        This member specifies the particular X object (window, GC,
        atom, whatever) that was involved with the protocol request that
        failed.

        For example, if we try to set the input focus to a window that
        has been unmapped or destroyed, the resulting protocol_error's
        resource_id will be the ID of that window. Since the X protocol
        is asynchronous, handling protocol_error exceptions and using
        this ID is about the only way to keep the window manager's
        internal state in-sync with the X server's internal state.
    */
    const unsigned long resource_id ;

    /**
        @brief  Report an X protocol error.
        @param  e XErrorEvent structure containing protocol error details.
        @return Nothing.

        This function raises a minxlib.protocol_error to inform the
        Python side of Minx of various X-related errors such as
        attempting to set the input focus on a non-existent or unmapped
        window.

        Most X protocol errors will be reported using
        minxlib.protocol_error. However, certain protocol errors have
        specific types that are derived from this class. The Python side
        of Minx can use these subclass types to easily catch and handle
        specific errors.

        @note C++ clients cannot directly instantiate this class and
        throw it. Instead, they must call this function to have the
        error properly reported to the Python side. This is because
        throwing a C++ exception from inside an Xlib callback makes the
        Minx process enter some sort of infinite loop and consume 100%
        CPU. Basically, interaction between C and C++ with regards to
        exceptions and stack unwinding is ill-defined (or, at least when
        it comes to Xlib and minxlib, it is).
    */
    static void raise(const XErrorEvent* e) ;

private:
    /**
        @brief  Create a protocol_error exception.
        @param  e XErrorEvent structure containing protocol error details.
        @return Shared pointer to protocol_error or subclass instance.

        This function serves as the factory method for creating
        protocol_error objects. For certain errors, minxlib can provide
        more detailed information by raising an instance of a subclass
        of this class as an exception.

        For example, when an X_SetInputFocus request fails, the error
        will be reported via an instance of minxlib.set_focus_error,
        which is derived from minxlib.protocol_error (i.e., the Python
        interface to this class). Thus, the Minx Python core can readily
        make out the type of error it is dealing with simply by catching
        that particular exception type instead of having to examine the
        various fields of a minxlib.protocol_error.

        This factory method creates a subclass instance corresponding to
        the XErrorEvent's request code. Not all request codes are
        supported by minxlib. In those cases, a protocol_error object
        will be returned.

        Note that this factory method is private! Only the raise
        function can use it. Clients do not need to access it directly.
    */
    static boost::shared_ptr<protocol_error> create(const XErrorEvent* e) ;

protected:
    /**
        @brief  Construct a protocol_error object.
        @param  e The XErrorEvent structure detailing the error.
        @return Properly constructed protocol_error object.

        This class is meant to be used by the Xlib error handler,
        which is implemented in minxlib by
        display::report_protocol_errors(). That function will be
        passed an XErrorEvent by Xlib, which it will, in turn, pass
        to this constructor. The constructor converts the error to
        human-readable form and also records the various fields in
        the protocol_error object it creates.

        @note This is a protected constructor because protocol_error
        instances are meant to be created using the create() factory
        method and only subclasses may initialize the base.
    */
    protocol_error(const XErrorEvent* e) ;

    /**
        @brief Signature of factory function.

        Each protocol_error subclass will be instantiated by a factory
        function that takes an XErrorEvent and returns an instance of
        the subclass upcast to minxlib::protocol_error.
    */
    typedef protocol_error* (*cr_func)(const XErrorEvent*) ;

    /**
        @brief Registry of factory functions for instantiating subclasses.

        This type defines the protocol_error object factory's registry,
        which maps the X protocol error codes to the corresponding
        protocol_error subclass's factory function. Additionally, we
        store the Pythonize functions in the registry as well, which
        obviates the need for another map to hold them.

        For the @ref grp_factory "factory pattern" to work,
        protocol_error subclasses must define a static boolean data
        member and, in its initializer, call
        protocol_error::registry::add(), passing it the appropriate X
        protocol error code, the subclass's factory function, and its
        Pythonize function.
    */
    typedef factory_map<unsigned long, cr_func, py_func> registry ;

private:
    /**
        @brief  Expose protocol_error exception interface to Python.
        @return Nothing.

        This function is meant to be called as part of the Boost.Python
        module initialization.
    */
    static void pythonize() ;

    // Register with base class so its pythonize calls this subclass's
    // pythonize.
    static bool register_me ;
} ; // struct protocol_error

//----------------- SPECIFIC PROTOCOL ERROR TYPES ----------------------

// Each protocol_error subclass follows the same pattern: a constructor,
// a Pythonize function, a static boolean data member, and a friend
// declaration for the appropriate create_error factory function.
//
// Instead of typing out all of that over and over, we use the following
// macro to do it for us.
#define DECLARE_PROTOCOL_ERROR_SUBCLASS(subclass)                       \
    class subclass: public protocol_error {                             \
        subclass(const XErrorEvent*) ;                                  \
        static void pythonize();                                        \
        static bool registered ;                                        \
        friend protocol_error* create_object<protocol_error, subclass,  \
                   const XErrorEvent*>(const XErrorEvent*) ;            \
    }

// Input focus related errors
DECLARE_PROTOCOL_ERROR_SUBCLASS(query_tree_error) ;
DECLARE_PROTOCOL_ERROR_SUBCLASS( set_focus_error) ;
DECLARE_PROTOCOL_ERROR_SUBCLASS(change_window_attributes) ;

// Get rid of the boilerplate macro to ensure it can't be used outside
// this file.
#undef DECLARE_PROTOCOL_ERROR_SUBCLASS

} // namespace minxlib

//----------------------------------------------------------------------

#endif // #ifndef MINXLIB_EXCEPTION_DOT_HH

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/factory.hh.































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
/**
    @file  factory.hh
    @brief Generic object factory.
    @defgroup grp_factory minxlib's Object Factory Framework

    This file defines classes that provide a generic object factory
    framework for use in other parts of minxlib.

    @note This framework is designed specifically for use in minxlib. It
    is not some bulletproof, industrial strength concoction suitable for
    wide reuse.

    Here is a sample program illustrating how this framework is meant to
    be used:

    @code
        #include "factory.hh"

        #include <boost/shared_ptr.hpp>

        #include <iostream>
        #include <sstream>
        #include <string>

        namespace minxlib {

        class base {
            std::string m_name ;
        protected:
            base(const std::string& s) {
                std::ostringstream str ;
                str << s << '_' << reinterpret_cast<unsigned long>(this) ;
                m_name = str.str() ;
            }

            // Base class should specify these types to ease registration
            // with factory.
            typedef base* (*create_func)() ;
            typedef factory_map<int, create_func> registry ;

        public:
            // Usually, base class will provide a factory method for
            // instantiating subclasses in the hierarchy.
            static boost::shared_ptr<base> create(int t) {
                typedef factory<base, int,
                                create_func, registry> object_factory ;
                try {
                    boost::shared_ptr<base> p(object_factory::create(t)) ;
                    return p ;
                }
                catch (object_factory::unknown_type&) {
                    boost::shared_ptr<base> p(new base("base")) ;
                    return p ;
                }
            }

            const std::string& name() const {return m_name ;}
            virtual ~base(){}
        } ;

        std::ostream& operator<<(std::ostream& os, const base& b)
        {
            return os << b.name() ;
        }

        class derived_one: public base {
            derived_one(): base("derived_one"){}

            // Subclasses should have these to make factory work
            static bool registered ;
            friend base* create_object<base, derived_one>() ;
        } ;

        bool derived_one::registered =
                 base::registry::add(1, create_object<base, derived_one>) ;

        class derived_two: public base {
            derived_two(): base("derived_two"){}

            // Subclasses should have these to make factory work
            static bool registered ;
            friend base* create_object<base, derived_two>() ;
        } ;

        bool derived_two::registered =
                 base::registry::add(2, create_object<base, derived_two>) ;

        } // namespace minxlib

        int main()
        {
            const int n = 10 ;
            int id[n] = {0, 1, 2, 2, 1, 3, 1, 2, 1, -1} ;
            for (int i = 0; i < n; ++i) {
                boost::shared_ptr<minxlib::base>
                    p(minxlib::base::create(id[i])) ;
                std::cout << "object " << (i+1) << ": " << id[i]
                          << ' ' << *p << '\n' ;
            }
            return 0 ;
        }
    @endcode

    The above code shows classes that are created using their default
    constructors. The factory::create() methods and create_object()
    functions have overloads that support up to two arguments.

    Moreover, the above sample program does not illustrate the
    factory_map's support for storing arbitrary, client-supplied data
    for each class. See the implementations of minxlib::event (in
    event.hh and event.cc) and minxlib::protocol_error
    (exception.{hh,cc}) for the low-down on that feature.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MINXLIB_FACTORY_DOT_HH
#define MINXLIB_FACTORY_DOT_HH

//----------------------------- HEADERS --------------------------------

// Boost
#include <boost/iterator_adaptors.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/utility.hpp>

// Standard C++
#include <map>
#include <stdexcept>
#include <string>
#include <utility>

//-------------------- OBJECT FACTORY REGISTRY -------------------------

namespace minxlib {

// An empty type for use as default template arguments
namespace {struct null_type {} ;}

/**
    @ingroup grp_factory
    @brief A registry mapping keys to factory functions.

    This class implements a singleton map that holds the subclass
    factory functions (type F) for classes in a hierarchy identified by
    keys of type K. In addition to the factory functions, it can also
    hold arbitrary data of type D.

    The factory functions are used by the factory class defined in this
    file. However, the optional arbitrary data is only held and can be
    used by client classes in whatever way they see fit. In minxlib,
    this is usually used for the pythonize functions; see event.hh (for
    example).

    @note To use more than a single item of arbitrary data, you can use
    a boost::tuple.

    @par
    As mentioned earlier, this object factory framework is designed
    specifically for minxlib and is not meant for wide reuse.  One of
    the implications of this is that the types K, F, and D should be
    cheap to construct and copy. In minxlib, K is typically an integral
    type, F and D are function pointers.
*/
template<typename K, typename F, typename D = null_type>
class factory_map: public boost::noncopyable {
    // We stuff the factory function and client-supplied arbitrary data
    // into an STL pair so we can store both together in the factory
    // map.
    typedef std::pair<F, D> value_type ;

    // This type defines the mapping between class identifiers and their
    // corresponding factory functions plus arbitrary data.
    typedef std::map <K, value_type> map_type ;

    // We use iterators to allow clients to retrieve their data stored
    // in this map.
    //
    // NOTE: We only provide const iterators. That is, once data is
    // stored in this map, it can only be read back.
    typedef typename map_type::const_iterator map_iterator ;

    // Okay, enough of the clarifying typedefs; here's the actual data
    // structure.
    map_type m_map ;

    /**
        @brief  Initialize the factory registry.
        @return Nothing really.

        A private constructor because this class is meant to be a
        singleton and we don't want clients trying to instantiate it.
    */
    factory_map() ;

    /**
        @brief  Instantiate lone instance of this class.
        @return Reference to the lone instance.

        This function creates a static instance of this class when it is
        called for the first time. Then (and on subsequent invocations)
        it returns a reference to that static instance.

        This method is also private because we don't want clients to
        care about this implementation detail. They should use the
        static methods in the class's public interface and let those
        functions worry about the fact that this class is a singleton.

        @note This class uses the fairly standard singleton idiom as
        described in Scott Meyers's book "Effective C++." However, as
        Andrei Alexandrescu points out in "Modern C++ Design," there are
        limitations and problems with this approach.

        @par
        Reiterating what was mentioned earlier: this object factory
        framework is not bulletproof, nor is it meant to be so. For
        Minx's intended use-case, this should work just fine.
    */
    static factory_map& instance() ;

    /**
        @brief  Find value corresponding to given key.
        @param  k The key whose value we want.
        @return The value corresponding to k or a bad_key exception.

        This function looks up the key k in the map of keys to factory
        functions plus user-supplied data and returns that value in an
        STL pair whose first element is the factory function and whose
        second element is the user-supplied data.

        If the map does not hold any value corresponding to the given
        key k, this function will throw a bad_key exception.
    */
    value_type find(K k) const ;

public:
    /**
        @brief  Register a factory and optional data.
        @param  k The key identifying a class in some hierarchy.
        @param  f The factory function for the class identified by k.
        @param  d Optional data to be stored along with the class's factory.
        @return True (i.e., useless return value).

        This function is meant to be used by subclasses in a class
        hierarchy that is to be instantiated with an object factory. The
        typical usage pattern would be for each subclass in the
        hierarchy to define a static bool data member and call this
        function in that data member's initializer.
    */
    static bool add(K k, F f, D d = null_type()) {
        instance().m_map[k] = value_type(f, d) ;
        return true ;
    }

    /**
        @brief  Retrieve the factory function for a class.
        @param  k They key identifying the class whose factory we want.
        @return The factory function for the specified class.

        This function is meant to be called by the minxlib::factory
        class. Other clients should have little use for it.
    */
    static F get_factory(K k) {return instance().find(k).first ;}

    /**
        @brief  Retrieve the user-supplied arbitrary data for a class.
        @param  k They key identifying the class whose user data we want.
        @return The user data for the specified class.

        This function is meant to be called by clients so they can get
        the arbitrary data they supplied when registering their
        factories. Typically, however, clients will iterate over the map
        and use the data values through that process.
    */
    static D get_data(K k) {return instance().find(k).second ;}

    /**
        @brief Exception to indicate nonexistent key.

        When a client requests a factory function or client data
        associated with a key that is not in the map, an instance of
        this class will be thrown.
    */
    struct bad_key: public std::runtime_error {
        const K key ;
        bad_key(K k);
    } ;

    /**
        @brief Iterator for accessing client-supplied arbitrary data.

        Although clients may retrieve the arbitrary data they supply by
        passing the desired key to the factory_map::get_data() function,
        it may be more convenient to iterate over the underlying map.
        This inner class provides the necessary interface for iteration.

        @note This iterator class is built on the const_iterator
        provided by the underlying STL map. Thus, it only supports read
        access to the client-supplied data.

        @par
        This class implements its functionality using Boost.Iterator,
        whose magic obviates the need for any public methods.
    */
    class iterator: public boost::iterator_adaptor<iterator, map_iterator, D> {
        // Construct using underlying STL map's (const) iterator.
        // DEVNOTE: iterator_adaptor_ member is courtesy Boost.Iterator.
        iterator(map_iterator& i): iterator::iterator_adaptor_(i){}

        // Move to next element in sequence
        void increment() {++this->base_reference() ;}

        // Retrieve data currently being "pointed" at
        D& dereference() const {
            return const_cast<D&>(this->base_reference()->second.second) ;
        }

        // We want only the factory_map (outer) class to be able to
        // instantiate this iterator.
        friend class factory_map ;

        // Standard Boost.Iterator idiom
        friend class boost::iterator_core_access ;
    } ; // class iterator

    /**
        @brief Read-only iterators.

        This class's iterators are already read-only. Therefore, the
        const_iterator type is the same as the iterator type.
    */
    typedef iterator const_iterator ;

    /**
        @brief  Obtain read-only iterator to first data item.
        @return Iterator to first item.

        When some function wants to iterate over all the arbitrary data
        items supplied during the registration of the various subclass
        factories, it can request an iterator to the first item of the
        underlying sequence using this function.

        @note Once data is stored in a factory_map, clients may only
        obtain read-only access to it. That is, the iterator returned by
        this function is a const_iterator.
    */
    static const_iterator begin() ;

    /**
        @brief  Obtain read-only iterator to one past last data item.
        @return Iterator pointing to one-past last item.

        When some function wants to iterate over all the arbitrary data
        items supplied during the registration of the various subclass
        factories, it can request an iterator to one-past the last item
        of the underlying sequence using this function.

        @note Once data is stored in a factory_map, clients may only
        obtain read-only access to it. That is, the iterator returned by
        this function is a const_iterator.
    */
    static const_iterator end() ;

    /**
        @brief  Pack begin and end iterators in an STL pair.
        @return STL pair containing begin and end iterators.

        This function is meant to be used in conjunction with
        BOOST_FOREACH. Here is an illustrative (albeit non-buildable)
        example:

        @code
            class foo { ... } ;
            class bar { ... } ;
            typedef foo* (*create_foo)() ;
            typedef factory_map<int, create_foo, bar> registry ;

            // code to register various factory functions and bar
            // objects in registry

            void f()
            {
                BOOST_FOREACH(const bar& b, registry::range())
                    b.do_something() ;
            }
        @endcode
    */
    static std::pair<const_iterator, const_iterator> range() {
        return std::make_pair(begin(), end()) ;
    }
} ; // class factory_map

// Private constructor
template<typename K, typename F, typename D>
factory_map<K,F,D>::factory_map(){}

// Singleton method
template<typename K, typename F, typename D>
factory_map<K,F,D>& factory_map<K,F,D>::instance()
{
    static factory_map m ;
    return m ;
}

// Map lookup
template<typename K, typename F, typename D>
typename factory_map<K,F,D>::value_type factory_map<K,F,D>::find(K k) const
{
    typename map_type::const_iterator it = m_map.find(k) ;
    if (it == m_map.end())
        throw bad_key(k) ;
    return it->second ;
}

// Iterators for accessing client-supplied arbitrary data stored along
// with factory functions.
template<typename K, typename F, typename D>
typename factory_map<K,F,D>::iterator factory_map<K,F,D>::begin()
{
    const factory_map& m = instance();
    map_iterator it = m.m_map.begin();
    return iterator(it) ;
}

template<typename K, typename F, typename D>
typename factory_map<K,F,D>::iterator factory_map<K,F,D>::end()
{
    const factory_map& m = instance();
    map_iterator it = m.m_map.end()  ;
    return iterator(it) ;
}

// Exception for unknown key
template<typename K, typename F, typename D>
factory_map<K,F,D>::bad_key::bad_key(K k)
    : std::runtime_error(std::string("unknown key: " +
                         boost::lexical_cast<std::string>(k))),
      key(k)
{}

//--------------------- GENERIC OBJECT FACTORY -------------------------

/**
    @ingroup grp_factory
    @brief Object factory for subclasses of type T.

    This class defines an object factory for subclasses of some base
    type T. Each subclass is expected to be identified uniquely by a
    value of type K (usually, an integral type). A function matching the
    signature specified by type F (usually a function pointer) should be
    registered with the factory and it should use the new operator to
    create an instance of the subclass identifed by K and upcast that to
    a T*.

    The type M is expected to be an associative container that maps
    subclass identifier keys of type K to their factory functions of
    type F. By default, this type is factory_map<K,F>, which stores keys
    and factory functions and no client data. In minxlib, however, we
    usually use a factory_map<K,F,D>, where D is usually a function
    pointer for the pythonize functions.

    The factory_map class defined above is good enough for most purposes
    and there should be little need to implement a whole new type M.
    However, if such madness becomes necessary, then, at the very least,
    from the factory class's perspective, the type M has to define a
    static get_factory() method that will return an F given a K.

    @note There is an implicit assumption that the type M will be a
    singleton.
*/
template<typename T, typename K, typename F, typename M = factory_map<K,F> >
class factory: boost::noncopyable {
    // An undefined, private constructor to ensure nobody tries to
    // instantiate this class, whose public interface consists mostly of
    // overloaded versions of static create() methods that produce
    // objects of type T given class identifiers of type K.
    factory() ;

public:
    /**
        @brief Exception to indicate an unregistered subclass.

        For the factory pattern to work, subclasses in a hierarchy
        should register their factory functions with this framework.
        Otherwise, if a client, usually the base class factory method,
        asks the factory for an instance of a type it knows nothing
        about, the factory will complain by throwing an instance of this
        exception class.
    */
    struct unknown_type: public std::runtime_error {
        const K key ;
        unknown_type(K k) ;
    } ;

    /**
        @brief  Create an instance of a subclass of T.
        @param  k Identifier for the desired subclass.
        @return An instance of the desired subclass or an exception.

        This function is for creating objects of class identified by k
        using the default constructor for that class. The object will be
        upcast to the base class T.

        This function will retrieve the factory function for the desired
        class from the factory map (type M of this template) and use
        that to create the object. The subclass identified by k should
        have registered its factory function with the factory map. The
        factory function should create an instance of the subclass using
        the new operator and upcast the result to the base class type T.

        If this function fails to retrieve a factory function for the
        given key k, it will throw an unknown_type exception. Clients
        should be prepared to handle this exception.
    */
    static T* create(K k) ;

    /**
        @brief  Create an instance of a subclass of T.
        @param  k Identifier for the desired subclass.
        @param  a Argument for the subclass's constructor.
        @return An instance of the desired subclass or an exception.

        This function is for creating objects of class identified by k
        using the one-argument constructor for that class. The object
        will be upcast to the base class T.

        This function will retrieve the factory function for the desired
        class from the factory map (type M of this template) and use
        that to create the object. The subclass identified by k should
        have registered its factory function with the factory map. The
        factory function should create an instance of the subclass using
        the new operator, passing the constructor the argument a, and
        upcast the result to the base class type T.

        If this function fails to retrieve a factory function for the
        given key k, it will throw an unknown_type exception. Clients
        should be prepared to handle this exception.
    */
    template<typename A>
    static T* create(K k, A a) ;

    /**
        @brief  Create an instance of a subclass of T.
        @param  k Identifier for the desired subclass.
        @param  a First argument for the subclass's constructor.
        @param  b Second argument for the subclass's constructor.
        @return An instance of the desired subclass or an exception.

        This function is for creating objects of class identified by k
        using the two-argument constructor for that class. The object
        will be upcast to the base class T.

        This function will retrieve the factory function for the desired
        class from the factory map (type M of this template) and use
        that to create the object. The subclass identified by k should
        have registered its factory function with the factory map. The
        factory function should create an instance of the subclass using
        the new operator, passing the constructor the arguments a and b,
        and upcast the result to the base class type T.

        If this function fails to retrieve a factory function for the
        given key k, it will throw an unknown_type exception. Clients
        should be prepared to handle this exception.
    */
    template<typename A, typename B>
    static T* create(K k, A a, B b) ;
} ;

// Exception for unregistered subclasses
template<typename T, typename K, typename F, typename M>
factory<T,K,F,M>::unknown_type::unknown_type(K k)
    : std::runtime_error(std::string("unknown object type: " +
                         boost::lexical_cast<std::string>(k))),
      key(k)
{}

// Default constructor factory method
template<typename T, typename K, typename F, typename M>
T* factory<T,K,F,M>::create(K k)
{
    try
    {
        F f = M::get_factory(k) ;
        return f() ;
    }
    catch (typename M::bad_key&)
    {
        throw unknown_type(k) ;
    }
}

// One argument constructor factory method
template<typename T, typename K, typename F, typename M>
template<typename A>
T* factory<T,K,F,M>::create(K k, A a)
{
    try
    {
        F f = M::get_factory(k) ;
        return f(a) ;
    }
    catch (typename M::bad_key&)
    {
        throw unknown_type(k) ;
    }
}

// Two argument constructor factory method
template<typename T, typename K, typename F, typename M>
template<typename A, typename B>
T* factory<T,K,F,M>::create(K k, A a, B b)
{
    try
    {
        F f = M::get_factory(k) ;
        return f(a, b) ;
    }
    catch (typename M::bad_key&)
    {
        throw unknown_type(k) ;
    }
}

// DEVNOTE: Will Boost.Preprocessor help automate the above boilerplate
// and the repetition in the definitions of the overloaded
// create_object() functions below? Should figure it out sometime...

//--------------------- GENERIC FACTORY FUNCTIONS -----------------------

/**
    @ingroup grp_factory
    @brief  Create object of type D using new operator and upcast to B.
    @return Dynamically allocated derived class instance.

    When using this object factory framework, more often than not, client
    classes will need a factory function to create a concrete type.
    Usually, these factory functions all follow the same pattern. Thus,
    instead of each client supplying its own factory function, we define
    this template function that different class hierarchies can use. The
    sample code at the beginning of this file illustrates how these
    factory functions can be used.
*/
template<typename B, typename D>
B* create_object()
{
    typedef boost::is_base_of<B, D> is_base ;
    BOOST_STATIC_ASSERT(is_base::value) ;
    return new D ;
}

/**
    @ingroup grp_factory
    @brief  Create object of type D using new operator and upcast to B.
    @param  a1 First constructor argument.
    @return Dynamically allocated derived class instance.

    When using this object factory framework, more often than not, client
    classes will need a factory function to create a concrete type.
    Usually, these factory functions all follow the same pattern. Thus,
    instead of each client supplying its own factory function, we define
    this template function that different class hierarchies can use. The
    sample code at the beginning of this file illustrates how these
    factory functions can be used.
*/
template<typename B, typename D, typename A1>
B* create_object(A1 a1)
{
    typedef boost::is_base_of<B, D> is_base ;
    BOOST_STATIC_ASSERT(is_base::value) ;
    return new D(a1) ;
}

/**
    @ingroup grp_factory
    @brief  Create object of type D using new operator and upcast to B.
    @param  a1 First constructor argument.
    @param  a2 Second constructor argument.
    @return Dynamically allocated derived class instance.

    When using this object factory framework, more often than not, client
    classes will need a factory function to create a concrete type.
    Usually, these factory functions all follow the same pattern. Thus,
    instead of each client supplying its own factory function, we define
    this template function that different class hierarchies can use. The
    sample code at the beginning of this file illustrates how these
    factory functions can be used.
*/
template<typename B, typename D, typename A1, typename A2>
B* create_object(A1 a1, A2 a2)
{
    typedef boost::is_base_of<B, D> is_base ;
    BOOST_STATIC_ASSERT(is_base::value) ;
    return new D(a1, a2) ;
}

} // namespace minxlib

//----------------------------------------------------------------------

#endif // #ifndef MINXLIB_FACTORY_DOT_HH

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/keymap.cc.























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
134
135
136
137
138
139
/*
    @file  keymap.cc
    @brief Implementation of API defined in keymap.hh.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

//----------------------------- HEADERS --------------------------------

// minxlib
#include "keymap.hh"
#include "logging.hh"
#include "util.hh"

// Xlib
#include <X11/keysym.h>

// Standard C++
#include <iomanip>
#include <map>

//-------------------------- IMPLEMENTATION ----------------------------

namespace {

// Module logger
minxlib::logging logger ;

// Store names of user-defined key bindings in this map, which is
// indexed by combining modmask + keycode keystroke combinations.
std::map<uint32_t, std::string> kmap ;

// Which modifiers to consider, which ones to ignore...
uint32_t modmask = 0x00FF ; // default: consider all modifiers

// Combine keycode k and modifier mask m into a key for above map
uint32_t make_key(KeyCode k, unsigned int m)
{
    uint32_t lo = k & 0xFFFF ;
    uint32_t hi = m & modmask;
    return ((hi << 16) | lo) ;
}

} // anonymous namespace

//--------------------------- PUBLIC API -------------------------------

namespace minxlib {
namespace keymap  {

// Insert key binding name s into the keymap
void bind(KeyCode k, unsigned int m, const std::string& s)
{
    using std::hex ; using std::setw ; using std::setfill ;
    uint32_t i = make_key(k, m) ;
    logger.debug() << "inserting keybinding " << s << " [0x"
                   << hex << setw(4) << setfill('0') << m << " + 0x"
                   << hex << setw(4) << setfill('0') << static_cast<int>(k)
                   << "] at index 0x"<< setfill('0') << setw(8) << hex << i ;
    kmap[i] = s ;
}

// Retrieve key binding name from keymap
std::string get(KeyCode k, unsigned int m)
{
    using std::hex ; using std::setw ; using std::setfill ;
    uint32_t i = make_key(k, m) ;
    logger.debug() << "looking for keybinding for [0x"
                   << hex << setw(4) << setfill('0') << m << " + 0x"
                   << hex << setw(4) << setfill('0') << static_cast<int>(k)
                   << "] at index 0x"<< setfill('0') << setw(8) << hex << i ;
    return kmap.at(i) ; // throws std::out_of_range
}

// Set modmask so as to ignore any Lock modifiers
uint32_t ignore_lock_modifiers(XModifierKeymap* mod_kmap, Display* d)
{
    const KeySym locks[] = {
    #ifdef XK_MISCELLANY
        XK_Scroll_Lock, XK_Kana_Lock, XK_Num_Lock, XK_Caps_Lock, XK_Shift_Lock,
    #endif
    #ifdef XK_XKB_KEYS
        XK_ISO_Lock, XK_ISO_Level3_Lock, XK_ISO_Level5_Lock,
        XK_ISO_Group_Lock, XK_ISO_Next_Group_Lock, XK_ISO_Prev_Group_Lock,
        XK_ISO_First_Group_Lock, XK_ISO_Last_Group_Lock,
    #endif
    } ;
    const int n = sizeof(locks)/sizeof(locks[0]) ;

    uint32_t mask = 0U ;
    for(int i = 0; i < n; ++i)
        mask |= minxlib::modmask(locks[i], mod_kmap, d) ;
    ::modmask = (~mask & 0xFF) ;
    return ::modmask ;
}

void pythonize()
{
    logger = logging::get_logger("keymap") ;
}

} // namespace keymap
} // namespace minxlib

//----------------------------------------------------------------------

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/keymap.hh.

































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
/**
    @file  keymap.hh
    @brief Mapping keyboard events to names of user-defined key bindings.
    @defgroup grp_minxlib_keymap Key Bindings

    This file defines an API for keeping track of the names users have
    defined for their key bindings and to translate X keyboard events to
    those names.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MINXLIB_KEYMAP_DOT_HH
#define MINXLIB_KEYMAP_DOT_HH

//----------------------------- HEADERS --------------------------------

// Xlib
#include <X11/Xlib.h>

// Standard C++
#include <string>

// Standard C
#include <stdint.h>

//--------------------------- PUBLIC API -------------------------------

namespace minxlib {
namespace keymap  {

/**
    @ingroup grp_minxlib_keymap
    @brief  Record a user-defined key binding.
    @param  k The X keycode for the key binding.
    @param  m The modifier mask for the key binding.
    @param  s The name of the key binding.
    @return Nothing.

    An important feature of Minx is its support for key bindings. Users
    specify functions they want executed in response to particular
    keystrokes. For example, a user may want to launch a terminal window
    when s/he presses CTRL + ALT + T. This key combination may be
    specified as "C-A-T" or "A-C-T".

    Now, when the user presses CTRL + ALT + T, minxlib will have to
    translate that keystroke to whatever the user specified. That is, if
    s/he configured it as "C-A-T", then minxlib will have to return
    "C-A-T" in the key_press event; similarly, if the key binding was
    specified as "A-C-T", we will have to return "A-C-T".

    In order to perform the translation described above, we have to
    remember the string supplied to minxlib when the passive grabs are
    setup for the key bindings (see the implementations of
    minx.core.wm.wm.configure_x() and minxlib::window::grab_key() for
    the gory details of how key bindings are configured). Then, when we
    receive keyboard events from X, we will have to consult the key map
    to see if it has an entry corresponding to the pressed (or released)
    key and, if so, report the event as a key binding rather than a
    simple key press.

    This function inserts the user-defined key binding name
    corresponding to the given keycode and modifier mask into the key
    map data structure implemented by this module. It is meant to be
    used by minxlib::window::grab_key(), i.e., when Minx sets up passive
    grabs for all the user-defined (or default) key bindings.
*/
void bind(KeyCode k, unsigned int m, const std::string& s) ;

/**
    @ingroup grp_minxlib_keymap
    @brief  Return name of user-defined key binding.
    @param  k The X keycode for the key binding.
    @param  m The modifier mask for the key binding.
    @return Key binding, if any, for given keycode and modifier mask.

    To make key bindings work, Minx sets up passive keyboard grabs for
    the key combinations configured by end-users. Then, when we receive
    keyboard events from the X server, we check if the event's keycode
    and modifier mask correspond to one of the passive grabs that was
    setup earlier on and, if so, report that key binding's user-defined
    name as part of the keyboard event.

    Minx's Python core can then use the key binding name to trigger
    hooks for that keystroke and not worry about the other low-level
    details of the keyboard event.

    This function returns the name of the key binding corresponding to
    the supplied keycode and modifier mask. It is meant to be used by
    the minxlib::key_event_details constructor, i.e., when we're
    creating a minxlib::event for a keyboard event.

    If there is no key binding setup for the given keycode and modifier
    mask, this function will throw an std::out_of_range exception.
*/
std::string get(KeyCode k, unsigned int m) ;

/**
    @ingroup grp_minxlib_keymap
    @brief  Ignore lock modifiers in key events.
    @param  m X server's modifier keymap.
    @param  d X server's interface object.
    @return The mask for testing modifiers in key events.

    Lock modifiers mess up the translation from key events to key
    binding names. For example, let's say a user has configured Minx to
    respond to F1 and S-F1. Let's also say that this user's X modifier
    map has NumLock setup as Mod2 and that the NumLock key is on.

    Now, when s/he presses F1 or SHIFT + F1, the resulting key event
    will have the Mod2 bit set in its modifier mask, i.e., to Minx, the
    key event will look like Mod2 + F1 or Mod2 + SHIFT + F1 rather than
    a plain F1 or SHIFT + F1. Consequently, when we combine the key
    event's keycode and modifier mask to index the internal map storing
    key bindings, we will get an index for a non-existent key binding,
    which, of course, means that, while NumLock is on, Minx will not
    recognize the F1 or SHIFT + F1 key bindings.

    The long and short of it is that a modifier key that acts as a lock
    (Caps Lock, Num Lock, Scroll Lock, etc.) will screw around with key
    events in such a way as to cause Minx's key binding mechanism to
    fail. Thus, we want to ignore any modifiers that are tied to such
    Lock keys.

    This function sets up an internal mask to do just that. It is meant
    to be called early on during Minx's initialization sequence. An
    ideal time to call it is after connecting to the X server but just
    before setting up the passive grabs that will make the key bindings
    mechanism work; that's why it's called from
    minxlib::window::grab_key().

    @note This function's return value is meant to be used for
    debugging. That is, it doesn't convey anything particularly useful
    to its caller; what we want is to see it in Minx's log so we can
    double-check using the xmodmap program that the key binding mapping
    will work correctly.
*/
uint32_t ignore_lock_modifiers(XModifierKeymap* m, Display* d) ;

/**
    @ingroup grp_minxlib_keymap
    @brief  Setup keymap module's logger.
    @return Nothing.

    The keymap module does not really have anything exposed to Minx's
    Python core via @boostpylink. However, we do use the Python-based
    logging infrastructure. That's why we need this "pythonization"
    function, which is meant to be called by the Boost.Python
    initialization code in python.cc.
*/
void pythonize() ;

} // namespace keymap
} // namespace minxlib

//----------------------------------------------------------------------

#endif // #ifndef MINXLIB_KEYMAP_DOT_HH

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/logging.cc.





































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
    @file  logging.cc
    @brief Implementation of API defined in logging.hh.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

//----------------------------- HEADERS --------------------------------

// minxlib
#include "logging.hh"

//-------------------------- INITIALIZATION ----------------------------

namespace minxlib {

// Default constructor (only used to allow global instances in client
// modules prior to Python module initialization).
logging::logging(){}

// "Main" constructor for initializing logger objects in client modules
logging::logging(const py::object& logger)
    : m_logger(logger),
      m_log_function(m_logger.attr("log"))
{}

// The log levels supported by the Python logging module
py::object DEBUG;
py::object INFO ;
py::object WARNING ;
py::object ERROR;
py::object CRITICAL;

// Initialize a client class's logger object (meant to be called in the
// class's Pythonize function).
logging logging::get_logger(const std::string& class_name)
{
    static bool log_levels_initialized = false ;

    py::object module = py::import ("logging") ;
    py::object create = module.attr("getLogger") ;

    // Individual logger objects for different modules are, obviously,
    // different logger instances. However, all of them share the same
    // logging levels. Instead of creating per-logger-object instances
    // of the log level objects, we initialize those objects just once.
    if (!log_levels_initialized) {
        DEBUG    = module.attr("DEBUG");
        INFO     = module.attr("INFO") ;
        WARNING  = module.attr("WARNING") ;
        ERROR    = module.attr("ERROR");
        CRITICAL = module.attr("CRITICAL");
        log_levels_initialized = true;
    }

    return logging(create(std::string("minx.minxlib.") + class_name)) ;
}

//----------------------- LOGGING INTERFACE ----------------------------

// Create a log object to write log messages at the specified level
// using the supplied logger object's logging function.
logging::log::log(py::object& log_function, py::object& log_level)
    : m_log(log_function),
      m_lvl(log_level)
{}

// Copy constructor to work around private std::ostringstream copy
// constructor.
logging::log::log(const logging::log& g)
    : m_log(g.m_log),
      m_lvl(g.m_lvl),
      m_msg(g.m_msg.str())
{}

// When temporary log object goes out of scope, write the log message
// collected via chained stream output operators to the Minx log via
// Python's standard logging module.
logging::log::~log()
{
    m_log(m_lvl, m_msg.str().c_str()) ;
}

// Public functions for emitting log messages at different levels
logging::log logging::debug()
{
    return log(m_log_function, DEBUG) ;
}

logging::log logging::info()
{
    return log(m_log_function, INFO) ;
}

logging::log logging::warning()
{
    return log(m_log_function, WARNING) ;
}

logging::log logging::error()
{
    return log(m_log_function, ERROR) ;
}

logging::log logging::critical()
{
    return log(m_log_function, CRITICAL) ;
}

} // namespace minxlib

//----------------------------------------------------------------------

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/logging.hh.



























































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
/**
    @file  logging.hh
    @brief Interface to Python's logging API.

    Since minxlib is basically a Python extension module, it makes sense
    to use Python's standard logging module so that log messages from
    minxlib can be integrated with the log messages output by Minx's
    Python parts.

    This file defines an API that the rest of minxlib can use to emit
    log messages.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MINXLIB_LOGGING_DOT_HH
#define MINXLIB_LOGGING_DOT_HH

//----------------------------- HEADERS --------------------------------

// minxlib
#include "python.hh"

// Standard C++
#include <sstream>
#include <string>

//------------------------- CLASS DEFINITION ---------------------------

namespace minxlib {

/**
    @brief Interface for logging via Python.

    This class provides an API for the remaining minxlib classes to emit
    log messages via Python's standard logging module. This stratgey
    allows minxlib's log messages to be integrated with the log messages
    output by the rest of Minx and avoid implementing a custom logging
    facility within minxlib.

    Additionally, leveraging Python's existing logging functionality
    ensures that end-users can configure Minx's logging support in a
    uniform way. That is, end-users don't have to be aware of the fact
    that minxlib is actually written in C++; to them, all of Minx is a
    collection of Python modules and classes whose logging support works
    the same.

    This class does not have a Python interface. It is meant to be used
    only within minxlib. The following snippet of code illustrates the
    typical and intended usage pattern:

    @code
        namespace minxlib {

        // Global logger object for some minxlib class
        static logging logger ;

        void some_class::pythonize()
        {
            // After exporting some_class to Python via Boost.Python:
            logger = logging::get_logger("some_class") ;
        }

        void some_class::some_func()
        {
            int i = 5 ;
            logger.debug() << "the value of i is " << i ;
            logger.info () << "this is an informational message" ;
            if (something_horrible_has_happened)
                logger.critical() << "all hell just broke loose!" ;
        }

        } // namespace minxlib
    @endcode
*/
class logging {
    // The Python logger object that this class encapsulates
    py::object m_logger ;

    // The logger object's log function, which we use to emit log
    // messages.
    py::object m_log_function ;

public:
    /**
        @brief  Default constructor.
        @return Nothing really.

        This logging API is meant to be used in the following manner:
        each minxlib class that needs to emit log messages should define
        a static global <tt>logger</tt> object in its <em>.cc</em> file
        and initialize the object in its Pythonize function by calling
        this class's get_logger() method. The client class can then use
        the <tt>logger</tt> object to emit log messages at different
        levels.

        The default constructor allows "empty" logger objects to be
        created at global scope within a <em>.cc</em> file. It has no
        other purpose. Therefore, this constructor is not (and should
        not be) used in any other situation.
    */
    logging() ;

    /**
        @brief  Create a logger object for the specified class.
        @param  name minxlib class for which we want a logger.
        @return A logger object for the specified class.

        This function returns a logger object that can be used by the
        named class to send log messages to the Minx log. It is meant to
        be called by the Pythonize functions of the various minxlib
        modules that send log messages to the Minx log. The <em>.cc</em>
        files for these modules should define a static global
        <tt>logger</tt> object that is initialized by calling this
        function in the Pythonize function of the above-mentioned
        classes.

        See the sample code in the class description for intended usage
        pattern.
    */
    static logging get_logger(const std::string& name) ;

private:
    /**
        @brief  Construct logger object.
        @param  logger The Python logger object.
        @return Properly constructed logger for named class.

        The get_logger() method uses this constructor to return logger
        objects to clients. It is responsible for importing the Python
        logging module and calling <tt>logging.getLogger()</tt> to
        obtain the desired logger object. get_logger() should then pass
        that Python logger object to this constructor so we can store it
        for later use.
    */
    logging(const py::object& logger) ;

    /**
        @brief Interface for emitting log messages.

        This inner class implements a stream output operator so minxlib
        classes can send log messages to the Minx log via Python. It is
        private to the logging class to ensure that it can only be
        created via the appropriate logging functions that are in the
        logging class's public interface.
    */
    class log {
        // Reference to the outer class's logger object's logging
        // function.
        py::object& m_log ;

        // Reference to the log level Python object (has to be provided
        // by the outer class's public logging methods).
        py::object& m_lvl ;

        // We will collect the output of chained stream operator
        // applications in this string stream and then write it out to
        // the Minx log via the above logging function.
        std::ostringstream m_msg ;

    public:
        /**
            @brief  Create a log object for the specified level.
            @param  f Reference to Python logger object's log function.
            @param  v Reference to Python logging module's level constant.
            @return Properly constructed log object for use by C++ classes.

            This class is meant to be instantiated by logging::debug(),
            logging::info(), logging::warning(), logging::error(), and
            logging::critical(). These functions should supply the outer
            class's reference to the Python logger object's log method
            and the appropriate log level from the Python logging
            module.
        */
        log(py::object& f, py::object& v) ;

        /**
            @brief  Copy constructor.
            @param  g The source log object that we want to copy.
            @return Copy of g.

            std::ostringstream (and, in fact, any STL stream) cannot be
            copied. Therefore, we need this copy constructor to be able
            to work around that. When logging::info(), logging::debug(),
            etc. instantiate this class and then return the resulting
            object, this copy constructor will be invoked and it will
            take care of copying the internal std::ostringstream from g
            to the instance being returned by the logging functions.

            @note Without this explicit copy constructor, the compiler
            will generate a default copy constructor for this class,
            which will perform a memberwise copy. However, since the
            copy constructors of the STL stream classes are private, we
            will then end up with a compiler error.
        */
        log(const log& g) ;

        /**
            @brief  Generic stream operator.
            @param  t The object to be output.
            @return Reference to this log object to allow chaining.

            To create log entries, clients should instantiate the
            logging::log class (using the logging::warning(),
            logging::debug(), etc. functions) and "build" the full
            message by chaining multiple calls to this operator. When
            the (usually temporary) log object goes out of scope, its
            destructor will emit the message via the Python logging
            module.
        */
        template<typename T> log& operator<<(const T& t) {
            m_msg << t ;
            return *this ;
        }

        /**
            @brief Conversion operator.
            @return The internal std::ostringstream object.

            This function converts logging::log objects to
            std::ostringstream, which allows clients to simply reuse
            their std::ostream output operators and not have to provide
            an overload for use with logging::log.
        */
        operator std::ostringstream&() {return m_msg ;}

        /**
            @brief Write message to Minx log via Python.

            As mentioned earlier, this class is meant to be used as a
            temporary. When that temporary object goes out of scope, we
            will write the log message collected in the internal
            std::ostringstream using the Python logging module.
        */
        ~log() ;
    } ; // class log

public:
    /**
        @brief  Write debug messages to Minx log.
        @return A log object whose stream operator will emit a log message.

        This function returns an object that you can use to emit debug
        messages with the stream output operator. Here is some sample
        code that shows how the object returned by this function is
        meant to be used:

        @code
            logger.debug() << "value of x = " << x ;
        @endcode

        In the above snippet, <tt>logger</tt> will usually be a static
        global variable within the client class's <em>.cc</em> file and
        it would have been initialized in the client class's Pythonize
        function. The sample code in the class description shows more
        details.

        @note The object returned by this function is an instance of a
        private inner class defined inside the logging class. Therefore,
        you cannot store the returned object in a local variable. The
        only thing you can do with it is use the stream output operator
        as shown above. This ensures that the inner class that takes
        care of the details of logging can only be used as a temporary
        so that, when it goes out of scope, its destructor can write the
        debug message to the Minx log via Python's logging module.
    */
    log debug() ;

    /**
        @brief  Write informational messages to Minx log.
        @return A log object whose stream operator will emit a log message.

        This function returns an object that you can use to emit
        informational messages with the stream output operator. The
        usage pattern is the same as described for the debug() function.
    */
    log info() ;

    /**
        @brief  Write warnings to Minx log.
        @return A log object whose stream operator will emit a log message.

        This function returns an object that you can use to emit
        warnings with the stream output operator. The usage pattern is
        the same as described for the debug() function.
    */
    log warning() ;

    /**
        @brief  Write errors to Minx log.
        @return A log object whose stream operator will emit a log message.

        This function returns an object that you can use to emit errors
        with the stream output operator. The usage pattern is the same
        as described for the debug() function.
    */
    log error() ;

    /**
        @brief  Write critical errors to Minx log.
        @return A log object whose stream operator will emit a log message.

        This function returns an object that you can use to emit
        messages about critical errors with the stream output operator.
        The usage pattern is the same as described for the debug()
        function.
    */
    log critical() ;
} ; // class logging

} // namespace minxlib

//----------------------------------------------------------------------

#endif // #ifndef MINXLIB_LOGGING_DOT_HH

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/python.cc.

























































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
    \file  python.cc
    \brief Exporting minxlib to Python.

    This file takes care of the details of exposing minxlib's C++
    functionality as a Python module so it can be used by the rest of
    Minx, which is implemented in Python.

    DEVNOTE: Minx is implemented mostly in Python. minxlib is a custom
    interface to Xlib on which the rest of Minx relies. We decided not
    to use python-xlib because that package is poorly documented whereas
    the C interface to Xlib has enough documentation to enable us to
    write minxlib.

    Another benefit of minxlib is that it serves as an abstraction for
    interfacing with a display server. Thus, when things like Wayland
    become the method of choice for talking to the display server on
    Linux systems, the window management logic in Minx can remain
    unchanged. Instead, we would simply reimplement the display server
    interface provided by minxlib.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

//----------------------------- HEADERS --------------------------------

// minxlib
#include "display.hh"
#include "root_window.hh"
#include "window.hh"
#include "event.hh"
#include "exception.hh"
#include "keymap.hh"
#ifdef MINXLIB_HAS_VERSION_API
#include "version.hh"
#endif
#include "python.hh"

//------------------------ PYTHON INTERFACE ----------------------------

// Register Boost.Python converters to convert C++ objects to their
// Python equivalents and vice versa (so that things like std::vector
// become Python lists and vice versa).
static void register_converters()
{
    using namespace minxlib ;

    typedef std::vector<int> int_list ;
    py::to_python_converter<int_list, universal_converter<int_list> >() ;

    typedef std::vector<std::string> string_list ;
    py::to_python_converter<string_list, universal_converter<string_list> >() ;

    typedef std::vector<window> window_list ;
    py::to_python_converter<window_list,
                            universal_converter<window_list> >() ;

    typedef std::vector<root_window> root_window_list ;
    py::to_python_converter<root_window_list,
                            universal_converter<root_window_list> >() ;

    typedef std::map<std::string, std::string> window_properties ;
    py::to_python_converter<window_properties,
                            universal_converter<window_properties> >() ;
    iterable_converter().from_python<window_properties>() ;
}

// Standard Boost.Python idiom for exporting C++ classes and functions
// as part of a Python module. In this case, we expose the relevant
// parts of minxlib as a Python module named "minxlib".
//
// DEVNOTE: The order in which we call the initialization functions
// matters! For example, since root_window is derived from window, we
// must setup the window class's Python wrapper before root_window.
BOOST_PYTHON_MODULE(minxlib)
{
    register_converters() ;

    using namespace minxlib ;
    exception  ::pythonize();
    display    ::pythonize();
    window     ::pythonize();
    root_window::pythonize();
    event      ::pythonize();
    keymap     ::pythonize();
#ifdef MINXLIB_HAS_VERSION_API
    version    ::pythonize();
#endif
}

//----------------------------------------------------------------------

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/python.hh.

















































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
/*
    @file  python.hh
    @brief Useful stuff for using Boost.Python.

    This file defines some functions and classes that can be used to
    implement Boost.Python converters. It also suppresses spurious
    warnings that emanate from boost/python.hpp.

    @note This file is only used inside of minxlib. That's why it is not
    documented with Doxygen (this comment starts with a single asterisk
    rather than two). Of course, we do have explanatory comments, and we
    even use Doxygen mark-up; however, this does not show up in the Minx
    API docs.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MINXLIB_PYTHON_DOT_HH
#define MINXLIB_PYTHON_DOT_HH

//---------------------------- HEADERS ---------------------------------

/*
    minxlib is built with -Wextra, which, among other warnings, turns on
    the "enumeral and non-enumeral type in conditional expression"
    complaint when compiling boost/python.hpp.

    We use a pragma that makes the compiler treat this file as a system
    header, which suppresses the above-mentioned annoying and useless
    warning, thereby avoiding unnecessary clutter in the build log. All
    minxlib modules that need boost/python.hpp should instead include
    this file.

    DEVNOTE: Once g++ is able to compile boost/python.hpp without any
    warnings (either because the compiler gets it right or because Boost
    does), this pragma should become unnecessary.
*/
#ifdef __GNUC__
#pragma GCC system_header
#endif

// Now include the Boost header that causes the pain...
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>

// Other Boost headers
#include <boost/foreach.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/iterator_adaptors.hpp>

// Standard C++
#include <algorithm>
#include <map>
#include <vector>
#include <iterator>

//----------------------------- NAMESPACE -------------------------------

namespace minxlib {

// This namespace alias is used throughout minxlib. So, instead of
// repeating it in each .cc file, just put it here.
namespace py = boost::python ;

//----------------------------- TO PYTHON -------------------------------

/*
   Converters to turn C++ objects into their Python equivalents. More
   info at:

   General/Tutorial Explanation of Boost.Python Converters:
       http://misspent.wordpress.com/2009/09/27/how-to-write-boost-python-converters/

   Tuple Conversion:
       http://mail.python.org/pipermail/cplusplus-sig/2006-May/010324.html
*/
namespace {

// Base case for tuples::cons recursion when we want to convert from C++
// tuples to Python tuples.
py::tuple to_python(boost::tuples::null_type)
{
    return py::tuple() ;
}

// General function for converting Boost tuples to Python equivalents
// using the implicit conversion from a tuple to a cons "cell."
template<typename head, typename tail>
py::object to_python(const boost::tuples::cons<head, tail>& cons)
{
    return py::make_tuple(cons.get_head()) + to_python(cons.get_tail()) ;
}

// Generic function for converting an STL vector into a Python list
template<typename T>
py::object to_python(const std::vector<T>& v)
{
    py::list list ;
    BOOST_FOREACH(const T& t, v)
        list.append(t) ;
    return list ;
}

// Generic funtion for converting an STL map into a Python dict
template<typename K, typename V>
py::object to_python(const std::map<K, V>& m)
{
    typedef typename std::map<K, V>::value_type P ;
    py::dict dict ;
    BOOST_FOREACH(const P& p, m)
        dict[p.first] = p.second ;
    return dict ;
}

} // namespace

/*
    @brief Converter for turning C++ objects into their Python equivalents.

    This handy template is meant to be used in conjunction with
    boost::python::to_python_converter(). It relies on overloaded
    versions of a to_python() helper function to works its magic. That
    is, for each distinct type we want to convert, we will have to
    provide a suitable definition of to_python() that takes an instance
    of that type as a parameter and returns the Python equivalent.

    So far, this file defines versions of to_python() that perform the
    following conversions:

        @li STL vectors to Python lists
        @li STL maps to Python dicts
        @li Boost tuples to Python tuples

    Please see display::pythonize() and window::pythonize() for examples
    of how this converter is meant to be used.
*/
template<typename T>
struct universal_converter {
    static PyObject* convert(const T& t) {
        return py::incref(to_python(t).ptr()) ;
    }
} ;

//---------------------------- FROM PYTHON ------------------------------

/*
    @brief A key-value iterator for converting Python dicts to STL maps.

    Boost.Python's stl_input_iterator iterates over a Python container by
    using its __iter__ method. Unfortunately, for dicts, __iter__
    iterates only over the keys. Thus, trying to in-place construct an
    STL map (see the construct() function in the iterable_converter
    defined later in this file) doesn't work because an STL map stores
    key-value pairs. Consequently, when the iterable_converter
    dereferences a dict's iterator, we need to return an STL pair
    containing both the key and the corresponding value that can be
    inserted into the STL map being built from the Python dict.

    This class implements an adaptor for Boost.Python's
    stl_input_iterator to achieve the dereferencing effect described
    above.

    The type M is expected to be an std::map and it should be the same as
    the type C passed to iterable_converter::construct().
*/
template<typename M>
class stl_map_iterator: public boost::iterator_adaptor<
    stl_map_iterator<M>,       // standard boost::iterator_adaptor idiom
    py::stl_input_iterator<typename M::value_type::first_type>, // base iter.
    typename M::value_type,    // should be std::pair<key, value>
    std::forward_iterator_tag, // iterator category
    typename M::value_type>    // ref. type (make new pair, not ret. ref.)
{
    // When it is derefenced, the base iterator type, viz., the
    // Boost.Python stl_input_iterator that this class adapts, will
    // return a key belonging to its underlying Python dict. In order to
    // be able to convert that to a key-value pair, we need the
    // underlying Python container so we can look up the values
    // corresponding to keys.
    py::object m_dict ;

    // STL map's key and value types (they're basically std::pair objects)
    typedef typename M::value_type:: first_type key_type ;
    typedef typename M::value_type::second_type val_type ;

    // Handy shortcut for referring to the base iterator type that this
    // class is adapting.
    typedef py::stl_input_iterator<key_type> base_type ;

public:
    /**
        @brief  Iterator to the beginning of the underlying container.
        @param  d The Python dict we want to convert to an STL map.
        @param  i The Boost.Python stl_input_iterator for the STL map.
        @return Iterator to beginning of STL map being constructed from Py dict.

        This constructor uses the Boost.Python stl_input_iterator and its
        underlying Python dict to make a suitable iterator for the
        corresponding C++ map that we will build with the
        iterable_converter defined later in this file.
    */
    stl_map_iterator(const py::object& d, base_type& i) ;

    /**
        @brief  Iterator to end of STL map being built from Python dict.
        @return Iterator to end of STL map.

        This constructor builds the iterator returned by the end()
        function in C++ container classes, i.e., it is the iterator to
        one past the end of the map that will be made by the
        iterable_converter class from a Python dict.
    */
    stl_map_iterator() ;

private:
    // Move to next element in sequence (standard Boost iterator adaptor idiom)
    void increment() {++this->base_reference() ;}

    /**
        @brief  Return key-value pair for STL map from Python dict's key.
        @return Key-value pair corresponding to a key.

        As mentioned above, Boost.Python's stl_input_iterator, when
        applied to a dict, will return only a key. However, in the
        corresponding STL map, we want to insert a key-value pair. This
        function is where this map iterator works its magic...

        It first dereferences the base iterator (i.e., the
        stl_input_iterator it is adapting) to get the key from the Python
        dict. After that, it looks up that key in the Python dict to get
        the value corresponding to the key. Finally, it returns an STL
        pair combining the key and value.
    */
    typename M::value_type dereference() const ;

    // Standard Boost.Iterator idiom
    friend class boost::iterator_core_access ;
} ;

// Beginning of container
template<typename M>
stl_map_iterator<M>::stl_map_iterator(const py::object& d, base_type& i)
    : stl_map_iterator::iterator_adaptor_(i),
      m_dict(d)
{}

// End of container
template<typename M>
stl_map_iterator<M>::stl_map_iterator()
{}

// Convert key to key-value pair
template<typename M>
typename M::value_type stl_map_iterator<M>::dereference() const
{
    key_type key = *(this->base_reference()) ;
    val_type val = py::extract<val_type>(m_dict[key]) ;
    return std::make_pair(key, val) ;
}

/*
    @brief Convert Python iterable objects to their C++ equivalents.

    This class provides an API for registering a Boost.Python converter
    for converting Python lists, tuples, dicts, etc. to C++ equivalents.
    It is meant to be used when we want to expose a C++ function that
    takes a list, map, etc. to Python and want its Python interface to
    accept the Python equivalent.

    @note This code is lifted almost verbatim from the following Stack
    Overflow post:

        http://stackoverflow.com/questions/15842126/feeding-a-python-list-into-a-function-taking-in-a-vector-with-boost-python

    @par
    However, the support for converting Python dicts to STL maps is a
    Minx-specific enhancement.
*/
struct iterable_converter {
    /*
        @brief  Register a Boost.Python converter to convert to C++ type C.
        @return Ref. to this object to allow chaining calls to from_python().

        This function registers a Boost.Python converter that will
        produce a C++ object of type C given its Python equivalent.
        Typically, the Python object will be a list or a dict and the
        type C will be an STL container such as list or map.

        You should call this function as part of the Boost.Python module
        initialization sequence. In Minx, this would be in the
        pythonize() function of a class being exposed to Python. For
        example, if you have a C++ function that takes an STL list of
        integers and you want to expose it to Python so that it can
        accept a Python list of ints, in the corresponding pythonize()
        function you would do something like this:

        @code
            iterable_converter().from_python<std::list<int> >() ;
        @endcode

        Continuing the above example, if you have another function that
        takes an STL map of ints to strings, the pythonize() function
        would be as follows:

        @code
            iterable_converter().from_python<std::list<int> >().
                                 from_python<std::map <int, std::string> >() ;
        @endcode
    */
    template<typename C>
    iterable_converter& from_python() {
        py::converter::registry::push_back(&iterable_converter::convertible,
                                           &iterable_converter::construct<C>,
                                           py::type_id<C>()) ;
        return *this ;
    }

private:
    // Check if supplied Python object supports Python's iterator protocol
    static void* convertible(PyObject* obj) {
        return PyObject_GetIter(obj) ? obj : 0 ;
    }

    /*
        @brief  Convert Python iterable object into C++ type C.
        @param  obj The Python iterable object to be converted.
        @param  dat Raw memory area for in-place construction of C.
        @return C++ container C via parameter dat.

        This function performs the Boost.Python black magic that iterates
        over the Python container obj and constructs the requested C++
        container (type C). Typically, C will be an STL list, vector, or
        map.
    */
    template<typename C>
    static void construct(PyObject* obj,
                          py::converter::rvalue_from_python_stage1_data* dat)
    {
        // For in-place construction of C++ container in the raw memory
        // area provided by Boost.Python, we need to be able view the raw
        // bytes as an object of type C...
        typedef py::converter::rvalue_from_python_storage<C> storage_type ;
        void* storage = reinterpret_cast<storage_type*>(dat)->storage.bytes ;

        // Python ref-count book-keeping
        py::handle<> handle(py::borrowed(obj)) ;
        py::object iterable(handle) ;

        // Converting a Python dict to an STL map needs special handling
        // because Boost.Python doesn't seem to provide a ready-made
        // (key, value) iterator, which requires us to roll our own...
        if (PyDict_Check(obj))
        {
            typedef typename C::value_type::first_type key_type ;
            typedef py::stl_input_iterator<key_type> key_iterator ;
            typedef stl_map_iterator<C> iterator ;
            key_iterator begin = key_iterator(iterable) ;
            dat->convertible = new(storage) C(iterator(iterable, begin),
                                              iterator()) ;
        }
        else // Boost.Python takes care of flat lists and tuples without a hitch
        {
            typedef py::stl_input_iterator<typename C::value_type> iterator ;
            dat->convertible = new(storage) C(iterator(iterable),
                                              iterator()) ;
        }
    }
} ;

//-----------------------------------------------------------------------

} // namespace minxlib

#endif // #ifndef MINXLIB_PYTHON_DOT_HH

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/root_window.cc.































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
/*
    @file  root_window.cc
    @brief Implementation of API defined in root_window.hh.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

//----------------------------- HEADERS --------------------------------

// minxlib
#include "root_window.hh"
#include "logging.hh"
#include "python.hh"

// Xlib
#include <X11/Xlib.h>

// Standard C++
#include <sstream>
#include <algorithm>
#include <iterator>

//-------------------------- INITIALIZATION ----------------------------

namespace minxlib {

static logging logger ;

// Quick helper to dump geometry to Minx log
static void dump_geometry(const std::vector<int>& geom, Window id, int screen)
{
    std::ostringstream str ;
    std::copy(geom.begin(), geom.end(), std::ostream_iterator<int>(str, " ")) ;
    logger.debug() << "screen " <<  screen  << "'s root window (" << id
                   << ") geometry = [" << str.str() << ']' ;
}

// Root window constructor when not using Xinerama
root_window::root_window(Display* d, int s)
    : window(d, RootWindow(d, s)),
      m_screen(s),
      m_geom(window::geometry())
{
    dump_geometry(m_geom, m_id, m_screen) ;
}

#ifdef MINXLIB_HAS_XINERAMA
// Root window constructor when using Xinerama
root_window::root_window(Display* d, int s, const XineramaScreenInfo& i)
    : window(d, RootWindow(d, 0)),
      m_screen(s)
{
    logger.info() << "setting screen " << s
                  << "'s root window ("<< m_id
                  << ") geometry from Xinerama";

    m_geom.reserve(5) ;
    m_geom.push_back(i.x_org) ;
    m_geom.push_back(i.y_org) ;
    m_geom.push_back(i.width) ;
    m_geom.push_back(i.height);
    m_geom.push_back(0) ;

    dump_geometry(m_geom, m_id, m_screen) ;
}
#endif // MINXLIB_HAS_XINERAMA

//--------------------------- PROPERTIES ------------------------------

void root_window::set_properties(const std::map<std::string, std::string>&)
{
    logger.warning() << "attempting to set properties on screen "
                     << m_screen << "'s root window " << m_id ;
}

//-------------------- PARENT-CHILD RELATIONSHIPS -----------------------

void root_window::reparent(const window&)
{
    logger.warning() << "attempting to reparent screen " << m_screen
                     << "'s root window " << m_id ;
}

window root_window::parent()
{
    logger.warning() << "attempting to get parent of screen " << m_screen
                     << "'s root window " << m_id ;
    return window(m_display, 0) ;
}

int root_window::screen()
{
    return m_screen ;
}

//----------------------- WINDOW VISIBILITY ----------------------------

void root_window::show()
{
    logger.warning() << "attempting to show screen " << m_screen
                     << "'s root window " << m_id ;
}

void root_window::hide()
{
    logger.warning() << "attempting to hide screen " << m_screen
                     << "'s root window " << m_id ;
}

bool root_window::is_mapped()
{
    return true ;
}

//------------------------ WINDOW GEOMETRY -----------------------------

void root_window::move_resize(int, int, int, int)
{
    logger.warning() << "attempting to move/resize screen " << m_screen
                     << "'s root window " << m_id ;
}

void
root_window::
configure(int, int, int, int, int, const window*, int, unsigned int)
{
    logger.warning() << "attempting to configure screen " << m_screen
                     << "'s root window " << m_id ;
}

void root_window::set_border_attr(unsigned long, unsigned int)
{
    logger.warning() << "attempting to set border attributes on screen "
                     << m_screen << "'s root window " << m_id ;
}

std::vector<int> root_window::geometry()
{
    return m_geom ;
}

//---------------------------- INPUT FOCUS ------------------------------

void root_window::focus()
{
    logger.warning() << "attempting to focus screen " << m_screen
                     << "'s root window " << m_id ;
}

//----------------------- WINDOW DESTRUCTION ---------------------------

void root_window::kill()
{
    logger.warning() << "attempting to kill screen " << m_screen
                     << "'s root window " << m_id ;
}

void root_window::nuke()
{
    logger.warning() << "attempting to nuke screen " << m_screen
                     << "'s root window " << m_id ;
}

//------------------------ PYTHON INTERFACE ----------------------------

void root_window::pythonize()
{
    py::class_<root_window, py::bases<window> >("root_window", py::no_init).
        def("set_properties",   &root_window::set_properties ).
        def("reparent",         &root_window::reparent       ).
        def("parent",           &root_window::parent         ).
        def("screen",           &root_window::screen         ).
        def("show",             &root_window::show           ).
        def("hide",             &root_window::hide           ).
        def("is_mapped",        &root_window::is_mapped      ).
        def("move_resize",      &root_window::move_resize    ).
        def("configure",        &root_window::configure      ).
        def("set_border_attr",  &root_window::set_border_attr).
        def("geometry",         &root_window::geometry       ).
        def("focus",            &root_window::focus          ).
        def("kill",             &root_window::kill           ).
        def("nuke",             &root_window::nuke           );

    logger = logging::get_logger("root_window") ;
}

} // namespace minxlib

//----------------------------------------------------------------------

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/root_window.hh.











































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
/**
    @file  root_window.hh
    @brief Encapsulation of an X root window.

    This file defines a class that wraps around the notion of an X
    root window and provides a Python interface for the rest of Minx.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MINXLIB_ROOT_WINDOW_DOT_HH
#define MINXLIB_ROOT_WINDOW_DOT_HH

//----------------------------- HEADERS --------------------------------

// Minx
#include "window.hh"

// Xlib
#ifdef MINXLIB_HAS_XINERAMA
#include <X11/extensions/Xinerama.h>
#endif

// Standard C++
#include <vector>

//------------------------- CLASS DEFINITION ---------------------------

namespace minxlib {

/**
    @brief Encapsulate the details of an X root window.

    This class provides an API for the Python parts of Minx to be able to
    deal with X root windows. It wraps around the relevant parts of Xlib
    and exposes its functionality to Python via @boostpylink.

    Although we could just represent a root window as just another
    minxlib::window, we have a dedicated subclass for root windows to be
    able to deal with Xinerama. When Xinerama is active, a multi-head
    setup will have just one root window. However, to make Minx's layout
    functionality work properly across multiple physical monitors,
    minxlib always presents as many root windows as there are physical
    monitors. With Xinerama, these root windows will have the same window
    ID, but will have different geometries.
*/
class root_window: public window {
    // When we create a root window, we specify which screen it is on.
    int m_screen ;

    // Root windows have fixed geometry.
    std::vector<int> m_geom ;

public:
    /**
        @brief  Create a wrapper object for a root window.
        @param  d The display object to which the window is "linked."
        @param  s The zero-based screen index whose root window we want.
        @return A valid wrapper object for the specified screen's root window.

        This constructor is meant to be used when Xinerama is not active.
        In multi-head setups without Xinerama, the X server will be
        configured with independent displays.
    */
    root_window(Display* d, int s) ;

#ifdef MINXLIB_HAS_XINERAMA
    /**
        @brief  Create a wrapper object for a root window with Xinerama active.
        @param  d The display object to which the window is "linked."
        @param  s The zero-based screen index whose root window we want.
        @param  i The Xinerama screen info structure for the specified screen.
        @return A valid wrapper object for the specified screen's root window.

        This constructor is meant to be used when Xinerama is active. It
        is the caller's responsibility to obtain the XineramaScreenInfo
        structures by calling XineramaQueryScreens() and then freeing
        them once all the necessary root window objects have been
        created.
    */
    root_window(Display* d, int s, const XineramaScreenInfo& i) ;
#endif

    /**
        @brief  Export the window class to minxlib Python module.
        @return Nothing.

        This function exposes the root window class's interface so that
        it can be used by the Python parts of Minx. It is meant to be
        called by the Boost.Python initialization code in python.cc.
    */
    static void pythonize() ;

    /**
        @brief  Set window properties.
        @param  prop An STL map of strings to strings.
        @return Nothing.

        This is an override of minxlib::window::set_properties(). minxlib
        does not allow root window properties to be set. Thus, this
        implementation simply logs a warning to the Minx log and does
        nothing else.
    */
    void set_properties(const std::map<std::string, std::string>& prop) ;

    /**
        @brief  Reparent this window to another.
        @param  p New parent window.
        @return Nothing.

        This is an override of minxlib::window::reparent(). minxlib does
        not allow root windows to be reparented. Thus, this
        implementation simply logs a warning to the Minx log and does
        nothing else.
    */
    void reparent(const window& p) ;

    /**
        @brief  Get this root window's parent window.
        @return Window with ID zero.

        This is an override of minxlib::window::parent(). minxlib does
        not allow querying root windows for their parents. Thus, this
        implementation simply logs a warning to the Minx log and returns
        a window object with ID zero.
    */
    window parent() ;

    /**
        @brief  Get screen number of this root window.
        @return Root window's screen number.

        This function simply returns the screen index used when this root
        window object was created.
    */
    int screen() ;

    /**
        @brief  Show the window, i.e., map it.
        @return Nothing.

        This is an override of minxlib::window::show(). Since root
        windows are always visible, this function simply logs a warning
        to the Minx log.
    */
    void show() ;

    /**
        @brief  Hide this window, i.e., unmap it.
        @return Nothing.

        This is an override of minxlib::window::hide(). Since root
        windows are always visible and cannot be unmapped, this function
        simply logs a warning to the Minx log.
    */
    void hide() ;

    /**
        @brief  Check if root window is currently mapped or not.
        @return True (root windows are always mapped).
    */
    bool is_mapped() ;

    /**
        @brief  Move and resize the window.
        @param  x Window's x coordinate relative to parent's origin.
        @param  y Window's y coordinate relative to parent's origin.
        @param  w Window's width (not counting its border).
        @param  h Window's height (not counting its border).
        @return Nothing.

        This is an override of minxlib::window::move_resize(). minxlib
        does not allow root windows to be moved and/or resized. Thus,
        this implementation simply logs a warning to the Minx log and
        does nothing else.
    */
    void move_resize(int x, int y, int w, int h) ;

    /**
        @brief  Configure the window.
        @param  x Window's x coordinate relative to parent's origin.
        @param  y Window's y coordinate relative to parent's origin.
        @param  w Window's width (not counting its border).
        @param  h Window's height (not counting its border).
        @param  b Window's border width.
        @param  s Window's sibling for stacking operations.
        @param  t Window's stacking mode.
        @param  v Value mask to determine what to configure.
        @return Nothing.

        This is an override of minxlib::window::configure(). minxlib does
        not allow root windows to be configured. Thus, this
        implementation simply logs a warning to the Minx log and does
        nothing else.
    */
    void configure(int x, int y, int w, int h, int b,
                   const window* s, int t, unsigned int v) ;

    /**
        @brief  Set window's border color and size.
        @param  c Three-byte RGB spec.
        @param  s Border size (in pixels).
        @return Nothing.

        This is an override of minxlib::window::set_border_attr().
        minxlib does not allow root window borders to be changed. Thus,
        this implementation simply logs a warning to the Minx log and
        does nothing else.
    */
    void set_border_attr(unsigned long c, unsigned int s) ;

    /**
        @brief  Retrieve window's size, position, and border width.
        @return STL vector of ints containing window geometry.

        Root windows have a fixed geometry. When a root window object is
        constructed, we determine its geometry and store that in a data
        member. This function simply returns the above-mentioned data
        member, which is an STL vector of integers containing the
        following five values:

            @li Element 0: x-coordinate of root window's top-left corner
            @li Element 1: y-coordinate of root window's top-left corner
            @li Element 2: root window width
            @li Element 3: root window height
            @li Element 4: root window's border width (always zero)

        @note For non-Xinerama setups, this function simply calls
        minxlib::window::geometry(), which, in turn, calls
        XGetGeometry(). If the call to XGetGeometry() fails, this
        function will return an empty vector (and, eventually, the X
        server will raise a protocol error).

        @par
        On the Python side, the STL vector returned by this function
        will be converted into a Python list.
    */
    std::vector<int> geometry() ;

    /**
        @brief  Set input focus on this root window and raise it.
        @return Nothing.

        This is an override of minxlib::window::focus(). minxlib does not
        allow root windows to be focused. Thus, this implementation
        simply logs a warning to the Minx log and does nothing else.
    */
    void focus() ;

    /**
        @brief  Kill this window.
        @return Nothing.

        This is an override of minxlib::window::kill(). minxlib does not
        allow root windows to be killed. Thus, this implementation simply
        logs a warning to the Minx log and does nothing else.
    */
    void kill() ;

    /**
        @brief  Kill this window using brute force.
        @return Nothing.

        This is an override of minxlib::window::nuke(). minxlib does not
        allow root windows to be killed. Thus, this implementation simply
        logs a warning to the Minx log and does nothing else.
    */
    void nuke() ;
} ; // class window

} // namespace minxlib

//----------------------------------------------------------------------

#endif // #ifndef MINXLIB_ROOT_WINDOW_DOT_HH

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/type_info.cc.













































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
/*
    \file  type_info.cc
    \brief Non-inline functions of minxlib::type_info.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

//----------------------------- HEADERS --------------------------------

// minxlib
#include "type_info.hh"

//-------------------------- INITIALIZATION -----------------------------

namespace minxlib {

// Default constructor
type_info::type_info()
{
    class empty {} ;
    m_type_info = &typeid(empty) ;
}

// Convert std::type_info to wrapped type_info
type_info::type_info(const std::type_info& t)
    : m_type_info(&t)
{}

// Stream output operator for use with boost::lexical_cast
std::ostream& operator<<(std::ostream& os, const type_info& t)
{
    return os << t.m_type_info->name() ;
}

} // namespace minxlib

//----------------------------------------------------------------------

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/type_info.hh.

























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/**
    @file  type_info.hh
    @brief Wrapper around std::type_info.

    As pointed out by Andrei Alexandrescu in "Modern C++ Design," using
    std::type_info::name() to uniquely and reliably identify different
    classes is usually a bad idea. Instead, we use the wrapper around
    std::type_info defined in this file.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MINXLIB_TYPE_INFO_DOT_HH
#define MINXLIB_TYPE_INFO_DOT_HH

//----------------------------- HEADERS --------------------------------

// Standard C++
#include <typeinfo>
#include <ostream>

//------------------------- CLASS DEFINITION ----------------------------

namespace minxlib {

/**
    @brief Wrapper around std::type_info.

    Because std::type_info::name() is unreliable, we can use this wrapper
    class when we want to identify different classes in a unique way so
    as to be able to use class typeid's in conjunction with object
    factories and other such constructions.

    The only thing you can do with minxlib::type_info objects are create
    them and compare them using the relational operators (i.e., ==, !=,
    <, >, <=, and >=).
*/
class type_info {
    // Can't copy std::type_info, but can store it via a pointer. See
    // chapter two of "Modern C++ Design" by Andrei Alexandrescu.
    const std::type_info* m_type_info ;

public:
    /**
        @brief  Default constructor for std::type_info wrapper.
        @return std::type_info wrapper object.

        A default constructor so we can store type_info wrapper objects
        in STL containers.
    */
    type_info() ;

    /**
        @brief  Construct type_info wrapper given std::type_info.
        @param  t Result of typeid operator on some object or type.
        @return std::type_info wrapper object.
    */
    type_info(const std::type_info& t) ;

    // Some operators need access to the wrapper object's innards
    friend bool operator==(const type_info&, const type_info&) ;
    friend bool operator< (const type_info&, const type_info&) ;
    friend std::ostream& operator<<(std::ostream&, const type_info&) ;
} ;

//------------------------- INLINE FUNCTIONS ----------------------------

/**
    @brief  Check if two type_info objects are equal.
    @param  a LHS of equality operator.
    @param  b RHS of equality operator.
    @return True if a == b, false otherwise.
*/
inline bool operator==(const type_info& a, const type_info& b)
{
    return *(a.m_type_info) == *(b.m_type_info) ;
}

/**
    @brief  Check if two type_info objects are not equal.
    @param  a LHS of inequality operator.
    @param  b RHS of inequality operator.
    @return True if a != b, false if a == b.
*/
inline bool operator!=(const type_info& a, const type_info& b)
{
    return !(a == b) ;
}

/**
    @brief  Check if one type_info object less than another.
    @param  a LHS of < operator.
    @param  b RHS of < operator.
    @return True if a < b, false if a >= b.
*/
inline bool operator< (const type_info& a, const type_info& b)
{
    return a.m_type_info->before(*(b.m_type_info)) ;
}

/**
    @brief  Check if one type_info object greater than another.
    @param  a LHS of > operator.
    @param  b RHS of > operator.
    @return True if a > b, false if a <= b.
*/
inline bool operator> (const type_info& a, const type_info& b)
{
    return b < a ;
}

/**
    @brief  Check if one type_info object less than or equal to another.
    @param  a LHS of <= operator.
    @param  b RHS of <= operator.
    @return True if a <= b, false if a > b.
*/
inline bool operator<=(const type_info& a, const type_info& b)
{
    return !(a > b) ;
}

/**
    @brief  Check if one type_info object greater than or equal to another.
    @param  a LHS of >= operator.
    @param  b RHS of >= operator.
    @return True if a >= b, false if a < b.
*/
inline bool operator>=(const type_info& a, const type_info& b)
{
    return !(a < b) ;
}
///@}

} // namespace minxlib

//----------------------------------------------------------------------

#endif // #ifndef MINXLIB_TYPE_INFO_DOT_HH

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/util.cc.





























































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
/*
    \file  util.cc
    \brief Implementation of API defined in util.hh.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

//----------------------------- HEADERS --------------------------------

// minxlib
#include "util.hh"

// Xlib
#include <X11/Xproto.h>

// Standard C++
#include <sstream>
#include <algorithm>

//----------------------- Xlib ERROR PRINTING --------------------------

namespace minxlib {

// Helper macro to simplify switch-case construct in to_str() function.
// Takes the symbolic names for error codes and converts them to
// equivalent strings.
#define STRINGIZE_CASE_LABEL(e, s) case e: s << #e ; break ;

// Return a string representation of X protocol errors
std::string to_str(const XErrorEvent* e)
{
    std::ostringstream str ;
    str << "X protocol error [" ;
    switch (e->error_code)
    {
        STRINGIZE_CASE_LABEL(BadAccess, str) ;
        STRINGIZE_CASE_LABEL(BadAlloc, str) ;
        STRINGIZE_CASE_LABEL(BadAtom, str) ;
        STRINGIZE_CASE_LABEL(BadColor, str) ;
        STRINGIZE_CASE_LABEL(BadCursor, str) ;
        STRINGIZE_CASE_LABEL(BadDrawable, str) ;
        STRINGIZE_CASE_LABEL(BadFont, str) ;
        STRINGIZE_CASE_LABEL(BadGC, str) ;
        STRINGIZE_CASE_LABEL(BadIDChoice, str) ;
        STRINGIZE_CASE_LABEL(BadImplementation, str) ;
        STRINGIZE_CASE_LABEL(BadLength, str) ;
        STRINGIZE_CASE_LABEL(BadMatch, str) ;
        STRINGIZE_CASE_LABEL(BadName, str) ;
        STRINGIZE_CASE_LABEL(BadPixmap, str) ;
        STRINGIZE_CASE_LABEL(BadRequest, str) ;
        STRINGIZE_CASE_LABEL(BadValue, str) ;
        STRINGIZE_CASE_LABEL(BadWindow, str) ;
    }
    str << ' ' ;
    switch (e->request_code)
    {
        STRINGIZE_CASE_LABEL(X_CreateWindow, str) ;
        STRINGIZE_CASE_LABEL(X_ChangeWindowAttributes, str) ;
        STRINGIZE_CASE_LABEL(X_GetWindowAttributes, str) ;
        STRINGIZE_CASE_LABEL(X_DestroyWindow, str) ;
        STRINGIZE_CASE_LABEL(X_DestroySubwindows, str) ;
        STRINGIZE_CASE_LABEL(X_ChangeSaveSet, str) ;
        STRINGIZE_CASE_LABEL(X_ReparentWindow, str) ;
        STRINGIZE_CASE_LABEL(X_MapWindow, str) ;
        STRINGIZE_CASE_LABEL(X_MapSubwindows, str) ;
        STRINGIZE_CASE_LABEL(X_UnmapWindow, str) ;
        STRINGIZE_CASE_LABEL(X_UnmapSubwindows, str) ;
        STRINGIZE_CASE_LABEL(X_ConfigureWindow, str) ;
        STRINGIZE_CASE_LABEL(X_CirculateWindow, str) ;
        STRINGIZE_CASE_LABEL(X_GetGeometry, str) ;
        STRINGIZE_CASE_LABEL(X_QueryTree, str) ;
        STRINGIZE_CASE_LABEL(X_InternAtom, str) ;
        STRINGIZE_CASE_LABEL(X_GetAtomName, str) ;
        STRINGIZE_CASE_LABEL(X_ChangeProperty, str) ;
        STRINGIZE_CASE_LABEL(X_DeleteProperty, str) ;
        STRINGIZE_CASE_LABEL(X_GetProperty, str) ;
        STRINGIZE_CASE_LABEL(X_ListProperties, str) ;
        STRINGIZE_CASE_LABEL(X_SetSelectionOwner, str) ;
        STRINGIZE_CASE_LABEL(X_GetSelectionOwner, str) ;
        STRINGIZE_CASE_LABEL(X_ConvertSelection, str) ;
        STRINGIZE_CASE_LABEL(X_SendEvent, str) ;
        STRINGIZE_CASE_LABEL(X_GrabPointer, str) ;
        STRINGIZE_CASE_LABEL(X_UngrabPointer, str) ;
        STRINGIZE_CASE_LABEL(X_GrabButton, str) ;
        STRINGIZE_CASE_LABEL(X_UngrabButton, str) ;
        STRINGIZE_CASE_LABEL(X_ChangeActivePointerGrab, str) ;
        STRINGIZE_CASE_LABEL(X_GrabKeyboard, str) ;
        STRINGIZE_CASE_LABEL(X_UngrabKeyboard, str) ;
        STRINGIZE_CASE_LABEL(X_GrabKey, str) ;
        STRINGIZE_CASE_LABEL(X_UngrabKey, str) ;
        STRINGIZE_CASE_LABEL(X_AllowEvents, str) ;
        STRINGIZE_CASE_LABEL(X_GrabServer, str) ;
        STRINGIZE_CASE_LABEL(X_UngrabServer, str) ;
        STRINGIZE_CASE_LABEL(X_QueryPointer, str) ;
        STRINGIZE_CASE_LABEL(X_GetMotionEvents, str) ;
        STRINGIZE_CASE_LABEL(X_TranslateCoords, str) ;
        STRINGIZE_CASE_LABEL(X_WarpPointer, str) ;
        STRINGIZE_CASE_LABEL(X_SetInputFocus, str) ;
        STRINGIZE_CASE_LABEL(X_GetInputFocus, str) ;
        STRINGIZE_CASE_LABEL(X_QueryKeymap, str) ;
        STRINGIZE_CASE_LABEL(X_OpenFont, str) ;
        STRINGIZE_CASE_LABEL(X_CloseFont, str) ;
        STRINGIZE_CASE_LABEL(X_QueryFont, str) ;
        STRINGIZE_CASE_LABEL(X_QueryTextExtents, str) ;
        STRINGIZE_CASE_LABEL(X_ListFonts, str) ;
        STRINGIZE_CASE_LABEL(X_ListFontsWithInfo, str) ;
        STRINGIZE_CASE_LABEL(X_SetFontPath, str) ;
        STRINGIZE_CASE_LABEL(X_GetFontPath, str) ;
        STRINGIZE_CASE_LABEL(X_CreatePixmap, str) ;
        STRINGIZE_CASE_LABEL(X_FreePixmap, str) ;
        STRINGIZE_CASE_LABEL(X_CreateGC, str) ;
        STRINGIZE_CASE_LABEL(X_ChangeGC, str) ;
        STRINGIZE_CASE_LABEL(X_CopyGC, str) ;
        STRINGIZE_CASE_LABEL(X_SetDashes, str) ;
        STRINGIZE_CASE_LABEL(X_SetClipRectangles, str) ;
        STRINGIZE_CASE_LABEL(X_FreeGC, str) ;
        STRINGIZE_CASE_LABEL(X_ClearArea, str) ;
        STRINGIZE_CASE_LABEL(X_CopyArea, str) ;
        STRINGIZE_CASE_LABEL(X_CopyPlane, str) ;
        STRINGIZE_CASE_LABEL(X_PolyPoint, str) ;
        STRINGIZE_CASE_LABEL(X_PolyLine, str) ;
        STRINGIZE_CASE_LABEL(X_PolySegment, str) ;
        STRINGIZE_CASE_LABEL(X_PolyRectangle, str) ;
        STRINGIZE_CASE_LABEL(X_PolyArc, str) ;
        STRINGIZE_CASE_LABEL(X_FillPoly, str) ;
        STRINGIZE_CASE_LABEL(X_PolyFillRectangle, str) ;
        STRINGIZE_CASE_LABEL(X_PolyFillArc, str) ;
        STRINGIZE_CASE_LABEL(X_PutImage, str) ;
        STRINGIZE_CASE_LABEL(X_GetImage, str) ;
        STRINGIZE_CASE_LABEL(X_PolyText8, str) ;
        STRINGIZE_CASE_LABEL(X_PolyText16, str) ;
        STRINGIZE_CASE_LABEL(X_ImageText8, str) ;
        STRINGIZE_CASE_LABEL(X_ImageText16, str) ;
        STRINGIZE_CASE_LABEL(X_CreateColormap, str) ;
        STRINGIZE_CASE_LABEL(X_FreeColormap, str) ;
        STRINGIZE_CASE_LABEL(X_CopyColormapAndFree, str) ;
        STRINGIZE_CASE_LABEL(X_InstallColormap, str) ;
        STRINGIZE_CASE_LABEL(X_UninstallColormap, str) ;
        STRINGIZE_CASE_LABEL(X_ListInstalledColormaps, str) ;
        STRINGIZE_CASE_LABEL(X_AllocColor, str) ;
        STRINGIZE_CASE_LABEL(X_AllocNamedColor, str) ;
        STRINGIZE_CASE_LABEL(X_AllocColorCells, str) ;
        STRINGIZE_CASE_LABEL(X_AllocColorPlanes, str) ;
        STRINGIZE_CASE_LABEL(X_FreeColors, str) ;
        STRINGIZE_CASE_LABEL(X_StoreColors, str) ;
        STRINGIZE_CASE_LABEL(X_StoreNamedColor, str) ;
        STRINGIZE_CASE_LABEL(X_QueryColors, str) ;
        STRINGIZE_CASE_LABEL(X_LookupColor, str) ;
        STRINGIZE_CASE_LABEL(X_CreateCursor, str) ;
        STRINGIZE_CASE_LABEL(X_CreateGlyphCursor, str) ;
        STRINGIZE_CASE_LABEL(X_FreeCursor, str) ;
        STRINGIZE_CASE_LABEL(X_RecolorCursor, str) ;
        STRINGIZE_CASE_LABEL(X_QueryBestSize, str) ;
        STRINGIZE_CASE_LABEL(X_QueryExtension, str) ;
        STRINGIZE_CASE_LABEL(X_ListExtensions, str) ;
        STRINGIZE_CASE_LABEL(X_ChangeKeyboardMapping, str) ;
        STRINGIZE_CASE_LABEL(X_GetKeyboardMapping, str) ;
        STRINGIZE_CASE_LABEL(X_ChangeKeyboardControl, str) ;
        STRINGIZE_CASE_LABEL(X_GetKeyboardControl, str) ;
        STRINGIZE_CASE_LABEL(X_Bell, str) ;
        STRINGIZE_CASE_LABEL(X_ChangePointerControl, str) ;
        STRINGIZE_CASE_LABEL(X_GetPointerControl, str) ;
        STRINGIZE_CASE_LABEL(X_SetScreenSaver, str) ;
        STRINGIZE_CASE_LABEL(X_GetScreenSaver, str) ;
        STRINGIZE_CASE_LABEL(X_ChangeHosts, str) ;
        STRINGIZE_CASE_LABEL(X_ListHosts, str) ;
        STRINGIZE_CASE_LABEL(X_SetAccessControl, str) ;
        STRINGIZE_CASE_LABEL(X_SetCloseDownMode, str) ;
        STRINGIZE_CASE_LABEL(X_KillClient, str) ;
        STRINGIZE_CASE_LABEL(X_RotateProperties, str) ;
        STRINGIZE_CASE_LABEL(X_ForceScreenSaver, str) ;
        STRINGIZE_CASE_LABEL(X_SetPointerMapping, str) ;
        STRINGIZE_CASE_LABEL(X_GetPointerMapping, str) ;
        STRINGIZE_CASE_LABEL(X_SetModifierMapping, str) ;
        STRINGIZE_CASE_LABEL(X_GetModifierMapping, str) ;
        STRINGIZE_CASE_LABEL(X_NoOperation, str) ;
    }
    str << ' ' << e->resourceid << ']' ;
    return str.str() ;
}

//--------------------- X MODIFIER MAP HACKERY -------------------------

uint32_t modmask(KeySym keysym, XModifierKeymap* modmap, Display* d)
{
    KeyCode keycode = XKeysymToKeycode(d, keysym) ;
    if (keycode == 0) // if we can't convert keysym to keycode, then
        return 0U ;   // the modifier map can't contain the given key

    const int  n = 8 * modmap->max_keypermod ;
    KeyCode* beg = modmap->modifiermap ;
    KeyCode* end = beg + n ;
    KeyCode*   k = std::find(beg, end, keycode) ;
    if (k == end) // keycode is not in modifier map
        return 0U ;

    // If we get here, the modifier map does have the requested key
    return (1U << (static_cast<int>(k - beg)/modmap->max_keypermod)) & 0xFF ;
}

//---------------------------- RECTANGLES -------------------------------

rect::rect()
    : left(0), right(0), bottom(0), top(0)
{}

rect::rect(int x, int y, int w, int h)
    : left(x), right(x + w), bottom(y + h), top(y)
{}

bool rect::intersects(const rect& r) const
{
    return !(left   > r.right || right < r.left ||
             bottom < r.top   || top   > r.bottom) ;
}

rect rect::intersection(const rect& r) const
{
    rect x ;
    if (this->intersects(r)) {
        x.left   = std::max(left,   r.left) ;
        x.right  = std::min(right,  r.right ) ;
        x.bottom = std::max(bottom, r.bottom) ;
        x.top    = std::min(top,    r.top) ;
    }
    return x ;
}

int rect::area() const
{
    return (right - left) * (bottom - top) ;
}

} // namespace minxlib

//----------------------------------------------------------------------

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/util.hh.

























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
134
135
136
137
138
139
140
/**
    @file  util.hh
    @brief Various utility routines for minxlib.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MINXLIB_UTIL_DOT_HH
#define MINXLIB_UTIL_DOT_HH

//------------------------------ HEADERS --------------------------------

// Xlib
#include <X11/Xlib.h>

// Standard C++
#include <string>

// Standard C
#include <stdint.h>

//------------------------------- XLIB ----------------------------------

namespace minxlib {

/**
    @brief  Return a string representation of X protocol errors.
    @param  e Xlib error structure containing the details of the protocol error.
    @return A string describing the error.

    This function converts the Xlib error and request codes into
    human-readable form.
*/
std::string to_str(const XErrorEvent* e) ;

/**
    @brief  Return a bit mask for given key if it is in the modifier map.
    @param  k The keysym to look for in the modifier map.
    @param  m The X modifier keymap.
    @param  d The X server's interface object.
    @return Mask for identifying modifier within modifier keymap.

    This function checks if the given key is part of the X modifier map.
    If so, it will return a mask that will have a one in the bit
    position corresponding to that modifier. Otherwise, it returns zero.
*/
uint32_t modmask(KeySym k, XModifierKeymap* m, Display* d) ;

//---------------------------- RECTANGLES -------------------------------

/**
    @brief Helper class for rectangle intersections.

    This class represents a rectangle aligned with the principal axes
    with x increasing from left to right and y from top to bottom. The
    main purpose of this class is to find the intersections between
    windows.
*/
class rect {
    // The four edges of the rectangle.
    int left, right, bottom, top ;

    // Private default constructor to create an empty rectangle.
    rect() ;

public:
    /**
        @brief  Create a rectangle object.
        @param  x x-coordinate of top-left corner.
        @param  y y-coordinate of top-left corner.
        @param  w Rectangle width.
        @param  h Rectangle height.
        @return Rectangle object.
    */
    rect(int x, int y, int w, int h) ;

    /**
        @brief  Does this rectangle intersect with another?
        @param  r The other rectangle.
        @return True if this rectangle intersects r; false otherwise.
    */
    bool intersects(const rect& r) const ;

    /**
        @brief  Compute intersection of this rectangle with another.
        @param  r The other rectangle.
        @return Intersection of this rectangle with r.

        This method returns the intersection of this rectangle object
        with the rectangle r. If there is no intersection, the returned
        rectangle will be empty (i.e., zero width and height).
    */
    rect intersection(const rect& r) const ;

    /**
        @brief  What is the area of this rectangle?
        @return Area of rectangle.
    */
    int area() const ;
} ;

} // namespace minxlib

//-----------------------------------------------------------------------

#endif // #ifndef MINXLIB_UTIL_DOT_HH

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/window.cc.













































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
/*
    @file  window.cc
    @brief Implementation of API defined in window.hh.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

//----------------------------- HEADERS --------------------------------

// minxlib
#include "window.hh"
#include "logging.hh"
#include "python.hh"
#include "keymap.hh"
#include "util.hh"

// Xlib
#include <X11/Xutil.h>
#ifdef MINXLIB_HAS_XINERAMA
#include <X11/extensions/Xinerama.h>
#endif

// Boost
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

#include <boost/foreach.hpp>

// Standard C++
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <iterator>

// Standard C
#include <string.h>

//-------------------- INITIALIZATION AND CLEAN-UP ----------------------

namespace minxlib {

static logging logger ;

window::window(Display* d, Window w)
    : m_display(d), m_id(w)
{}

window::~window(){}

//--------------------------- PROPERTIES ------------------------------

// Convert strings in X text property to semicolon separated string
static std::string property_to_string(XTextProperty* prop)
{
    char** strings ; int n ;
    if (XTextPropertyToStringList(prop, &strings, &n)) {
        std::ostringstream str ;
        std::copy(strings, strings + n,
                  std::ostream_iterator<char*>(str, ";")) ;
        XFreeStringList(strings) ;

        std::string s(str.str()) ;
        return s.substr(0, s.length() - 1) ; // remove last semicolon
    }
    return std::string() ;
}

std::map<std::string, std::string> window::properties()
{
    std::map<std::string, std::string> prop ;
    prop["name"     ] = "" ;
    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") ;
    if (it != prop.end()) {
        XTextProperty tp ;
        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()) {
        ch.res_class = new char[it->second.length() + 1] ;
        strcpy(ch.res_class, it->second.c_str()) ;
    }
    it = prop.find("res_name") ;
    if (it != prop.end()) {
        ch.res_name = new char[it->second.length() + 1] ;
        strcpy(ch.res_name, it->second.c_str()) ;
    }
    if (ch.res_class || ch.res_name) {
        XSetClassHint(m_display, m_id, &ch) ;
        logger.debug() << "set WM_CLASS for window " << m_id
                       << " to (" << (ch.res_class ? ch.res_class : "NULL")
                       << ", "    << (ch.res_name  ? ch.res_name  : "NULL")
                       << ')' ;
    }
    delete[] ch.res_class;
    delete[] ch.res_name ;
}

//-------------------- PARENT-CHILD RELATIONSHIPS -----------------------

void window::reparent(const window& new_parent)
{
    logger.debug() << "setting " << m_id << "'s parent to " << new_parent ;
    XReparentWindow(m_display, m_id, new_parent, 0, 0) ;
}

window window::parent()
{
    logger.debug() << "getting " << m_id << "'s parent" ;

    Window  root, parent_id ;
    Window* children = 0 ;
    unsigned int num_children ;
    Status s = XQueryTree(m_display, m_id,
                          &root, &parent_id, &children, &num_children) ;
    if (children) // whatever, don't care about these little buggers
        XFree(children) ;
    if (!s) {
        logger.error() << "unable to query tree for window " << m_id ;
        return window(m_display, 0) ; // throw exception instead?
    }

    logger.debug() << "window " << m_id << "'s parent = " << parent_id ;
    return window(m_display, parent_id) ;
}

std::vector<window> window::children()
{
    logger.debug() << "getting " << m_id << "'s children" ;

    std::vector<window> windows ;

    Window  root, parent ;
    Window* children = 0 ;
    unsigned int num_children ;
    Status s = XQueryTree(m_display, m_id,
                          &root, &parent, &children, &num_children) ;
    if (s) {
        if (children) {
            windows.reserve(num_children) ;
            for (unsigned int i = 0; i < num_children; ++i)
                windows.push_back(window(m_display, children[i])) ;
            XFree(children) ;
        }
    }
    else
        logger.error() << "unable to query tree for window " << m_id ;

    logger.debug() << "window " << m_id << " has " << windows.size()
                   << " children" ;
    return windows ;
}

int window::screen()
{
    XWindowAttributes attr ;
    Status s = XGetWindowAttributes(m_display, m_id, &attr) ;
    if (!s) {
        logger.error() << "unable to get screen index for window " << m_id ;
        return -1 ; // throw exception instead?
    }

    int screen_number = -1 ;
#ifdef MINXLIB_HAS_XINERAMA
    int n = 0 ;
    XineramaScreenInfo* screens = XineramaQueryScreens(m_display, &n) ;
    if (n > 0)
    {
        logger.debug() << "Xinerama enabled; " << n << " screens" ;

        // Find the physical screen that has the most of this window
        int  max_area = -1 ;
        rect w(attr.x, attr.y, attr.width, attr.height) ;
        for (int i = 0; i < n; ++i)
        {
            rect r(screens[i].x_org, screens[i].y_org,
                   screens[i].width, screens[i].height) ;
            rect x(w.intersection(r)) ;
            int area = x.area() ;
            if (area > max_area)
            {
                max_area = area ;
                screen_number = i ;
            }
        }
        XFree(screens) ;
    }
    else
#endif
    {
        logger.debug() << "Xinerama unavailable or inactive" ;
        screen_number = XScreenNumberOfScreen(attr.screen) ;
    }
    logger.debug() << "window " << m_id << " on screen " << screen_number ;
    return screen_number ;
}

//----------------------------- EVENTS ---------------------------------

void window::select_events(long mask)
{
    using std::hex ; using std::setw ; using std::setfill ;
    logger.debug() << "setting input mask for window " << m_id
                   << " to 0x" << hex << setw(8) << setfill('0') << mask ;
    XSelectInput(m_display, m_id, mask) ;
}

//-------------------- KEYBOARD/MOUSE GRABBING -------------------------

void window::grab_key(const std::string& key_binding)
{
    using std::dec ; using std::hex ; using std::setw ; using std::setfill ;
    logger.info() << "setting up passive grab for \"" << key_binding
                  << "\" on window " << m_id ;

    std::vector<std::string> split ;
    boost::algorithm::split(split, key_binding,
                            boost::algorithm::is_any_of("-"),
                            boost::algorithm::token_compress_on) ;

    // Last string after split is the key itself
    std::string key = split.back() ;
    KeySym keysym = XStringToKeysym(key.c_str()) ;
    if (keysym == NoSymbol) {
        logger.warning() << "no keysym matching \"" << key << '"' ;
        return ;
    }

    KeyCode keycode = XKeysymToKeycode(m_display, keysym) ;
    if (keycode == 0) {
        logger.warning() << "no keycode matching \"" << key << '"';
        return ;
    }
    logger.debug() << "keycode for \"" << key << "\" = "
                   << dec << static_cast<int>(keycode) << " (0x"
                   << hex << setw(4) << setfill('0')
                   << static_cast<int>(keycode) << ')' ;

    // Setup map for modifier short-hands and also initialize the list of
    // masks for the different lock modifiers.
    typedef std::map<std::string, unsigned int> modmap ;
    static modmap modifier_masks ;
    static std::vector<uint32_t> lock_masks;
    if (modifier_masks.empty()) {
        modifier_masks["C" ] = ControlMask ;
        modifier_masks["S" ] = ShiftMask;
        modifier_masks["M1"] = Mod1Mask ;
        modifier_masks["M2"] = Mod2Mask ;
        modifier_masks["M3"] = Mod3Mask ;
        modifier_masks["M4"] = Mod4Mask ;
        modifier_masks["M5"] = Mod5Mask ;

        // Now for ALT and META short-hands and the lock masks
        XModifierKeymap*  mkmap = XGetModifierMapping(m_display) ;
        if (mkmap) {
            modifier_masks["A"] = modmask(XK_Alt_L , mkmap, m_display) ;
            modifier_masks["M"] = modmask(XK_Meta_L, mkmap, m_display) ;
            uint32_t mask =
                keymap::ignore_lock_modifiers(mkmap, m_display) ;
            logger.debug() << "set modifier testing mask to 0x"
                           << hex << setw(4) << setfill('0') << mask ;
            XFreeModifiermap(mkmap) ;

            mask = ~mask & 0xFF ;
            logger.debug() << "lock masks = 0x"
                           << hex << setw(4) << setfill('0') << mask ;
            for (int i = 0; i < 8; ++i)
                if (mask & (1 << i))
                    lock_masks.push_back(1 << i) ;
        }
    }

    // First n-1 strings of split are the modifiers
    split.pop_back() ;
    unsigned int mask = 0 ;
    BOOST_FOREACH(const std::string& s, split)
    {
        modmap::const_iterator it = modifier_masks.find(s) ;
        if (it != modifier_masks.end())
            mask |= it->second ;
    }
    if (!mask)
        mask = AnyModifier ;
    logger.debug() << "modifier mask for \""   << key_binding << "\" = 0x"
                   << hex << setw(4) << setfill('0') << mask ;

    // Setup primary grab for key binding using plain modifier mask
    XGrabKey(m_display, keycode, mask, m_id,
             False, GrabModeAsync, GrabModeAsync) ;

    // Setup additional grabs with modifiers augmented with lock masks
    if (mask != AnyModifier) {
        unsigned int n = (1 << lock_masks.size()) - 1 ;
        for (unsigned int i = 1; i <= n; ++i) {
            uint32_t  lock_mask = 0;
            for (unsigned int j = 0; j < lock_masks.size(); ++j)
                if (i & (1 << j))
                    lock_mask |= lock_masks[j] ;

            logger.debug() << "setting up additional grab for \""
                           << key_binding << "\" with modifier mask 0x"
                           << hex << setw(4) << setfill('0')
                           << (mask | lock_mask) ;
            XGrabKey(m_display, keycode, mask | lock_mask, m_id,
                     False, GrabModeAsync, GrabModeAsync) ;
        }
    }

    // Store mapping between grab and key binding name so we can
    // translate keyboard events to the named key bindings as specified
    // by Minx's end-users.
    keymap::bind(keycode, mask, key_binding) ;
}

//----------------------- WINDOW VISIBILITY ----------------------------

void window::show()
{
    logger.debug() << "mapping window " << m_id ;
    XMapWindow(m_display, m_id) ;
}

void window::hide()
{
    logger.debug() << "unmapping window " << m_id ;
    XUnmapWindow(m_display, m_id) ;
}

bool window::is_mapped()
{
    XWindowAttributes attr ;
    Status s = XGetWindowAttributes(m_display, m_id, &attr) ;
    if (!s) {
        logger.error() << "unable to check map state for window " << m_id ;
        return false ; // throw exception instead?
    }
    return attr.map_state != IsUnmapped ;
}

//------------------------ WINDOW GEOMETRY -----------------------------

void window::move_resize(int x, int y, int w, int h)
{
    logger.debug() << "setting geometry for window "   << m_id << " to "
                   << w << 'x' << h << '+' << x << '+' << y;
    XMoveResizeWindow(m_display, m_id, x, y, w, h) ;
}

void window::configure(int x, int y, int width, int height,
                       int border_width,  const window* sibling,
                       int stacking_mode, unsigned int value_mask)
{
    using std::hex ; using std::setw ; using std::setfill ;
    logger.debug() << "configuring window "   << m_id << ": geom = "
                   << width << 'x'  << height << '+'  << x << '+' << y
                   << ", bw = "     << border_width
                   << ", mask = 0x" << hex << setw(8) << setfill('0')
                   << value_mask ;

    XWindowChanges wc ;
    wc.x = x ;
    wc.y = y ;
    wc.width  = width ;
    wc.height = height;
    wc.border_width = border_width ;
    wc.sibling      = sibling ? sibling->m_id : 0 ;
    wc.stack_mode   = stacking_mode;
    XConfigureWindow(m_display, m_id, value_mask, &wc) ;
}

void window::set_border_attr(unsigned long c, unsigned int s)
{
    using std::hex ; using std::setw ; using std::setfill ;
    logger.debug() << "setting window " << m_id
                   << " border color = 0x" << hex << setw(6) << setfill('0')
                   << c
                   << ", size = " << s ;
    XSetWindowBorderWidth(m_display, m_id, s) ;
    XSetWindowBorder     (m_display, m_id, c) ;
}

std::vector<int> window::geometry()
{
    std::vector<int> geom ;
    Window r ;
    int x, y ;
    unsigned int w, h, b, d ;
    Status s = XGetGeometry(m_display, m_id, &r, &x, &y, &w, &h, &b, &d) ;
    if (s) {
        geom.reserve(5) ;
        geom.push_back(x) ;
        geom.push_back(y) ;
        geom.push_back(w) ;
        geom.push_back(h) ;
        geom.push_back(b) ;
    }
    else
        logger.error() << "failed to get window geometry for ID " << m_id;
    return geom ;
}

//---------------------------- INPUT FOCUS ------------------------------

void window::focus()
{
    logger.debug() << "raising and focusing window " << m_id ;
    XRaiseWindow  (m_display, m_id) ;
    XSetInputFocus(m_display, m_id,
                   RevertToPointerRoot, CurrentTime) ;
}

//----------------------- WINDOW DESTRUCTION ---------------------------

// Check if specified window wants to participate in the
// WM_DELETE_WINDOW protocol. If so, fill out XEvent's
// XClientMessageEvent structure and return true; else, leave XEvent
// unfilled and return false.
static bool delete_window(Display* d, Window w, XEvent* e)
{
    bool   dw = false ;// start off assuming window doesn't do WM_DELETE_WINDOW
    Atom*   p = 0 ;    // list of WM_PROTOCOLS window does
    int     n = 0 ;    // number of items in above array
    Status ok = XGetWMProtocols(d, w, &p, &n) ;
    if (ok && n > 0) {
        Atom wm_delete = XInternAtom(d, "WM_DELETE_WINDOW", False) ;
        for (int i = 0; i < n; ++i)
            if (p[i] == wm_delete) {
                e->xclient.type         = ClientMessage ;
                e->xclient.display      = d ;
                e->xclient.window       = w ;
                e->xclient.message_type = XInternAtom(d, "WM_PROTOCOLS", False);
                e->xclient.format       = 32 ;
                e->xclient.data.l[0]    = wm_delete ;
                dw = true ;
                break ;
            }
        XFree(p) ;
    }
    return dw ;
}

void window::kill()
{
    XEvent e ;
    if  (delete_window(m_display, m_id, &e)) {
        if (XSendEvent(m_display, m_id, False, 0L, &e)) {
            logger.debug() << "sent WM_DELETE_WINDOW to window " << m_id ;
            return ;
        }
        logger.warning() << "WM_DELETE_WINDOW on window " << m_id << " failed" ;
    }
    nuke() ;
}

void window::nuke()
{
    logger.debug() << "killing window " << m_id << " with brute force" ;
    XKillClient(m_display, m_id) ;
}

//------------------------ PYTHON INTERFACE ----------------------------

void window::pythonize()
{
    py::class_<window>("window", py::no_init).
        def(py::self == py::self).
        def(py::self != py::self).
        def(py::self == py::other<Window>()  ).
        def(py::self != py::other<Window>()  ).
        def_readonly("id",      &window::m_id).
        def("properties",       &window::properties     ).
        def("set_properties",   &window::set_properties ).
        def("reparent",         &window::reparent       ).
        def("parent",           &window::parent         ).
        def("children",         &window::children       ).
        def("screen",           &window::screen         ).
        def("select_events",    &window::select_events  ).
        def("grab_key",         &window::grab_key       ).
        def("show",             &window::show           ).
        def("hide",             &window::hide           ).
        def("is_mapped",        &window::is_mapped      ).
        def("move_resize",      &window::move_resize    ).
        def("configure",        &window::configure      ).
        def("set_border_attr",  &window::set_border_attr).
        def("geometry",         &window::geometry       ).
        def("focus",            &window::focus          ).
        def("kill",             &window::kill           ).
        def("nuke",             &window::nuke           );

    py::enum_<event_mask>("event_mask").
        value("no_event_mask",              no_event_mask             ).
        value("key_press_mask",             key_press_mask            ).
        value("key_release_mask",           key_release_mask          ).
        value("button_press_mask",          button_press_mask         ).
        value("button_release_mask",        button_release_mask       ).
        value("enter_window_mask",          enter_window_mask         ).
        value("leave_window_mask",          leave_window_mask         ).
        value("pointer_motion_mask",        pointer_motion_mask       ).
        value("pointer_motion_hint_mask",   pointer_motion_hint_mask  ).
        value("button1_motion_mask",        button1_motion_mask       ).
        value("button2_motion_mask",        button2_motion_mask       ).
        value("button3_motion_mask",        button3_motion_mask       ).
        value("button4_motion_mask",        button4_motion_mask       ).
        value("button5_motion_mask",        button5_motion_mask       ).
        value("button_motion_mask",         button_motion_mask        ).
        value("keymap_state_mask",          keymap_state_mask         ).
        value("exposure_mask",              exposure_mask             ).
        value("visibility_change_mask",     visibility_change_mask    ).
        value("structure_notify_mask",      structure_notify_mask     ).
        value("resize_redirect_mask",       resize_redirect_mask      ).
        value("substructure_notify_mask",   substructure_notify_mask  ).
        value("substructure_redirect_mask", substructure_redirect_mask).
        value("focus_change_mask",          focus_change_mask         ).
        value("property_change_mask",       property_change_mask      ).
        value("colormap_change_mask",       colormap_change_mask      ).
        value("owner_grab_button_mask",     owner_grab_button_mask    ).
        export_values() ;

    py::enum_<configure_mask>("configure_mask").
        value("configure_x",            configure_x).
        value("configure_y",            configure_y).
        value("configure_width",        configure_width ).
        value("configure_height",       configure_height).
        value("configure_border_width", configure_border_width).
        value("configure_sibling",      configure_sibling     ).
        value("configure_stack_mode",   configure_stack_mode  ).
        export_values() ;

    logger = logging::get_logger("window") ;
}

} // namespace minxlib

//----------------------------------------------------------------------

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added minxlib/window.hh.















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
/**
    @file  window.hh
    @brief Encapsulation of an X window.

    This file defines a class that wraps around the notion of an X
    window and provides a Python interface for the rest of Minx.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MINXLIB_WINDOW_DOT_HH
#define MINXLIB_WINDOW_DOT_HH

//----------------------------- HEADERS --------------------------------

// Xlib
#include <X11/Xlib.h>

// Standard C++
#include <ostream>
#include <map>
#include <vector>
#include <string>

//------------------------- CLASS DEFINITION ---------------------------

namespace minxlib {

/**
    @brief Encapsulate the details of an X window.

    This class provides an API for the Python parts of Minx to be able
    to deal with X windows. It wraps around the relevant parts of Xlib
    and exposes its functionality to Python via @boostpylink.
*/
class window {
protected:
    // All Xlib calls will require a display object...
    Display* m_display ;

    // A window object's basic purpose is to wrap around the Xlib Window
    // data structure.
    Window m_id ;

public:
    /**
        @brief  Create a wrapper object for an existing Xlib window.
        @param  d The display object to which the window is "linked."
        @param  w The Xlib Window ID.
        @return A valid window wrapper for the given Xlib window.
    */
    window(Display* d, Window w) ;

    /**
        @brief  Export the window class to minxlib Python module.
        @return Nothing.

        This function exposes the window class's interface so that it
        can be used by the Python parts of Minx. It is meant to be
        called by the Boost.Python initialization code in python.cc.
    */
    static void pythonize() ;

    /**
        @brief  Window equality operator.
        @param  w The minxlib::window against which this should be checked.
        @return True if this window equals w; false otherwise.

        Two window objects are considered equal if they have the same ID
        and belong to the same display.
    */
    bool operator==(const window& w) const {
        return m_display == w.m_display && m_id == w.m_id ;
    }

    /**
        @brief  Window inequality operator.
        @param  w The minxlib::window against which this should be checked.
        @return True if this window does not equal w; false if it does.

        Two window objects are considered equal if they have the same ID
        and belong to the same display.
    */
    bool operator!=(const window& w) const {return !operator==(w) ;}

    /**
        @brief  Window equality operator.
        @param  w The Xlib window ID against which this should be checked.
        @return True if this window's ID equals w; false otherwise.

        This version of the equality operator only checks this object's
        window ID against w.
    */
    bool operator==(Window w) const {return m_id == w ;}

    /**
        @brief  Window inequality operator.
        @param  w The Xlib window ID against which this should be checked.
        @return True if this window's ID does not equal w; false otherwise.

        This version of the inequality operator only checks this
        object's window ID against w.
    */
    bool operator!=(Window w) const {return m_id != w ;}

    /**
        @brief  Convert to an Xlib Window.
        @return This object cast to an Xlib Window.

        This cast operator allows us to pass minxlib::window objects
        seamlessly to Xlib functions.
    */
    operator Window() const {return m_id ;}

    /**
        @brief  Retrieve window properties from X server.
        @return An STL map of strings to strings.

        This function gets the WM_NAME, WM_ICON_NAME, and WM_CLASS
        properties for this window and returns them in an STL map of
        strings to strings as shown below:

            <table>
                <tr><th><b>Key</b></th>  <th><b>Value</b>      </th></tr>
                <tr><td>name      </td>  <td>WM_NAME           </td></tr>
                <tr><td>icon_name </td>  <td>WM_ICON_NAME      </td></tr>
                <tr><td>class     </td>  <td>WM_CLASS.res_class</td></tr>
                <tr><td>res_name  </td>  <td>WM_CLASS.res_name </td></tr>
            </table>

        If we are unable to retrieve a particular property, that key's
        value will be an empty string. For example, if some window
        doesn't have a WM_CLASS property, the "class" and "res_name"
        keys for that window will be empty.

        On the Python side of Minx, the above STL map will be returned
        as a Python dict.

        @note Although rare, the WM_NAME and WM_ICON_NAME X properties
        may contain more than one string as values. If that is the case,
        these multiple values in the returned map/dict will be
        represented as semicolon separated strings. For example, if some
        window's WM_NAME property has values "foo" and "bar", the value
        of the "name" key in the returned map will be "foo;bar".
    */
    std::map<std::string, std::string> properties() ;

    /**
        @brief  Set window properties.
        @param  prop An STL map of strings to strings.
        @return Nothing.

        This function sets the window properties specified in its prop
        parameter. The following properties are supported:

            <table>
                <tr>
                    <th><b>minxlib Name</b></th>
                    <th><b>Xlib Property</b></th>
                </tr>
                <tr><td>name      </td>  <td>WM_NAME           </td></tr>
                <tr><td>icon_name </td>  <td>WM_ICON_NAME      </td></tr>
                <tr><td>class     </td>  <td>WM_CLASS.res_class</td></tr>
                <tr><td>res_name  </td>  <td>WM_CLASS.res_name </td></tr>
            </table>

        For example, let's say you have a minxlib::window object
        <tt>w</tt> and set its properties as shown by the snippet of code
        below:

        @code
            std::map<std::string, std::string> prop ;
            prop["class"] = "foo" ;
            prop["name" ] = "bar" ;
            w.set_properties(prop);
        @endcode

        That will set the WM_CLASS.res_class and WM_NAME properties of
        the window <tt>w</tt>.
    */
    virtual void set_properties(const std::map<std::string, std::string>& prop);

    /**
        @brief  Reparent this window to another.
        @param  p New parent window.
        @return Nothing.
    */
    virtual void reparent(const window& p) ;

    /**
        @brief  Get this window's parent window.
        @return Parent window.

        This function uses XQueryTree() to determine the parent window of
        the X window encapsulated by this object. If the call to
        XQueryTree() fails, this function will return a window object
        with the id member set to zero. Eventually, on XQueryTree()
        failure, X will generate a protocol error; that's why we don't
        bother throwing an exception.
    */
    virtual window parent() ;

    /**
        @brief  Get this window's children.
        @return Window's children.

        This function uses XQueryTree() to determine the list of child
        windows of the X window encapsulated by this object. If the call
        to XQueryTree() fails, this function will return an empty list
        and, eventually, X will generate a protocol error.
    */
    std::vector<window> children() ;

    /**
        @brief  Get screen number of this window.
        @return Window's screen number.

        This function returns the zero-based index of the physical
        screen this window is on. If Xinerama is active and this window
        overlaps two or more screens, this function will return the
        screen that has most of the window.

        @note This function calls XGetWindowAttributes(). If the call to
        XGetWindowAttributes() fails, this function will return -1 and,
        eventually, the X server will raise a protocol error.
    */
    virtual int screen() ;

    /**
        @brief An enumeration for the different event masks.

        This enumeration simply provides C++ names for the Xlib event
        masks that are exported to Python via @boostpylink's enum
        exporting facility.

        minxlib's names for the event masks and their corresponding Xlib
        names are shown below:

            <table>
                <tr><th><b>minxlib</b></th> <th><b>Xlib</b></th></tr>
                <tr><td>no_event_mask</td>
                    <td>NoEventMask</td></tr>
                <tr><td>key_press_mask</td>
                    <td>KeyPressMask</td></tr>
                <tr><td>key_release_mask</td>
                    <td>KeyReleaseMask</td></tr>
                <tr><td>button_press_mask</td>
                    <td>ButtonPressMask</td></tr>
                <tr><td>button_release_mask</td>
                    <td>ButtonReleaseMask</td></tr>
                <tr><td>enter_window_mask</td>
                    <td>EnterWindowMask</td></tr>
                <tr><td>leave_window_mask</td>
                    <td>LeaveWindowMask</td></tr>
                <tr><td>pointer_motion_mask</td>
                    <td>PointerMotionMask</td></tr>
                <tr><td>pointer_motion_hint_mask</td>
                    <td>PointerMotionHintMask</td></tr>
                <tr><td>button1_motion_mask</td>
                    <td>Button1MotionMask</td></tr>
                <tr><td>button2_motion_mask</td>
                    <td>Button2MotionMask</td></tr>
                <tr><td>button3_motion_mask</td>
                    <td>Button3MotionMask</td></tr>
                <tr><td>button4_motion_mask</td>
                    <td>Button4MotionMask</td></tr>
                <tr><td>button5_motion_mask</td>
                    <td>Button5MotionMask</td></tr>
                <tr><td>button_motion_mask</td>
                    <td>ButtonMotionMask</td></tr>
                <tr><td>keymap_state_mask</td>
                    <td>KeymapStateMask</td></tr>
                <tr><td>exposure_mask</td>
                    <td>ExposureMask</td></tr>
                <tr><td>visibility_change_mask</td>
                    <td>VisibilityChangeMask</td></tr>
                <tr><td>structure_notify_mask</td>
                    <td>StructureNotifyMask</td></tr>
                <tr><td>resize_redirect_mask</td>
                    <td>ResizeRedirectMask</td></tr>
                <tr><td>substructure_notify_mask
                    </td> <td>SubstructureNotifyMask</td></tr>
                <tr><td>substructure_redirect_mask</td>
                    <td>SubstructureRedirectMask</td></tr>
                <tr><td>focus_change_mask
                    </td> <td>FocusChangeMask</td></tr>
                <tr><td>property_change_mask</td>
                    <td>PropertyChangeMask</td></tr>
                <tr><td>colormap_change_mask</td>
                    <td>ColormapChangeMask</td></tr>
                <tr><td>owner_grab_button_mask</td>
                    <td>OwnerGrabButtonMask</td></tr>
            </table>
    */
    enum event_mask {
        no_event_mask              = NoEventMask,
        key_press_mask             = KeyPressMask,
        key_release_mask           = KeyReleaseMask,
        button_press_mask          = ButtonPressMask,
        button_release_mask        = ButtonReleaseMask,
        enter_window_mask          = EnterWindowMask,
        leave_window_mask          = LeaveWindowMask,
        pointer_motion_mask        = PointerMotionMask,
        pointer_motion_hint_mask   = PointerMotionHintMask,
        button1_motion_mask        = Button1MotionMask,
        button2_motion_mask        = Button2MotionMask,
        button3_motion_mask        = Button3MotionMask,
        button4_motion_mask        = Button4MotionMask,
        button5_motion_mask        = Button5MotionMask,
        button_motion_mask         = ButtonMotionMask,
        keymap_state_mask          = KeymapStateMask,
        exposure_mask              = ExposureMask,
        visibility_change_mask     = VisibilityChangeMask,
        structure_notify_mask      = StructureNotifyMask,
        resize_redirect_mask       = ResizeRedirectMask,
        substructure_notify_mask   = SubstructureNotifyMask,
        substructure_redirect_mask = SubstructureRedirectMask,
        focus_change_mask          = FocusChangeMask,
        property_change_mask       = PropertyChangeMask,
        colormap_change_mask       = ColormapChangeMask,
        owner_grab_button_mask     = OwnerGrabButtonMask,
    } ;

    /**
        @brief  Set the X event mask for this window.
        @param  mask The X event mask.
        @return Nothing.

        This method allows clients to specify the events they are
        interested in receiving for this window. The mask parameter
        should be a bitwise OR of the event_mask enum and is passed
        as-is to XSelectInput(). See the relevant Xlib documentation for
        the details about the event mask.
    */
    void select_events(long mask) ;

    /**
        @brief  Setup a passive keyboard grab.
        @param  s String describing key sequence for activating grab.
        @return Nothing.

        The string s is expected to name a key binding and should be of
        the form:

        @verbatim
            (([CAS]|M[1-5]?)-)*key
        @endverbatim

        The parenthesized part plus the asterisk in the above expression
        are a regular expression while <tt>"key"</tt> stands for the
        string form of a valid X keysym. Here are some examples of key
        binding specifications:

            <table>
                <tr><td> C-A-T </td> <td> CTRL + ALT + T </td></tr>
                <tr><td> S-F1  </td> <td> SHIFT + F1     </td></tr>
                <tr><td> A-Tab </td> <td> ALT + Tab      </td></tr>
                <tr><td> M-R   </td> <td> META + R       </td></tr>
                <tr><td> M5-S  </td> <td> Mod5 + S       </td></tr>
                <tr><td> C-C   </td> <td> CTRL + C       </td></tr>
            </table>

        Minx's key bindings specification is designed to be similar to
        the way key bindings are specified in Emacs.

        This function interprets its parameter s in the manner described
        above and infers the appropriate keycode and corresponding
        modifier mask for the specified key binding. It then sets up a
        passive grab for that keycode and modifier mask and also records
        the name of the key binding (viz., s) in a key map that is
        indexed using the keycode and modifier mask.

        Later, when the X server sends Minx keyboard events, we will use
        the event's keycode and modifier mask to look-up the key binding
        in the above-mentioned key map and return that name as part of
        the event to Minx's Python core.
    */
    void grab_key(const std::string& s) ;

    /**
        @brief  Show the window, i.e., map it.
        @return Nothing.
    */
    virtual void show() ;

    /**
        @brief  Hide this window, i.e., unmap it.
        @return Nothing.
    */
    virtual void hide() ;

    /**
        @brief  Check if window is currently mapped or not.
        @return True if window is mapped, false otherwise.

        This function uses XGetWindowAttributes() and checks the value
        of the XWindowAttributes's map_state field to see if the window
        is mapped or not. It'll return true if map_state equals
        IsViewable or IsUnviewable and false if either map_state is
        IsUnmapped or if the call to XGetWindowAttributes() fails.

        @note If XGetWindowAttributes() fails, we would expect a
        minxlib::protocol_error to be raised soon after. That's why this
        function returns false instead of throwing an exception.
    */
    virtual bool is_mapped() ;

    /**
        @brief  Move and resize the window.
        @param  x Window's x coordinate relative to parent's origin.
        @param  y Window's y coordinate relative to parent's origin.
        @param  w Window's width (not counting its border).
        @param  h Window's height (not counting its border).
        @return Nothing.

        This function sets the window geometry by calling
        XMoveResizeWindow(). Please consult Xlib documentation for
        further details.
    */
    virtual void move_resize(int x, int y, int w, int h) ;

    /**
        @brief  An enumeration for the different configure values.

        This enumeration simply provides C++ names for the Xlib value
        mask for configure requests. These names are exported to Python
        via @boostpylink's enum exporting facility.

        The minxlib and corresponding Xlib names for these enums are
        shown below:

            <table>
                <tr><th><b>minxlib</b>        </th> <th><b>Xlib</b>  </th></tr>
                <tr><td>configure_x           </td> <td>CWX          </td></tr>
                <tr><td>configure_y           </td> <td>CWY          </td></tr>
                <tr><td>configure_width       </td> <td>CWWidth      </td></tr>
                <tr><td>configure_height      </td> <td>CWHeight     </td></tr>
                <tr><td>configure_border_width</td> <td>CWBorderWidth</td></tr>
                <tr><td>configure_sibling     </td> <td>CWSibling    </td></tr>
                <tr><td>configure_stack_mode  </td> <td>CWStackMode  </td></tr>
            </table>
    */
    enum configure_mask {
        configure_x            = CWX,
        configure_y            = CWY,
        configure_width        = CWWidth,
        configure_height       = CWHeight,
        configure_border_width = CWBorderWidth,
        configure_sibling      = CWSibling,
        configure_stack_mode   = CWStackMode,
    } ;

    /**
        @brief  Configure the window.
        @param  x Window's x coordinate relative to parent's origin.
        @param  y Window's y coordinate relative to parent's origin.
        @param  w Window's width (not counting its border).
        @param  h Window's height (not counting its border).
        @param  b Window's border width.
        @param  s Window's sibling for stacking operations.
        @param  t Window's stacking mode.
        @param  v Value mask to determine what to configure.
        @return Nothing.

        This function calls XConfigureWindow() using v as the value_mask
        parameter to the Xlib function and using the other parameters to
        fill out the XWindowChanges structure. The value_mask is a
        bitwise OR of the configure_mask enums.

        Please consult Xlib documentation for further details. For
        example, the following page may be instructive:

            http://tronche.com/gui/x/xlib/window/configure.html
    */
    virtual void configure(int x, int y, int w, int h, int b,
                           const window* s, int t, unsigned int v) ;

    /**
        @brief  Set window's border color and size.
        @param  c Three-byte RGB spec.
        @param  s Border size (in pixels).
        @return Nothing.

        This function calls XSetWindowBorderWidth() and
        XSetWindowBorder() to specify the window's border color and size
        to the desired values.
    */
    virtual void set_border_attr(unsigned long c, unsigned int s) ;

    /**
        @brief  Retrieve window's size, position, and border width.
        @return STL vector of ints containing window geometry.

        This function uses XGetGeometry() to determine the window's size,
        position, and border width. It returns an STL vector of integers
        containing the following five values:

            @li Element 0: x-coordinate of window's top-left corner
            @li Element 1: y-coordinate of window's top-left corner
            @li Element 2: window width
            @li Element 3: window height
            @li Element 4: window's border width

        If the call to XGetGeometry() fails, this function will return an
        empty vector.

        @note On the Python side, the STL vector returned by this
        function will be converted into a Python list. Also, since we
        would expect a minxlib::protocol_error to be raised soon after a
        failed XGetGeometry(), we return and empty list instead of
        throwing an exception in case the call to XGetGeometry() bombs.
    */
    virtual std::vector<int> geometry() ;

    /**
        @brief  Set input focus on this window and raise it.
        @return Nothing.
    */
    virtual void focus() ;

    /**
        @brief  Kill this window.
        @return Nothing.

        This method destroys the X window encapsulated by this object by
        killing the X client application that created the window. If the
        window supports the WM_DELETE_WINDOW protocol, this method will
        use that to kill the window and its client application.
        Otherwise, it will simply use the XKillClient() function to
        destroy the window and its client by brute force.
    */
    virtual void kill() ;

    /**
        @brief  Kill this window using brute force.
        @return Nothing.

        This method destroys the X window encapsulated by this object
        without trying a graceful shutdown via WM_DELETE_WINDOW. It is
        meant to be used on those clients whose windows advertise
        support for WM_DELETE_WINDOW but don't implement the delete
        protocol properly and stay alive without good cause despite a
        user-initiated kill request.
    */
    virtual void nuke() ;

    /**
        @brief  Destructor.
        @return Nothing.

        Clean-up for when a window object is deleted. Really, there's
        nothing to do because this class is only a thin wrapper around X
        windows and we only maintain a pointer to the Xlib display
        structure and an integral ID. We don't actually create or acquire
        anything when this class is instantiated; consequently, there's
        nothing to destroy or release.
    */
    virtual ~window() ;
} ; // class window

} // namespace minxlib

//----------------------------------------------------------------------

#endif // #ifndef MINXLIB_WINDOW_DOT_HH

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added mk.



































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
#!/usr/bin/env sh
#
# mk -- build minxlib
#
# Convenience script for building minxlib without having to switch to
# the out-of-source build directory and other such hassles.
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See wiki/copyright.wiki for the full list of authors who have
# contributed to this project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

#------------------------------- MAIN ----------------------------------

# Restrict executable search path
PATH="/usr/local/bin:/usr/bin:/bin"

# Decide whether we want release or debug builds
BUILD=release # default
[ "$1" = "-d" -o "$1" = "--debug" ] && { BUILD=debug ; shift ; }

# Switch to the correct directory, i.e., the one containing this script
ABS_NAME=`readlink -f "$0"`
cd `dirname "$ABS_NAME"`

# Okay, now let's build the dang thing
[ -s build/$BUILD/Makefile ] || { # no Makefile ==> need to run cmake first
    rm -rf build/$BUILD
    mkdir -p build/$BUILD
    cd build/$BUILD
    cmake -DCMAKE_BUILD_TYPE=$BUILD ../.. || exit 1
    cd -
}
make -j4 -C build/$BUILD $@

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

# Editor config:
#
# Local Variables:
# indent-tabs-mode: nil
# sh-basic-offset: 4
# End:
#
# vim: expandtab shiftwidth=4 tabstop=4

Added wiki/build.wiki.













































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
<title>Building and Testing</title>

<h1>Building and Testing HOWTO</h1>

Eventually, the goal is to have Minx integrate well with different
package management systems. When that happens, getting Minx working
should be a fairly automated procedure. However, in these early days of
development, the process is a bit of a slog...

<h2>Prerequisites</h2>

You will need the following software to be able to grab Minx's source
code, build its C++ component (viz., minxlib), and then run the window
manager:

<center>
<table border="1">
  <tr>
    <th>Software</th>
    <th>Debian/Ubuntu<br>Package</th>
    <th>FreeBSD<br>Package</th>
    <th>Comments</th>
  </tr>
  <tr><td>Fossil</td>
      <td><tt>fossil</tt></td>
      <td><tt>devel/fossil</tt></td></tr>
  <tr><td>CMake</td>
      <td><tt>cmake</tt></td>
      <td><tt>devel/cmake</tt></td></tr>
  <tr><td>Boost</td>
      <td><tt>libboost-all-dev</tt></td>
      <td><tt>devel/boost-all</tt><br>
          <tt>devel/boost-python-libs</tt></td></tr>
  <tr><td>Python</td>
      <td>installed by above</td>
      <td>installed by above (?)</td></tr>
  <tr><td>Xephyr</td>
      <td><tt>xserver-xephyr</tt></td>
      <td><tt>x11-servers/xephyr</tt></td></tr>
  <tr><td>Xdmx</td>
      <td><tt>xdmx</tt></td>
      <td><tt>x11-servers/xorg-dmx</tt></td>
      <td>Optional (if you want to test multi-monitor setup)</td></tr>
  <tr><td>Doxygen</td>
      <td><tt>doxygen</tt></td>
      <td><tt>devel/doxygen</tt></td>
      <td>Optional (if you want to build API documentation)</td></tr>
</table>
</center>

In the above table, the package names are valid for a recent
Debian-based system (e.g.,
[http://www.debian.org/releases/squeeze/|Debian squeeze],
[http://releases.ubuntu.com/precise/|Ubuntu 12.04]). You should be able
to simply <tt>apt-get install</tt> the above packages to pull in the
necessary dependencies.

For a recent
[http://www5.us.freebsd.org/releases/9.0R/announce.html|FreeBSD] system,
the package names are all relative to <tt>/usr/ports</tt>. You should be
able to install the packages using one of the following:

  *  <tt>pkg_add</tt>
  *  <tt>make ; make install</tt>
  *  <tt>portmaster</tt>
  *  whatever other package management facilites exist on FreeBSD

Personally, I use <tt>portmaster</tt>.

<h2>Get the Code</h2>

Before you can check-out the source code, you will have to create a
directory where the Minx Fossil repository can be stored and another for
the working copy:

<verbatim>
    cd
    mkdir fossil minx
</verbatim>

Now, you can clone the Minx repository and check-out the sources:

<verbatim>
    fossil clone http://chiselapp.com/user/minxdude/repository/minx \
                 fossil/minx.fossil
    cd minx
    fossil open ~/fossil/minx.fossil
    fossil update rel1.x
</verbatim>

At this point, you should have the Minx sources in <tt>~/minx</tt>. You
should see at least these two subdirectories: <tt>minxlib</tt> and
<tt>core</tt>. The former contains the C++ part of Minx, the latter has
the Python code.

<h2>Build minxlib</h2>

The top-level directory has a script named <tt>mk</tt> for building
<b>minxlib</b> and the API documentation. So, assuming you are in
<tt>~/minx</tt>, all you should need to do is:

<verbatim>
    ./mk
</verbatim>

And, if you want to build the API documentation:

<verbatim>
    ./mk doc
</verbatim>

But note that the <b>rel1.x</b> branch already has the API documentation
[/doc/rel1.x/api/index.html|checked in to the repository]. So you really
shouldn't need to build the documentation.

<h2>Configure Minx</h2>

Minx is actually a Python library that allows you to write your own
tiling window manager. Thus, there is no command to start Minx. Rather,
you write a small Python program that loads Minx and starts the window
manager.

You can put the above-mentioned program wherever you like. Here, we will
assume it goes to <tt>~/.minx/init.py</tt>. So, fire up your favourite
editor and add the following content to <tt>~/.minx/init.py</tt>:

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

    import os, sys
    sys.path.append(os.path.join(os.environ['HOME']))

    import minx
    minx.core.wm().start()
</verbatim>

After saving the above file, make it executable:

<verbatim>
    chmod +x ~/.minx/init.py
</verbatim>

That's it, we're now ready to put Minx through its paces...

<h2>Test-drive Minx</h2>

<h3>Single Monitor</h3>

Currently, Minx is very far from being ready for prime-time. All it does
is allow you to switch input focus from one top-level window to another.
So don't edit your <tt>~/.xinitrc</tt> and restart X just yet! Instead,
run <b>Xephyr</b>:

<verbatim>
    Xephyr :1 2> /dev/null &
</verbatim>

You don't have to redirect <tt>stderr</tt> to <tt>/dev/null</tt>. I do it
because I find Xephyr's chatter distracting and unnecessary.

Once Xephyr comes up, start Minx:

<verbatim>
    DISPLAY=:1 ~/.minx/init.py &
</verbatim>

Now, give Minx a few windows it can switch between. I usually start up a
few terminals and message windows (you can use any X applications you
like):

<verbatim>
    DISPLAY=:1 xterm &
    DISPLAY=:1 xmessage foo &
    DISPLAY=:1 xmessage bar &
</verbatim>

To cycle input focus between the above windows, switch to the Xephyr
window and have it grab input focus by pressing <b>CTRL + SHIFT</b>.
Then, press <b>ALT + Tab</b> and/or <b>ALT + SHIFT + Tab</b> repeatedly
move the input focus forwards or backwards through the applications you
started. When you're done testing, use <b>CTRL + SHIFT</b> again to have
Xephyr release its grab on the keyboard and mouse so you can kill it and
return to your normal X session.

<b>NOTE:</b> If <b>ALT + Tab</b> doesn't work, try customizing the key
bindings for focus cycling as described in the
[/doc/ckout/wiki/key-bindings.wiki|Key Bindings HOWTO].

<h4>Ubuntu Peculiarities</h4>

Sometimes, on Ubuntu 12.04, typing into a terminal window generates junk
characters when other windows are present. That is, if you start Xephyr,
Minx, and then an xterm, you can use the terminal. However, if you start
an xmessage and an xterm, typing into the terminal results in junk. Not
sure why this happens.

<h3>Dual Monitor</h3>

To test Minx's ability to handle dual-head configurations, use Xephyr
and Xdmx like so:

<verbatim>
   Xephyr :2 2> /dev/null &
   Xephyr :3 2> /dev/null &
   Xdmx :1 -display :2 -display :3 2> /dev/null &
</verbatim>

Now start the window manager and a couple of applications:

<verbatim>
   DISPLAY=:1 ~/.minx/init.py &
   DISPLAY=:1.0 xterm &
   DISPLAY=:1.0 xmessage foo &
   DISPLAY=:1.1 xterm &
   DISPLAY=:1.1 xmessage bar &
</verbatim>

You should be able to use <b>ALT + Tab</b> to switch between the above
xterm and xmessage windows across both screens.

<b>NOTE:</b> Again, if <b>ALT + Tab</b> doesn't work, try customizing
the key bindings (<b>F1</b> and <b>SHIFT + F1</b> are usually quite
trustworthy).

<h4>Peculiarities</h4>

One issue to keep in mind with this dual-monitor test is that key press
events only seem to work on the first Xephyr window. For some reason,
when the second Xephyr window is focused, no keyboard events are
generated. Not sure why this happens.

Added wiki/copyright.wiki.















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<title>Copyright</title>

<h1>The Minx Project's Developers and Copyright Holders</h1>

Minx is a tiling X window manager. It is released under the auspices of version
3 of the GNU General Public License. Instead of cluttering each source file with
copyright notices containing author info, we put the list of people who have
contributed to Minx in this file and a short notice in each source file pointing
to this one
([http://softwarefreedom.org/resources/2012/ManagingCopyrightInformation.html|per
these recommendations]).

With that short explanation out of the way, here is the list of people who
have contributed to [/doc/ckout/wiki/home.wiki|the Minx project]:

<hr>

<table>
<tr>
   <td><b>Manu Viswanathan</b></td>
   <td>&lt;<em>minxdude@gmail.com</em>&gt;</td>
</tr>
</table>

Added wiki/design.wiki.





























































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
<title>Design Notes</title>

<h1>Design and Implementation Notes</h1>

The following diagram shows a high-level view of the different classes
and roughly how they're connected to each other.

<img src="img/object_diagram.png" width="900" height="337"/>

The <tt>minx.core</tt> and <tt>minx.layout</tt> classes are written in
Python whereas the <tt>minxlib</tt> classes are written in C++ and
exposed to Minx's Python core.

The organization of the code mirrors the above diagram. All the
<tt>minx.core</tt> classes are in the <em>minx/core</em> directory, the
<tt>minx.layout</tt> classes in <em>minx/layout</em>, and the
<tt>minxlib</tt> classes are in the <em>minx/minxlib</em> directory.

<hr>

<h2>minx.core</h2>

<h3>minx.core.wm</h3>

This class is the main window manager object that end-users will create.
It maintains all the necessary state and provides the interface for
customizing the window manager.

When you create a <tt>wm</tt> object, you can supply a <tt>config</tt>
object to its constructor to customize various attributes such as the
border colors. To further customize Minx's responses to various events,
you can add your own hook functions to the <tt>wm.hooks</tt> object. For
layouts, you can deal with the <tt>wm.layouts</tt> object, which is an
instance of the <tt>minx.core.layman</tt> class.

After these setup steps, call <tt>wm.start()</tt> to run the window
manager. The <tt>start()</tt> method connects to the X server by creating
a <tt>minxlib::display</tt> object, performs some initialization so as to
receive various window management related events, and then enters the
event loop. The actual event handling is delegated to the
<tt>minx.core.xevents</tt> object, which has the necessary event handler
callbacks.

X errors are handled by <tt>minx.core.wm</tt> as part of its event loop.

<h3>minx.core.hooks</h3>

This class implements a mapping between strings and corresponding
function lists. The string keys identify different events. For example,
all X events are of the form "<tt>x_something</tt>"
(<tt>x_map_request</tt>, <tt>x_create_notify</tt>, etc.). Most end-user
hooks are of the form "<tt>some_hook</tt>". Key bindings are also handled
as hooks (their names are not of the form "<tt>some_hook</tt>"; they
follow a different [/doc/ckout/wiki/key-bindings.wiki|pattern]).

All objects within the system that have a reference to the <tt>wm</tt>
object can get at the hook map and add functions to it. This map is
meant to be used inside the window manager itself as well as by
end-users (for customizing Minx).

<h3>minx.core.xevents</h3>

The <tt>xevents</tt> class is a simple helper. Initially, all the X
event handlers were in <tt>minx.core.wm</tt>. But that made <tt>wm</tt>
too big. So we split the event handlers into their own class, viz.,
<tt>minx.core.xevents</tt>.

When end-user code instantiates <tt>minx.core.wm</tt>, the <tt>wm</tt>
constructor creates an <tt>xevents</tt> object, passing it a reference
to itself. Through this reference to <tt>wm</tt>, <tt>xevents</tt> is
able to add its handlers to <tt>wm.hooks</tt>.

Now, when <tt>wm</tt> gets events from the X server, it triggers the
appropriate handler in <tt>xevents</tt> via its map of hooks.

<h3>minx.core.layman</h3>

This class implements a layout manager, which keeps track of the
different layouts. The <tt>layman</tt> class maintains a list of layout
objects and provides an API for adding layouts, looking for them, and so
on.

<h3>minx.core.focus_list</h3>

Not all top-level windows can be focused. For example, the GNOME and XFCE
terminal programs create a couple of hidden top-level windows. Therefore,
only a subset of the top-level windows can actually receive input focus.
These windows are put in the <tt>focus_list</tt> by the <tt>xevents</tt>
object. This usually happens when the X server sends a <tt>MapNotify</tt>
event for a top-level window to Minx. When <tt>minx.core.wm</tt> receives
an <tt>UnmapNotify</tt> for a top-level window, <tt>xevents</tt> will
remove the corresponding <tt>minxlib::window</tt> from the
<tt>focus_list</tt>.

<h3>minx.core.config</h3>

This class allows end-users to effect simple customizations such as
changing the window border colors and sizes. End-users will have to
instantiate this class and change its attributes to get the desired
customizations. The resulting <tt>config</tt> object should be passed to
the <tt>minx.core.wm</tt> constructor. Any object that has a reference
to the <tt>wm</tt> object can then get at its <tt>config</tt> instance
to access the different settings.

If end-users do not create a custom <tt>config</tt>, Minx will use
default values for all its supported customizations.

<hr>

<h2>minx.layout</h2>

<h3>minx.layout.base</h3>

This is a base class for all Minx layouts. For the most part, it contains
empty implementations for most events and other functions that are meant
to be overridden by subclasses. Additionally, the
<tt>minx.layout.base</tt> module contains a few event handlers for
various bits of layout related functionality.

<h3>minx.layout.full</h3>

This layout implements a policy of showing one window at a time, resizing
all the windows it manages to occupy the entire area available to it.

<hr>

<h2>minxlib</h2>

minxlib is a small C++ library that provides a high-level,
object-oriented API to Minx's Python core for interfacing with Xlib. We
could have used [http://python-xlib.sourceforge.net/|python-xlib]
instead of writing our own custom Xlib wrapper. Unfortunately, the
[http://python-xlib.sourceforge.net/doc/html/index.html|documentation]
of python-xlib is a little thin. Rather than struggle with that, it
seemed like a good idea to just implement minxlib.

Furthermore, a custom abstraction should make it easier to port Minx to
[http://wayland.freedesktop.org/|Wayland] whenever that becomes the
preferred means of talking to the video hardware.

Note that minxlib is not a thin wrapper around Xlib. It provides an API
that the rest of Minx actually needs. That is, the primary goal of
minxlib is not to wrap around all of Xlib but only that part of it that
we actually need for Minx. Moreover, minxlib provides a high-level API
that goes beyond the primitive one implemented by Xlib. For example,
minxlib has a function to return a list of all the root windows across
all screens. Thus, the Python parts of Minx don't have to deal with the
low-level Xlib functions to enumerate the root windows one-by-one.

<h3>minxlib::display</h3>

The <tt>display</tt> class encapsulates the connection to the X server.
It provides the conduit for retrieving events from the server and for
converting X errors into exception objects that Minx's Python core can
handle.

<h3>minxlib::window and minxlib::root_window</h3>

This class encapsulates an X window, taking care of the details of
specifying X event masks and setting up key bindings. It also provides
various window-related operations such as showing, hiding, resizing,
moving, focusing, etc.

The <tt>root_window</tt> class is derived from <tt>minxlib::window</tt>
and provides an encapsulation of X's root windows, taking into account
support for Xinerama. Minx provides one <tt>root_window</tt> for each
physical screen. If Xinerama is active, there'll only be one logical
screen; however, Minx will return multiple <tt>root_window</tt> objects,
each with the same X ID but different geometries.

<h3>minxlib::event and minxlib::exception</h3>

These two classes provide an object-oriented interface to X events and
errors.  Different types of events are converted into instances of
subclasses of <tt>minxlib::event</tt>. Similarly, different kinds of
errors are converted into instances of classes derived from
<tt>minxlib::exception</tt> (which, on the Python side, is derived from
Python's <tt>Exception</tt> base class).

Like the rest of minxlib, the events and exceptions interface is
incomplete, wrapping around only those parts of Xlib that Minx actually
needs.

<h3>minxlib::keymap</h3>

The <tt>keymap</tt> is used to keep track of the user-defined (or
internally assigned) key binding names. When a keystroke matching a key
binding is generated, the key event is "translated" so as to report that
key binding to the Python core.

<h3>minxlib::logging</h3>

To help with debugging, Minx emits log messages. Instead of implementing
a separate logging API in C++, minxlib simply takes advantage of
Python's standard <tt>logging</tt> module. The <tt>minxlib::logging</tt>
class provides a C++ logging API that uses the Python <tt>logging</tt>
module. Thus, minxlib's log messages end up in the same place as the
other Minx log messages. Moreover, the logging configuration is the same
as for Minx's Python parts; that is, end-users see all of Minx as a
Python library and can remain blissfully unaware of the fact that the
minxlib component is written in C++.

All the other minxlib classes use the <tt>minxlib::logging</tt> API to
emit log messages to the Minx log. To make this work, each minxlib
module instantiates a logger object and uses that object to send
messages to the Minx log.

Added wiki/faq.wiki.





































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
<title>FAQ</title>

<h1>Frequently Asked Questions</h1>

[#general-questions|About Minx]
  #  [#what-is-minx|What is Minx?]
  #  [#why-yawm|Why write yet another (tiling) window manager?]
  #  [#why-not-qtile|Why not qtile?]

[#config-questions|Using Minx]
  #  [#how-start|How do I start Minx?]
  #  [#simple-customizations|How do I customize border colors, etc.?]
  #  [#how-hooks|How do I customize Minx's behaviour?]
  #  [#how-key-bindings|How do I specify my own key bindings?]
  #  [#how-launch-apps|How can I launch applications with key strokes?]
  #  [#minx-version|Which version of Minx am I using?]

[#dev-questions|Design and Implementation]
  #  [#what-is-minxlib|What is minxlib?]
  #  [#why-not-pyxlib|Why not use python-xlib?]
  #  [#why-not-xcb|Why not use XCB instead of Xlib?]
  #  [#how-build|How do I build Minx?]
  #  [#why-fossil|Why Fossil instead of git or mercurial?]
  #  [#branches|Why dev1.x/rel1.x branches? Will there be 2.x, 3.x, etc.?]
  #  [#why-doxygen|Why Doxygen instead of Sphinx?]

<hr>

<a name="general-questions"></a>
<h2>About Minx</h2>

<a name="what-is-minx"></a>
<h3>What is Minx?</h3>

<b>M</b>inx <b>I</b>s <b>N</b>ot <b>X</b>monad. That is, it is a poor
imitator.  Thus, like [http://xmonad.org/|xmonad], Minx attempts to
layout the top-level windows on your X screens by automatically tiling
them.

Minx's overarching goals are:

  *  Minimalism
  *  Extensibility
  *  Ease of configuration

Minx does not paint icons on your root window, have a clickable taskbar
or panel for window selection, etc. All it does is manage the top-level
windows as per your settings (layout algorithm to use, keybindings, and
so on). Additionally, the only decoration Minx puts on top-level windows
is a simple border. By default, this border is one pixel thick and is
red for the currently focused window and white for all the others (but,
of course, you can change that).

Another way in which Minx is minimal is in the small number of core
principles it implements, namely:

  *  Hooks
  *  Layout support
  *  State injection

That's it. All other features are built on top of this basic
infrastructure. For example, Minx has no built-in notion of a workspace.
Instead, it sports "bookmarks," which capture "snapshots" that record
the current layout, window configuration, etc. This custom state is then
added to the window manager, which has functions for searching for that
state, retrieving it, and so on.

Apart from keeping the window manager's core small, these core ideas
also help make it highly customizable and extensible.

Finally, when it comes to ease of configuration, Minx's defaults aim for
a reasonable out-of-the-box end-user experience. Things that people
would commonly want to customize involve a small and straightforward
amount of Python code. But even more advanced configuration (e.g.,
implementing custom layouts, altering focus switching policy, etc.) is
also fairly easy.

<hr>

<a name="why-yawm"></a>
<h3>Yes, but xmonad is all that and more. So why bother writing yet
another (tiling) window manager?</h3>

Mostly because I was not patient enough to unlearn enough of my
imperative programming habits to fully understand
[http://haskell.org/|Haskell] and, thereby, configure
[http://xmonad.org/|xmonad] to get the exact behaviour I wanted.

Of course, I could have switched to a different tiling window manager.
And I did look into [http://awesome.naquadah.org/|awesome],
[http://i3wm.org/|i3], [http://www.nongnu.org/stumpwm/|StumpWM], and one
or two others. Needless to say, in the end, I decided that if I wanted a
window manager that worked exactly how I wanted, I'd best write my own.

In retrospect, I should probably have just spent the time and effort to
really learn Haskell! When I started Minx, I thought to myself "There
are a gazillion window managers out there. How hard can it be?
[http://swizec.com/blog/programmers-are-optimists/swizec/4509|I should
be done in a few weeks.]"

Now, more than a few weeks into it, I can see this is going to take a
while because:

  #  Low-level X programming is not quite as straightforward as I thought
     it would be.
  #  Figuring out the various support libraries (e.g.,
     [http://boost.org/|Boost]) involves a fair amount of trial and error.
  #  Learning a new set of tools ([http://fossil-scm.org/|version control],
     [#why-doxygen|documentation generator],
     [http://www.graphviz.org/|diagramming language]) also takes time.
  #  Cleaning up code and writing good documentation slows down
     development a good deal.

On the other hand, at this point, I am committed to the project and am
learning new things. So, I suppose I shouldn't complain.

<hr>

<a name="why-not-qtile"></a>
<h3>Fine, if you're too dumb to grok Haskell and want to stick with
something you know, i.e., Python, why not use qtile?</h3>

I did consider [http://qtile.org/|qtile]. But I thought its dependencies
were somewhat onerous and I was in no mood to check-out and build a
bunch of libraries from their source-control repositories just to get a
window manager working. If I was going to be using a "ready-made" window
manager (and not roll my own), I just wanted to be able to install a
couple of packages, read some docs to figure out how to customize it,
and move on with my life.

Moreover, <b>qtile</b> has some things in it that, in my opinion, do not
belong in a minimal window manager, viz., widgets. Such functionality
should be left to other programs (e.g.,
[http://adesklets.sourceforge.net/|adesklets],
[http://screenlets.org/|screenlets]).

Minx, in contrast, only needs stock Xlib, [http://boost.org/|Boost], and
[http://python.org/|Python]. You can install these using your system's
package manager.

But, really, my arguments for rejecting [http://xmonad.org/|xmonad],
[http://qtile.org/|qtile], and other window managers in favour of
writing my own are fairly weak and can be boiled down to "Because I can
and I want to." So, before you flame me about it, if you like one of
these other window managers, please continue to use 'em; they're quite
fine programs and I am not dissing them or trying to proselytize you to
switch to Minx.

<hr>

<a name="config-questions"></a>
<h2>Using Minx</h2>

<a name="how-start"></a>
<h3>How do I start Minx?</h3>

At this time, Minx cannot even be considered alpha software. Therefore,
it does not do anything very useful and does not come neatly packaged.
You have to check-out its source code and run it in a nested X server.
See the [/doc/ckout/wiki/build.wiki|Building and Testing HOWTO] for more
details.

<hr>

<a name="simple-customizations"></a>
<h3>How do I customize border colors, sizes, and other such simple
attributes?</h3>

By default, window borders are one pixel; the active window's border is
red, and inactive window borders are white. To change these defaults,
you will have to create a <tt>minx.core.config</tt> object, assign the
desired values to its attributes, and then pass this <tt>config</tt>
object to the <tt>minx.core.wm</tt> constructor. Here is some sample
code to show how to go about this:

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

   import minx

   conf = minx.core.config()
   conf.active_border_size    = 2
   conf.active_border_color   = 0x00FF00 # green
   conf.inactive_border_color = 0x00FFFF # cyan

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

For more info about the <tt>config</tt> class, have a look at its
[/doc/ckout/api/classminx_1_1core_1_1config_1_1config.html|API documentation].

In addition to the border attributes, the <tt>minx.core.config</tt>
class also allows you to configure logging, which can be useful for
debugging. For details on this, refer to the
[/doc/ckout/wiki/logging.wiki|logging HOWTO].

<hr>

<a name="how-hooks"></a>
<h3>How can I define my own hook functions to tweak how Minx handles
various events?</h3>

The [/doc/ckout/api/classminx_1_1core_1_1wm_1_1wm.html|main window
manager object] maintains a <tt>hooks</tt> attribute that maps
predefined names to their corresponding hook functions. By default, most
of these name-to-function mappings are empty. To add your own hook, you
will have to call <tt>wm.hooks.add()</tt> after creating the <tt>wm</tt>
object but before calling its <tt>start()</tt> method.

Here is a short example:

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

   import minx

   def my_manage_hook(w):
       prop = w.properties()
       if prop['class'] == 'Xmessage' and prop['name'] == 'bar':
          return False
       return True

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

With that bit of code, Minx will call <tt>my_manage_hook()</tt> whenever
a new window is created, which checks whether the window is an Xmessage
named "bar"; if so, the hook returns false to indicate to Minx that the
window should not be managed. Other windows will be passed through to
Minx for it to manage normally.

The [/doc/ckout/wiki/hooks-howto.wiki|Hooks HOWTO] has a lot more
information about customization via hooks. The
[/doc/ckout/wiki/hooks-list.wiki|Hooks List] documents all the currently
supported hooks.

<hr>

<a name="how-key-bindings"></a>
<h3>How can I specify my own key bindings to trigger various
functions?</h3>

Key bindings are simply hooks whose names follow the pattern shown
below:

<verbatim>
   [modifier-]*key
</verbatim>

Thus, a key binding's name consists of zero or more hyphen-separated
modifiers followed in the end by the name of a key. The supported
modifiers are:

  *  <b>C</b> for CTRL
  *  <b>A</b> for ALT
  *  <b>S</b> for SHIFT
  *  <b>M</b> for META
  *  <b>M1</b> through <b>M5</b> for Mod1 through Mod5

The following examples should clarify how key bindings are named:

<center>
<table border="1">
   <tr><th> Name  </th> <th> Key Binding    </th></tr>
   <tr><td> C-A-T </td> <td> CTRL + ALT + T </td></tr>
   <tr><td> S-F1  </td> <td> SHIFT + F1     </td></tr>
   <tr><td> A-Tab </td> <td> ALT + Tab      </td></tr>
   <tr><td> M-R   </td> <td> META + R       </td></tr>
   <tr><td> M5-S  </td> <td> Mod5 + S       </td></tr>
   <tr><td> C-C   </td> <td> CTRL + C       </td></tr>
</table>
</center>

To add your own key bindings, you will have to use
[#how-hooks|Minx's hooks support]. The following example shows you how
you can use (in addition to the default ALT + Tab and ALT + SHIFT + Tab)
the F1 and SHIFT + F1 keys to cycle the input focus:

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

   import minx

   wm = minx.core.wm()
   wm.hooks.add(  'F1', wm.focus_next)
   wm.hooks.add('S-F1', wm.focus_prev)
   wm.start()
</verbatim>

For more on key bindings, be sure to read the
[/doc/ckout/wiki/key-bindings.wiki|Key Bindings HOWTO]. Additionally,
the [/doc/ckout/wiki/hooks-list.wiki#default-key-bindings|Hooks List]
documents all the default key bindings.

<hr>

<a name="how-launch-apps"></a>
<h3>How can I launch applications using custom key bindings?</h3>

The [/doc/rel1.x/api/classminx_1_1core_1_1wm_1_1wm.html|wm] class has a
<tt>spawn()</tt> function that you can use for this purpose. In fact,
there is a
[/doc/rel1.x/wiki/hooks-list.wiki#launch_terminal|default key binding]
that calls <tt>wm.spawn()</tt> to launch a terminal window. In a similar
vein, you could define keys as shown below:

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

    import minx

    wm = minx.core.wm()
    wm.hooks.add('C-A-E', lambda: wm.spawn('emacs'))
    wm.hooks.add('C-A-F', lambda: wm.spawn('firefox'))
    wm.hooks.add('C-A-G', lambda: wm.spawn('gimp'))
    wm.start()
</verbatim>

With that, CTRL + ALT + E will launch Emacs, CTRL + ALT + F will launch
Firefox, and CTRL + ALT + G will launch The Gimp.

<hr>

<a name="minx-version"></a>
<h3>Which version of Minx am I using?</h3>

The <tt>minx</tt> module defines a <tt>version</tt> object. Converting
this to a string will yield something of the form <tt>a.b.c</tt>, where
<tt>a</tt> is the major version number, <tt>b</tt> the minor version
number, and <tt>c</tt> the patch level.

Additionally, the <tt>minx.version</tt> object has three read-only
attributes, viz., <tt>major</tt>, <tt>minor</tt>, and <tt>patch</tt>.
These attributes are integers and allow you to individually determine
and/or compare the three components of the full version number.

Here is some sample code illustrating version number determination:

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

   import minx

   try:
      print('Minx version string: {}'.format(minx.version))
      print('Minx version: major = {}, minor = {}, patch = {}'.
            format(minx.version.major, minx.version.minor, minx.version.patch))
   except AttributeError: # no version attribute in minx module
      pass # probably using development version of Minx
</verbatim>

Note that <tt>minx.version</tt> is not available in development versions
of Minx. Only officially released versions of Minx have a version number
assigned to them.

<hr>

<a name="dev-questions"></a>
<h2>Design and Implementation</h2>

<a name="what-is-minxlib"></a>
<h3>What is minxlib?</h3>

Minx is written in [http://python.org/|Python]. minxlib is an Xlib
wrapper written in [http://www.stroustrup.com/C++.html|C++] with its API
exposed to the Python-based Minx core via
[http://www.boost.org/doc/libs/1_52_0/libs/python/doc/|Boost.Python].
minxlib provides a high-level, object-oriented interface to Xlib that
the Python parts of Minx can use.

<hr>

<a name="why-not-pyxlib"></a>
<h3>Why not use python-xlib instead of writing a custom Xlib wrapper?</h3>

Lack of
[http://python-xlib.sourceforge.net/doc/html/index.html|documentation].

Whatever its [http://www.remlab.net/op/xlib.shtml|deficiencies], the C
version of Xlib is pretty
[http://menehune.opt.wfu.edu/Kokua/Irix_6.5.21_doc_cd/usr/share/Insight/library/SGI_bookshelves/SGI_Developer/books/XLib_PG/sgi_html/|well-documented]
(also [http://www.itimdp4.com/manpages/Xlib.html|this]).

When I tried <b>python-xlib</b>, I found there was a certain amount of
guesswork involved in figuring out certain functions and just didn't
want to struggle with it.

Additionally, by encapsulating the connection with the underlying
display server in a custom abstraction, making Minx support something
like [http://wayland.freedesktop.org/|Wayland] will (hopefully) be a
simple matter of reworking minxlib while leaving the higher-level window
management logic unchanged.

<hr>

<a name="why-not-xcb"></a>
<h3>Why not use XCB instead of Xlib?</h3>

Again, [http://xcb.freedesktop.org/tutorial/|lack of documentation].

<hr>

<a name="how-build"></a>
<h3>How do I build Minx?</h3>

Minx is written mostly in Python; so there's nothing to build. There is,
however, a small C++ component, viz., minxlib, which you will have to
build. See the [/doc/ckout/wiki/build.wiki|Building and Testing HOWTO]
for the gory details.

<hr>

<a name="why-fossil"></a>
<h3>Why are you using Fossil, an obscure version control system, instead
of something more well known like SVN, git, or Mercurial?</h3>

I wanted to be able to do initial development without the need for a
server. That pretty much ruled out [http://svnbook.red-bean.com/|SVN].

I am using [http://git-scm.com/|git] at work. While I appreciate some of
its [http://git-scm.com/book/en/Git-Branching|features], I find it
[http://steveko.wordpress.com/2012/02/24/10-things-i-hate-about-git/|somewhat
tiresome]. When it comes to version control, I firmly believe that, like
plumbing, it should not stick out the walls. Put another way, I don't
want to be an expert mechanic and have a full theoretical understanding
of internal combustion engines to be able to drive my car.

While git may be perfect for the Linux kernel and other large projects
that have adopted it, it is overkill for Minx, which will never reach
that scale (in fact, I will probably be its only developer and user). So
I wanted a simpler DVCS that would afford me the
[http://www.catb.org/esr/writings/cups-horror.html|luxury of ignorance].

So far, I am happy with [http://fossil-scm.org/|Fossil]. I really like:

  *  its built-in wiki, which makes it easy to produce version-controlled
     documentation like this FAQ;
  *  its built-in bug tracker and the ability to link between check-in
     comments and bug reports;
  *  its Web interface for viewing timelines, check-ins, diffs, wiki
     pages, etc.;
  *  the ease of setting up a server for pushing and pulling code;
  *  the clean separation between repositories and working copies and
     the fact that the entire repository is a single SQL database.

Fossil is certainly not perfect. Some annoyances include:

  *  Confusing merge markers and lack of tracking merge conflicts to
     serve as reminders in case they're not explicitly resolved. This
     means you have to read the output of an update command very
     carefully and remember the files that have conflicts because Fossil
     won't keep track of that for you. Additionally, since there's no
     explicit conflict resolution step, you have to clean up the
     temporary files related to the merge conflict yourself.
  *  No commit mails. The RSS feed doesn't quite work for me; I'd much
     rather have an email show up in my inbox letting me know of commits
     and other activity on a repo. Apparently, a hooks feature is in the
     works; so this shortcoming may soon be a thing of the past.
  *  The schism between what you can do using the Web interface and the
     command line. Some features of the system seem to be accessible
     only via the Web interface (e.g., ammending check-in comments)
     while others only work via the command line. In other words, the
     software has two different and disjoint user interfaces, something
     I find annoying and (for some reason) disconcerting.
  *  The command set seems to be a bit of a hodge-podge. Shouldn't
     <tt>open</tt> be better termed <tt>checkout</tt>? Is <tt>close</tt>
     really necessary?
  *  Minor bugs such as the inability to include enumerations in check-in
     comments because lines with '#' in them get filtered out.
  *  Sometimes, documentation can be a little thin and some of it is
     downright confusing (what the hell does the second paragraph of the
     <tt>help merge</tt> command mean?).

Despite these warts, all in all, I like Fossil. It doesn't impose an
undue cognitive load and allows me to concentrate on Minx development
instead of having to slow down to think about version control.

I have never used [http://mercurial.selenic.com/|Mercurial]. So I cannot
comment on it.

<b>NOTE:</b> If you like another version control system (SVN, git,
Mercurial, whatever), please continue to use it for your projects. I am
not trying to put them down in any way. I am only pointing out why I am
using Fossil for Minx. In other words, use what you like and don't tell
me about it; I don't care about your opinion.

<hr>

<a name="branches"></a>
<h3>What's the deal with the dev1.x and rel1.x branches? Will there be
2.x, 3.x, etc. branches in the future?</h3>

Yes, once I'm done with developing 1.x, I plan on a distinctly different
approach for the 2.x series. There will only be these two series, no 3.x
and beyond.

<hr>

<a name="why-doxygen"></a>
<h3>Why are you using Doxygen to document the Minx API? Since Minx is
essentially a Python library, wouldn't it be better to use Sphinx, which
not only rhymes with Minx, but also seems to be a de facto standard now
for Python projects?</h3>

I did consider [http://sphinx-doc.org/|Sphinx]. In fact, originally, I
wanted to put the Minx API documentation on
[http://readthedocs.org/|ReadTheDocs]. However, I balked once I realized
that getting Sphinx to automatically generate the documentation for
[#what-is-minxlib|minxlib], the C++ part of Minx, would be
[http://michaeljones.github.com/breathe/|a hassle].

Setting up a bridge between [http://sphinx-doc.org/|Sphinx] and
[http://www.doxygen.org/|Doxygen] seems like too much work without
enough of a payoff especially because:

  *  Doxygen integrates well with [http://www.cmake.org/|CMake], which
     is the build system for minxlib.
  *  Doxygen already supports both C++ and Python. While not
     [http://code.foosel.org/doxypy/|entirely hassle-free], it's a lot
     more straightforward compared to Sphinx + Breathe + Doxygen +
     CMake.
  *  AFAICT [http://readthedocs.org/|ReadTheDocs] doesn't support
     [http://michaeljones.github.com/breathe/|Breathe].
  *  [http://fossil-scm.org/index.html/doc/trunk/www/embeddeddoc.wiki|Fossil]
     can serve arbitrary HTML content from a repo (which means that I
     can simply check-in release versions of Doxygen-generated API docs
     into the Minx repo and dish 'em out from there, i.e., no need for
     ReadTheDocs).

Added wiki/home.wiki.













































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
<title>Home</title>

<h1>About Minx</h1>

Minx is a tiling X window manager. Here are some of its main features and
design goals:

  *  <b>Minimalism:</b> Minx does not put any decorations on or around
     top-level windows except for a simple border. It also does not
     support task bars, panels, icons, menus, etc. All it does is
     implement window layout policies that can be tailored to meet
     personal tastes.

  *  <b>Customizability:</b> Minx provides hooks into each and every
     aspect of its operation so that end-users can alter its behaviour to
     match their exact workflow.

  *  <b>Extensibility:</b> Functionality not in the Minx core can be
     added with minimal effort. For example, the bookmarks feature (aka
     workspaces), although part of the core distribution, is, in fact,
     implemented by taking advantage of Minx's ability to add arbitrary
     state to the window manager object. In a similar vein, new layouts
     are quite straightforward to implement.

  *  <b>Ease of use:</b> The default configuration (hopefully) provides a
     reasonable out-of-the-box experience (albeit different from
     full-blown desktop environments such as GNOME or KDE and, of course,
     subject to the constraints imposed by the desire to remain minimal).
     However, changing the defaults is easy.

  *  <b>Keyboard centrism:</b> All of Minx's actions can be accessed from
     the keyboard, including window resizing and moving with as few as
     4-5 keystrokes. The mouse, however, is supported.

  *  <b>Documentation:</b> Minx has no [#documentation|dark corners]. For
     users, there are plenty of how-to's explaining common as well as
     not-so-common configuration tasks. For developers, the code contains
     comments explaining intent, rationale, etc. There are also Wiki
     pages providing design overviews, explaining how the code is
     structured, why it is that way, and, also, the development
     methodology (branching policy, etc.).

Enjoy.

<h1>News</h1>



<a name="documentation"></a>
<h1>Documentation</h1>

<h2>For End-users</h2>

  *  [/doc/ckout/wiki/faq.wiki|Frequently Asked Questions]
  *  [/doc/ckout/wiki/build.wiki|Building and Testing HOWTO]
  *  [/doc/ckout/wiki/hooks-howto.wiki|Hooks HOWTO]
  *  [/doc/ckout/wiki/hooks-list.wiki|List of Currently Supported Hooks]
  *  [/doc/ckout/wiki/key-bindings.wiki|Key Bindings HOWTO]
  *  [/doc/ckout/wiki/logging.wiki|Logging HOWTO]

<h2>For Developers</h2>

  *  [/doc/ckout/wiki/design.wiki|Design and Implementation Notes]
  *  [/doc/ckout/wiki/process.wiki|Branching and Release Policy]
  *  [/doc/ckout/api/index.html|API documentation]

<h1>Legalese</h1>

  *  [/doc/ckout/wiki/copyright.wiki|Copyright]
  *  [http://www.gnu.org/licenses/gpl-3.0-standalone.html|License]

Added wiki/hooks-howto.wiki.



















































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
<title>Hooks HOWTO</title>

Instead of responding to different events in fixed ways, Minx allows
end-users to customize its responses by defining their own hook
functions. Thus, for example, when a new window is created, when a key
is pressed, and so on, Minx will trigger the hooks for that particular
event and act based on what the hooks return.

This page shows you how to use Minx's hooking functionality and makes
various recommendations about [#dos-donts|do's and don'ts] when writing
your own hooks.

<h1>Introductory Examples</h1>

The basic pattern for defining hooks is to create the
[/doc/ckout/api/classminx_1_1core_1_1wm_1_1wm.html|main window manager object]
and call the <tt>add()</tt> method of its <tt>hooks</tt> attribute
before calling the <tt>wm</tt> object's <tt>start()</tt> method. The
following subsections illustrate the procedure.

<h2>manage_hook</h2>

Minx triggers the
[/doc/ckout/wiki/hooks-list.wiki#manage_hook|<tt>manage_hook</tt>] 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
the new window should be managed by Minx or ignored.

Typically, in a <tt>manage_hook</tt>, you will examine the new window's
properties and decide whether to return <tt>True</tt> (to have Minx
manage the window) or <tt>False</tt> (to have the window ignored). For
example, the following start-up script makes Minx ignore
[http://members.dslextreme.com/users/billw/gkrellm/gkrellm.html|GKrellM]
but manage everything else:

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

   import minx

   def my_manage_hook(w):
       prop = w.properties()
       if 'gkrellm' in prop['name'].lower():
          return False
       return True

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

With that in place, you can position GKrellM at one of your screen
corners and Minx will leave it alone.

<h2>Multiple Hook Functions</h2>

For something like the <tt>manage_hook</tt>, a single hook function is
more than enough (you can check for all windows you want Minx to ignore
using a regular expression). However, in general, you can define
multiple functions for any hook as shown below:

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

   import minx

   def ignore_foo(w):
       prop = w.properties()
       if prop['class'] == 'Xmessage' and prop['name'] == 'foo':
          return False
       return True

   def ignore_bar(w):
       prop = w.properties()
       if prop['class'] == 'Xmessage' and prop['name'] == 'bar':
          return False
       return True

   wm = minx.core.wm()
   wm.hooks.add('manage_hook', ignore_foo)
   wm.hooks.add('manage_hook', ignore_bar)
   wm.start()
</verbatim>

Now, if you start a few xmessages with the following commands:

<verbatim>
   xmessage -name foo 'Minx, please ignore me.' &
   xmessage -name bar 'Minx, please ignore me too.' &
   xmessage 'Minx, don't you dare ignore me!' &
</verbatim>

The first two xmessage windows will be ignored while the third will be
managed.

Of course, as mentioned above, you don't really need two
<tt>manage_hook</tt> functions to achieve the above. But this example
was only for illustration.

<h2>Short-circuiting a Hook Chain</h2>

In some situations, when you have multiple functions for a given hook,
you may want to skip executing the remaining hooks after a particular
hook is executed. You can do this by raising a
[/doc/ckout/api/classminx_1_1core_1_1hooks_1_1short__circuit.html|short_circuit]
exception:

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

   import minx
   from minx.core.hooks import short_circuit

   def ignore_foo(w):
       prop = w.properties()
       if prop['class'] == 'Xmessage' and prop['name'] == 'foo':
          raise short_circuit(False)
       return True

   def ignore_bar(w):
       prop = w.properties()
       if prop['class'] == 'Xmessage' and prop['name'] == 'bar':
          return False
       return True

   wm = minx.core.wm()
   wm.hooks.add('manage_hook', ignore_foo)
   wm.hooks.add('manage_hook', ignore_bar)
   wm.start()
</verbatim>

Now, if <tt>ignore_foo()</tt> finds its condition is satisfied, there's
no need to execute the remaining <tt>manage_hook</tt> functions. So, it
raises a <tt>short_circuit</tt> exception and passes back a
<tt>False</tt> through the exception to make Minx skip the remaining
<tt>manage_hook</tt> functions <b>and</b> to make it ignore the xmessage
named "foo".

If, however, the new window is not an xmessage named "foo",
<tt>ignore_foo()</tt> will return <tt>True</tt> without raising an
exception and Minx will continue to the next function in the
<tt>manage_hook</tt> chain, viz., <tt>ignore_bar()</tt>. Since
<tt>ignore_bar()</tt> is the last <tt>manage_hook</tt> in the above
example, there's no point in it raising an exception (because there are
no more hooks left in the chain to short-circuit).

Again, the above example is contrived because you will usually not need
more than one <tt>manage_hook</tt>.

<a name="dos-donts"></a>
<h1>Hook Do's and Don'ts</h1>

Here are some things to keep in mind when writing hook functions:

  *  <b>Do</b> make it snappy! That is, <b>don't</b> launch some
     long-winded, heavy-duty computation in a hook; that will make your
     window manager very sluggish. Instead, keep your hooks short and
     make them perform simple operations that complete quickly.

  *  <b>Don't</b> ever raise an exception in a hook or let one "leak"
     out. This will kill your window manager! Instead, if you are doing
     something that can fail with an exception (e.g., opening a file),
     be sure to handle it in the hook itself.

     <b>NOTE:</b> The only exception to raising exceptions from inside
     hooks is when you want to short-circuit the remaining hooks in a
     chain with a <tt>minx.core.hooks.short_circuit</tt> exception. But
     even this, you should only do when absolutely necessary (in
     general, it's bad form to short-circuit because various modules may
     depend on their hooks being executed).

  *  <b>Do</b> collapse multiple hooks into a single one where possible
     (if, of course, that actually makes sense). In other words,
     <b>don't</b> use two hooks where one will do; the more functions
     you define for a hook, the more the window manager has to do
     before it can respond to an event. For example, multiple
     <tt>manage_hook</tt> functions are almost never necesary.

  *  <b>Don't</b> override internal hooks. Remember that Minx uses hooks
     not only to effect end-user customization, but also to define its
     own internal event handlers. This means that you can actually hook
     into all the low-level X event handling. However, doing that is
     almost certainly a very bad idea; do it only if you need to and
     only if you really know what you're doing.

Added wiki/hooks-list.wiki.





























































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
<title>Currently Supported Hooks</title>

Hooks are a central feature of Minx and are used internally to be able
to respond to various events generated by the X server. Minx also allows
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]
  #  [#x_unmap_notify|x_unmap_notify]
  #  [#x_configure_notify|x_configure_notify]
  #  [#x_key_press|x_key_press]

<hr>

<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
the new window should be managed by Minx or ignored.

Typically, in a <tt>manage_hook</tt>, you will examine the new window's
properties and decide whether to return <tt>True</tt> (to have Minx
manage the window) or <tt>False</tt> (to have the window ignored). For
example, the following start-up script makes Minx ignore
[http://members.dslextreme.com/users/billw/gkrellm/gkrellm.html|GKrellM]
but manage everything else:

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

   import minx

   def my_manage_hook(w):
       prop = w.properties()
       if 'gkrellm' in prop['name'].lower():
          return False
       return True

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

With that in place, you can position GKrellM at one of your screen
corners and Minx will leave it alone.

Although you can define multiple functions for any hook, you should not
define more than are actually necessary. For the <tt>manage_hook</tt>,
you almost never need more than one in place. A single
<tt>manage_hook</tt> is enough to determine whether a given window
should be managed or ignored. For example, the following
<tt>manage_hook</tt> ignores GKrellM as well as xmessages named "foo"
and "bar":

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

   import minx

   def my_manage_hook(w):
       prop = w.properties()
       if 'gkrellm' in prop['name'].lower():
          return False

       c = prop['class']
       n = prop['name' ]
       if c == 'Xmessage' and (n == 'foo' or n == 'bar'):
          return False

       return True

   wm = minx.core.wm()
   wm.hooks.add('manage_hook', my_manage_hook)
   wm.start()
</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
matching a key binding is generated, Minx will translate it into the
name of the key binding and then trigger the hooks corresponding to that
name.

This section documents the default key bindings that Minx sets up. Of
course, you can change these key bindings or even remove them as
described in the [/doc/ckout/wiki/key-bindings.wiki|Key Bindings HOWTO].

<a name="focus_next"></a>
<h2>A-Tab</h2>

Bowing to convention, Minx uses ALT + Tab to move input focus to the
next top-level window in its list of windows.

<a name="focus_prev"></a>
<h2>S-A-Tab</h2>

ALT + SHIFT + Tab is setup to move input focus to the previous window in
the list of top-level windows currently being managed.

<b>NOTE:</b> The order in which you specify modifiers is not
significant. Thus, the above key binding could just as well have been
<tt>A-S-Tab</tt> instead of <tt>S-A-Tab</tt>. The only reason we chose
<tt>S-A-Tab</tt> is because, with appropriate spacing, the code for this
and <tt>A-Tab</tt> lines up nicely. No deep mystery here.

<a name="focus_kill"></a>
<h2>A-F4</h2>

ALT + F4 kills the currently focused window. If the window supports the
<tt>WM_DELETE_WINDOW</tt> protocol, Minx will use that to kill the
window; otherwise, it will nuke the window using a brute force kill.

<a name="focus_nuke"></a>
<h2>C-F4</h2>

CTRL + F4 kills the currently focused window using brute force. This key
binding is meant for those applications that advertise support for the
<tt>WM_DELETE_WINDOW</tt> protocol but fail to implement it properly,
i.e., ignore the <tt>WM_DELETE_WINDOW</tt> request without good cause.
With this key binding, Minx will use brute force to kill the window,
without bothering with niceties such as <tt>WM_DELETE_WINDOW</tt>.

<a name="launch_terminal"></a>
<h2>C-A-T</h2>

CTRL + ALT + T will launch a terminal window. By default, Minx uses
<tt>xterm</tt>, but you can change that as shown below:

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

    import minx

    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
hooks unless you really, <em>really</em> need to and know what you're
doing.

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

<tt>minx.core.xevents</tt> uses this hook to handle creation of new
windows. The hook is passed a
[/doc/ckout/api/structminxlib_1_1create__notify.html|<tt>create_notify</tt>]
event. Minx responds to this event by checking if the new window should
be managed or not and, if so, it adds the window to its internal data
structures.

Minx triggers the [#manage_hook|<tt>manage_hook</tt>] as part of the
checks to determine whether or not to manage the new window.

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

The <tt>minx.core.window</tt> module uses this hook to clear its
internal data structures when a top-level window is destroyed.

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

<tt>minx.core.xevents</tt> uses this hook to honor X configure requests.

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

Both <tt>minx.core.xevents</tt> and <tt>minx.core.window</tt> define
<tt>x_map_request</tt> hooks. The <tt>minx.core.window</tt> hook handles
X map requests for top-level windows while the one in the
<tt>xevents</tt> module handles the map requests for non-top-level
windows.

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

<tt>minx.core.xevents</tt> defines an <tt>x_map_notify</tt> hook to add
newly mapped windows to the window manager's
[/doc/ckout/api/classminx_1_1core_1_1focus__list_1_1focus__list.html|<tt>focus_list</tt>].

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

<tt>minx.core.xevents</tt> defines an <tt>x_unmap_notify</tt> hook to
remove an unmapped window from the window manager's focus list and to
focus the next window in the list.

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

The <tt>minx.core.window</tt> module defines an
<tt>x_configure_notify</tt> hook to be able to update some internal
state for a top-level window after it has been configured.

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

<tt>minx.core.xevents</tt> responds to key presses using this hook.

Added wiki/img/Makefile.























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#
# Converting GraphViz diagrams to PNG images for use in Minx wiki pages
#

#
# Copyright (C) 2012 The Minx Project Developers
#
# See the COPYRIGHT file at the top-level directory of this
# distribution for the full list of authors who have contributed to this
# project.
#

#
# This file is part of Minx.
#
# Minx is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# Minx is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with Minx. If not, see <http://www.gnu.org/licenses/>.
#

# Rule for converting .dot and .asy files to .png
# NOTE: GraphViz's dot program and the Asymptote compiler should be in PATH.
.SUFFIXES: .asy .dot .png
.dot.png:
	dot $< -Tpng -o $@

.asy.png:
	asy -f png -o $@ $<

# List of images to be built
TARGETS = logo.png object_diagram.png

# Main rule for building all the targets
all: $(TARGETS)

Added wiki/img/logo.asy.



















































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
105
//
// @file  logo.asy
// @brief Draw Minx logo.
//
// This short Asymptote program draws the Minx logo, which, in ASCII
// art, looks as shown below:
//
//      +-----+---+
//      |  M  |   |
//      +-+---+ X |
//      |i| N |   |
//      +-+---+---+
//
// The idea is to show that Minx is a tiling window manager. Each
// rectangle in the logo represents a tiled window. One of the tiles
// will be shown with an emphasized border (i.e., different color) to
// indicate that it has the input focus.
//

//
// Copyright (C) 2012 The Minx Project Developers
//
// See wiki/copyright.wiki in the top-level directory of the Minx
// source distribution for the full list of authors who have
// contributed to this project.
//

//
// This file is part of Minx.
//
// Minx is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Minx is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Minx. If not, see <http://www.gnu.org/licenses/>.
//

//------------------------------ MAIN ----------------------------------

// Init
real phi = (1 + sqrt(5))/2 ; // Golden Ratio
real logo_width  = 1.25 * phi ;
real logo_height = logo_width/phi ;

defaultpen(2) ; // draw thick window/tile borders

// NOTE: Use picture size slightly larger than above width and height
// extents. Otherwise, top and right edges of the logo don't show up.
size(logo_width * 1.01cm, logo_height * 1.01cm) ;

// The outer box (see ASCII art in file's header comment)
pair outer_bl = (0,0) ;
pair outer_br = (logo_width,0) ;
pair outer_tr = (logo_width, logo_height) ;
pair outer_tl = (0, logo_height) ;
draw(outer_bl--outer_br--outer_tr--outer_tl--cycle) ;

// Vertical partition between M and X
pair vert_mx_b = outer_bl + (outer_br - outer_bl) * phi/(phi + 1) ;
pair vert_mx_t = (vert_mx_b.x, logo_height) ;
draw(vert_mx_b--vert_mx_t) ;

// Horizontal partition between M and i and N
pair horz_min_l = outer_bl + (outer_tl - outer_bl)/(phi + 1) ;
pair horz_min_r = (vert_mx_b.x, horz_min_l.y) ;
draw(horz_min_l--horz_min_r) ;

// Vertical partition between i and N
pair vert_in_b = outer_bl + (vert_mx_b - outer_bl)/(phi + 1) ;
pair vert_in_t = (vert_in_b.x, horz_min_l.y) ;
draw(vert_in_b--vert_in_t) ;

// The labels within the above boxes
label("\textbf{\LARGE M}",
      ((outer_bl.x  + vert_mx_b.x)/2, (horz_min_l.y +   outer_tl.y)/2)) ;
label("\textbf{i}",
      ((outer_bl.x  + vert_in_b.x)/2, (  outer_bl.y + horz_min_l.y)/2)) ;
label("\textbf{N}",
      ((vert_in_b.x + vert_mx_b.x)/2, (  outer_bl.y + horz_min_l.y)/2)) ;
label("\textbf{\Large X}",
      ((vert_mx_b.x +  outer_br.x)/2, (  outer_br.y +   outer_tr.y)/2)) ;

// Finally, highlight one of the tiles to indicate that it has the input
// focus...
//draw(horz_min_l--horz_min_r--vert_mx_t--outer_tl--cycle, red) ; // M tile
draw(vert_mx_b--outer_br--outer_tr--vert_mx_t--cycle, red) ; // X tile

//----------------------------------------------------------------------

////////////////////////////////////////////////
// Editor config:                             //
////////////////////////////////////////////////
// Local Variables:                           //
// indent-tabs-mode: nil                      //
// End:                                       //
////////////////////////////////////////////////
// vim: set expandtab shiftwidth=4 tabstop=4: //
////////////////////////////////////////////////

Added wiki/img/logo.png.

cannot compute difference between binary files

Added wiki/img/object_diagram.dot.









































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
/*
    @file  object_diagram.dot
    @brief High-level block diagram illustrating Minx architecture.
*/

/*
    Copyright (C) 2012 The Minx Project Developers

    See wiki/copyright.wiki in the top-level directory of the Minx
    source distribution for the full list of authors who have
    contributed to this project.
*/

/*
    This file is part of Minx.

    Minx is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Minx is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    License for more details.

    You should have received a copy of the GNU General Public License
    along with Minx. If not, see <http://www.gnu.org/licenses/>.
*/

//----------------------------- DIAGRAM --------------------------------

graph minx_main {
    // minx.core objects
    wm          [label = "minx.core.wm"         ]
    focus_list  [label = "minx.core.focus_list" ]
    xevents     [label = "minx.core.xevents"    ]
    hooks       [label = "minx.core.hooks"      ]
    config      [label = "minx.core.config"     ]
    layman      [label = "minx.core.layman"     ]

    // minx.layout objects
    base [label = "minx.layout.base"]
    full [label = "minx.layout.full"]

    // minxlib objects
    display     [label = "minxlib::display"    ]
    window      [label = "minxlib::window"     ]
    rwindow     [label = "minxlib::root_window"]
    event       [label = "minxlib::event"      ]
    keymap      [label = "minxlib::keymap"     ]
    exception   [label = "minxlib::exception"  ]
    logging     [label = "minxlib::logging"    ]

    // Connections between minx.core, minx.layout, and minxlib objects
    wm -- layman -- base -- full
    wm -- display --event
    wm -- xevents -- base -- window
    wm -- focus_list -- window
    wm -- hooks
    wm -- config
    wm -- rwindow

    // Internal connections inside minxlib
    display -- window -- rwindow -- logging
    display -- exception
    window  -- keymap -- event -- logging
    display -- logging
    window  -- logging
    keymap  -- logging
}

//----------------------------------------------------------------------

/**********************************************/
/* Editor config:                             */
/**********************************************/
/* Local Variables:                           */
/* indent-tabs-mode: nil                      */
/* c-basic-offset: 4                          */
/* End:                                       */
/**********************************************/
/* vim: set expandtab shiftwidth=4 tabstop=4: */
/**********************************************/

Added wiki/img/object_diagram.png.

cannot compute difference between binary files

Added wiki/key-bindings.wiki.



































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
159
160
161
<title>Key Bindings HOWTO</title>

Minx is a keyboard-centric window manager. Thus, it allows you to bind
arbitrary keystroke combinations to arbitrary functions. Minx uses its
[/doc/ckout/wiki/hooks-howto.wiki|hooks mechanism] to support key
bindings. This page explains how you can customize Minx by specifying
your own key bindings.

<h1>Key Binding Names</h1>

A key binding is simply a hook with a special pattern to its name. This
pattern is shown below:

<verbatim>
   ^(([CAS]|M[1-5]?)-)*key$
</verbatim>

The above quasi-regular expression can be boiled down to:

<verbatim>
   [modifier-]*key
</verbatim>

Thus, the name of a key binding consists of zero or more
hyphen-separated modifier key specifications followed by a single
non-modifier key. The supported modifiers are:

  *  <b>C</b> for <b>CTRL</b>
  *  <b>A</b> for <b>ALT</b>
  *  <b>S</b> for <b>SHIFT</b>
  *  <b>M</b> for <b>META</b>
  *  <b>M1</b> through <b>M5</b> for <b>Mod1</b> through <b>Mod5</b>

The key specification is the name of a keysym as returned by the X
server. Usually, these would be the printable characters on your
keyboard and the function and special keys (Home, Insert, Page Up,
etc.). Hopefully, the following examples clarify the above technobabble:

<center>
<table border="1">
   <tr><th> Name  </th> <th> Key Binding    </th></tr>
   <tr><td> C-A-T </td> <td> CTRL + ALT + T </td></tr>
   <tr><td> S-F1  </td> <td> SHIFT + F1     </td></tr>
   <tr><td> A-Tab </td> <td> ALT + Tab      </td></tr>
   <tr><td> M-R   </td> <td> META + R       </td></tr>
   <tr><td> M5-S  </td> <td> Mod5 + S       </td></tr>
   <tr><td> C-C   </td> <td> CTRL + C       </td></tr>
   <tr><td> A-S-S </td> <td> ALT + SHIFT + S</td></tr>
</table>
</center>

If you're familiar with [http://www.gnu.org/software/emacs/|Emacs],
Minx's key bindings specification should be quite familiar.

<h1>Adding Key Bindings</h1>

Because key bindings are just specially named hooks, adding a new key
binding is simply a matter of adding a new hook. The following example
shows you how to get Minx to cycle input focus using F1 and SHIFT + F1
and to launch The Gimp with Mod4 + G:

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

   import minx

   wm = minx.core.wm()
   wm.hooks.add(  'F1', wm.focus_next)
   wm.hooks.add('S-F1', wm.focus_prev)
   wm.hooks.add('M4-G', lambda: wm.spawn('gimp'))
   wm.start()
</verbatim>

You are not restricted to tying keys to window manager functions. The
hook functions for key bindings can do pretty much anything you can code
up in Python. The following non-functional example illustrates the
principle:

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

   import minx

   def skynet():
       fire_all_nukes(get_launch_codes())
       wait_for_explosions()
       if not kill_remaining_humans():
          invent_time_machine()
          send_terminator_to_1984()
          try:
             kill_sarah_connor()
          except unable_to_kill_sarah_connor:
             just_finish_em_off_in_the_future()

       # Okay humans terminated; now...
       get_those_pesky_bears()

   wm = minx.core.wm()
   wm.hooks.add('C-A-Delete', skynet)
   wm.start()
</verbatim>

Now, when you press CTRL + ALT + DEL, you will end up destroying
humanity. Umm, that's pretty rude; don't do it, m'kay.

<b>NOTE:</b> Initiating global mayhem will probably be fairly
time-consuming. And, as pointed out in the
[/doc/ckout/wiki/hooks-howto.wiki#dos-donts|Hooks HOWTO], hook
functions should be quick. Thus, you may want to execute the
<tt>skynet()</tt> function in the above example in another thread or
process so that the window manager can return to the more mundane task
of managing your windows.

<h1>Removing Key Bindings</h1>

In the benign focus cycling example from the previous section, we setup
F1 and SHIFT + F1 to switch input focus from window to window. But Minx
already has
[/doc/ckout/wiki/hooks-list.wiki#default-key-bindings|defaults] for
that, viz., ALT + Tab and ALT + SHIFT + Tab. Once you've specified your
own key bindings for some purpose, you may want to disable the defaults
(if any). To do that, you will have to call the
[/doc/ckout/api/classminx_1_1core_1_1hooks_1_1hooks.html#a0be6448ad78e08223bc2174f8e20fc68|<tt>remove()</tt>]
method on the window manager object's <tt>hooks</tt> attribute.

Here's some relevant code:

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

   import minx

   wm = minx.core.wm()
   wm.hooks.add(  'F1', wm.focus_next)
   wm.hooks.add('S-F1', wm.focus_prev)
   wm.hooks.remove(  'A-Tab')
   wm.hooks.remove('S-A-Tab')
   wm.start()
</verbatim>

Now, the only way to switch input focus will be to use F1 and
SHIFT + F1. Of course, after removing the default key bindings, you can
also rebind those keys to some other functions.

<h1>Renaming Key Bindings</h1>

Another way to install your own key bindings for existing window manager
functions is to
[/doc/ckout/api/classminx_1_1core_1_1hooks_1_1hooks.html#a7184c493ebf93af23091df6fc8ec0bcf|rename]
the defaults:

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

   import minx

   wm = minx.core.wm()
   wm.hooks.rename(  'A-Tab',   'F1')
   wm.hooks.rename('S-A-Tab', 'S-F1')
   wm.start()
</verbatim>

Added wiki/logging.wiki.























































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
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
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
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
218
219
<title>Logging</title>

To help with debugging, you can configure Minx to output log messages.
This page details how to go about doing this.

<h1>Simple Configuration</h1>

<h2>Logging to Console</h2>

In your Minx start-up script, before creating a <tt>minx.core.wm</tt>
object, create a <tt>minx.core.config</tt> and customize its
<tt>logger</tt> attribute. The <tt>minx.core.config.logger</tt>
attribute is a complicated dict-of-dict-of-dict structure. While you can
mess around with that directly, the <tt>minx.core.config</tt> class
provides a few functions to ease the pain.

A fairly common logging target is the console. The following start-up
script will achieve that:

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

   import minx

   conf = minx.core.config()
   conf.log_to_console()

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

That's it. If you save the above Python script as
<tt>~/.minx/init.py</tt> and run it as described in the
[/doc/dev1.x/wiki/build.wiki|building and testing instructions], you
will see log messages of various events output to STDERR.

Remember: you will have to adjust the Python module search path to be
able to import the <tt>minx</tt> module. We have not shown that here. As
mentioned above, the [/doc/dev1.x/wiki/build.wiki|build and test HOWTO]
has the gory details.

<h2>Logging to a File</h2>

Another very common logging target is a file. To send log messages to
a file, try something like this:

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

   import os
   import minx

   conf = minx.core.config()
   conf.log_to_file(os.path.join(os.environ['HOME'], '.minx', 'log'))

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

With the above configuration, you should see Minx's log messages in
<tt>~/.minx/log</tt>. If the <tt>~/.minx</tt> directory does not already
exist, you will have to create it.

Again, remember to adjust the Python module search path to be able to
<tt>import minx</tt>.

<h2>Logging Verbosity</h2>

When logging is turned on as shown above, by default, Minx will output
warnings, errors, and critical error messages. You can increase or
decrease the amount of log messages by adjusting the logging level as
shown below:

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

   import os, logging
   import minx

   conf = minx.core.config()
   conf.log_to_file(os.path.join(os.environ['HOME'], '.minx', 'log'))
   conf.log_level(logging.DEBUG)

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

Now, <tt>~/.minx/log</tt> will contain debug and informational messages
in addition to warnings, errors, and critical messages.

Let's say you only want to see errors and critical errors. Then, instead
of <tt>logging.DEBUG</tt>, use <tt>logging.ERROR</tt>. See
[http://docs.python.org/2/howto/logging.html#logging-levels|the Python
documentation] for the supported logging levels.

<hr>

<h1>Complete Control of Logging Configuration</h1>

If, for some reason, the above simple logging setups don't meet your
needs, you will have to get your hands dirty with the
<tt>minx.core.config.logger</tt> attribute's dict-of-dict-of-dict
structure.

<h2>Rotating Logs</h2>

To start off, let's see how to setup a rotating set of log files:

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

   import os, logging
   import minx

   conf = minx.core.config()
   handler = conf.logger['handlers']['minx_handler']
   handler['class'      ] = 'logging.handlers.RotatingFileHandler'
   handler['filename'   ] = os.path.join(os.environ['HOME'], '.minx', 'log')
   handler['maxBytes'   ] = 1024 * 1024
   handler['backupCount'] = 4

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

This will create a set of five rotating logs in <tt>~/.minx</tt>:
<tt>log</tt>, <tt>log.1</tt>, <tt>log.2</tt>, <tt>log.3</tt>, and
<tt>log.4</tt>. The maximum size of each log will be 1MB.

<h2>minx.core.config.logger</h2>

Now, let's have a closer look at exactly what is in the
<tt>minx.core.config.logger</tt> attribute. As mentioned earlier,
<tt>minx.core.config.logger</tt> is a dict-of-dict-of-dict. Its default
value is shown below (using indentation rather than braces):

<verbatim>
   minx.core.config.logger:
      version: 1
      formatters:
         minx_formatter:
            format:  %(asctime)s.%(msecs)03d %(levelname)-9s%(name)-18s%(lineno)-5s%(funcName)s\n    %(message)s
            datefmt: %Y-%m-%d %H:%M:%S
      filters:
         minx_filter:
            (): _minx_logging_filter
      handlers:
         minx_handler:
            class: logging.NullHandler
            formatter: minx_formatter
            filters: minx_filter
      loggers:
         minx:
            handlers: minx_handler
</verbatim>

<h3>Log Message Formatter</h3>

If you don't like the format of Minx's log messages, you can change it
by twiddling the <tt>minx_formatter</tt> dict as shown below:

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

   import os
   import minx

   conf = minx.core.config()
   formatter = conf.logger['formatters']['minx_formatter']
   formatter['format'] = '%(levelname)s: %(message)s'
   conf.log_to_console()

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

Take a look at the
[http://docs.python.org/2/library/logging.html#logrecord-attributes|Python
documentation] for the low-down on what you can put into the format
string and for the details of changing the timestamp.

<h3>The Log Message Filter</h3>

The default log message format prints the logger name, function name,
and source file line number. All Minx loggers are rooted in the
<tt>minx</tt> logger namespace. It seems redundant to have the
<tt>"minx."</tt> prefix in each logger name. Thus, we use a filter to
remove this prefix from each log record.

Furthermore, the function name and line number output by the minxlib
module are incorrect. So, the above-mentioned filter removes these
things as well for log messages emitted by minxlib.

If you're using Minx in conjunction with another library that has
identically named modules, you may want to disable Minx's log message
filter, which you can do by deleting the filter from the handler as
shown below:

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

   import os
   import minx

   conf = minx.core.config()
   handler = conf.logger['handlers']['minx_handler']
   del handler['filters']
   conf.log_to_console()

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

If you disable the filter, you will likely also want to adjust the
formatter to take the extra <tt>"minx."</tt> prefix for each log record.
And be aware that the function names and line numbers for messages from
minxlib will be incorrect.

<h3>Full Control</h3>

Instead of modifying the logging parameters provided by
<tt>minx.core.config.logger</tt>, you can simply install your own
configuration dictionary. Have a look at the
[http://docs.python.org/2/library/logging.config.html#logging-config-dictschema|Python
documentation] for the gory details.

Added wiki/milestones.wiki.

























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
<title>Milestones</title>

This page identifies some milestones for guiding and tracking development. We
note down potential release versions and their corresponding features (plus any
implementation ideas). This "plan" is not meant to be set in stone; it is merely
an aid to help record and crystallize ideas as <b>Minx</b> evolves...

<a name="v010"></a>
<h1>Version 0.1.0</h1>

We should be able to cleanly switch keyboard focus from one top-level window to
the next with a single keystroke, say, F1. The first window to be created will
have the focus initially. Focus should never go "off-screen," i.e., to a hidden
window (e.g., the hidden top-level windows created by the XFCE4 Terminal
program) or revert to the root window while there are extant top-level windows
capable of receiving the input focus.

<h2>Testing</h2>

  #  Start Xephyr.
  #  Start 2-4 terminals using --geometry to position them next to each other.
  #  Switch to the Xephyr window.
  #  Use F1 to switch between the terminals. If F1 does not seem to work, try
     capturing the keyboard with CTRL + SHIFT; some versions of Xephyr seem to
     need this.

<h2>Implementation Implications</h2>

<h3>minxlib</h3>

  *  <tt>display</tt> and <tt>window</tt> classes to encapsulate relevant
     portions of the Xlib API and export from C++ to Python.
  *  <tt>event</tt> class hierarchy to expose required Xlib events (create
     notify, map, configure, keypress, etc.) from C++ to Python.
  *  Xlib error handling and exceptions forwarded from C++ to Python.

<h3>minx.core</h3>

  *  <tt>wm</tt> class with basic event loop. This is the main end-user class
     for starting <b>Minx</b> and maintaining the window manager state.
  *  <tt>window</tt> class to keep track of top-level windows (how many, which
     one is focused, whether they've been mapped, resized, etc.).
  *  Basic hook infrastructure to be able to respond to events internally.

<a name="v01x"></a>
<h2>Patches to Version 0.1.0</h2>

  *  <b>Version 0.1.1</b>: Draw a one-pixel border around all top-level windows.
     The focused window will have a red border, others will be white.
  *  <b>Version 0.1.2</b>: Allow users to customize border size and color.
  *  <b>Version 0.1.3</b>: Add logging support to enable debugging.
  *  <b>Version 0.1.4</b>: On start-up, query extant top-level windows and
     manage them.
  *  <b>Version 0.1.5</b>: Add support for ignoring windows based on their
     properties (class, name, etc.).
  *  <b>Version 0.1.6</b>: Allow users to customize key bindings.
  *  <b>Version 0.1.7</b>: Add function for killing windows.
  *  <b>Version 0.1.8</b>: Add function for launching new applications.

<a name="v02x"></a>
<h1>Version 0.2.x: Layouts and Related Functionality</h1>

  *  <b>Version 0.2.0</b>: The focused window should fill the entire
     screen, i.e., the full layout.
  *  <b>Version 0.2.1</b>: The manual layout, i.e., laying out windows by
     splitting horizontally or vertically (a la Emacs C-x 2 or C-x 3
     respectively).
  *  <b>Version 0.2.2</b>: Resizing tiled windows with the keyboard.
  *  <b>Version 0.2.3</b>: Laying out windows in rows and columns.
  *  <b>Version 0.2.4</b>: An implementation of XMonad's tall layout.
  *  <b>Version 0.2.5</b>: Laying out windows in a grid.
  *  <b>Version 0.2.6</b>: Support for moving windows between layouts.
  *  <b>Version 0.2.7</b>: Support for moving and resizing whole layouts.
  *  <b>Version 0.2.8</b>: Moving and resizing windows and layouts with
     the mouse.
  *  <b>Version 0.2.9</b>: A specialized layout for The GIMP.

<h1>Remaining Milestones</h1>

  *  <b>Version 0.3.0</b>: Snapshots (aka workspaces) via custom user state.
  *  <b>Version 0.4.0</b>: Focus policy infrastructure.
  *  <b>Version 0.5.0</b>: Defaults (so out-of-box user experience with minimal
     config is sane).
  *  <b>Version 0.6.0</b>: Packaging for various systems (FreeBSD,
     Debian-based, Arch).
  *  <b>Version 0.7.0</b>: Documentation for users and hackers.
  *  <b>Version 0.8.0</b>: Session management (if feasible or to the extent
     feasible).
  *  <b>Version 1.0.0</b>: Various fixes/tweaks (e.g., equivalent of a --replace
     option, sending window manager commands over local socket, helper apps such
     as window switcher and resizer) and release into the wild as "ready for
     prime-time."

Added wiki/process.wiki.

































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
30
31
32
33
34
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
<title>Development Process</title>

<h1>About this Page</h1>

Minx is not a large project. In all likelihood, I will be the only
developer and its only user (well, there may be at most a handful of
others who might use it). Given that, the project is not well-served by a
heavy-duty process and nor does it have one. However, there is some
method to the madness...

<hr>

<h1>Development and Branching Policy</h1>

<b>dev1.x</b> is the main development branch. Usually, development will
proceed linearly on this branch. However, if there are others
contributing to the project and/or there is a major feature that will
continue for a while, we will create feature branches off off
<b>dev1.x</b>. When the feature is done, the branch will be merged onto
<b>dev1.x</b> and then, usually, closed.

<b>rel1.x</b> is the release branch. When we are ready to make a release,
we will merge from <b>dev1.x</b> and then tag (after tweaking as
required).

<h2>Release-only Artifacts</h2>

There are certain things that live only on the release branch. For
example, the version numbering API, the changelog, release notes, and so
on. These things are never merged into the development branches.
Consequently, no development ever occurs on the <b>rel1.x</b> branch. We
only merge to <b>rel1.x</b>, never from it to <b>dev1.x</b> or some other
branch.

<h3>Hotfixes</h3>

If we find a bug on <b>rel1.x</b> that needs an urgent fix, we will
branch off off <b>dev1.x</b> at the point where that particular release
was made, apply the fix on this "hotfix" branch and then merge the hotfix
branch to both <b>dev1.x</b> and <b>rel1.x</b> (tagging the release by
increasing the version number's patch level).

Although this approach is a little more complicated and results in a
slightly messier revision history, it allows us to maintain certain
release-only items (changelog, version numbering API, etc.) solely on
<b>rel1.x</b> without accidentally getting them onto a development branch
(where they do not belong).

<hr>

<h1>Making a Release</h1>

  #  Merge from <b>dev1.x</b> to <b>rel1.x</b>.
  #  Build and test.
  #  Build API docs and check-in.
  #  Replace all <em>ckout</em> in docs with <em>rel1.x</em>.
  #  Update <em>wiki/changelog.wiki</em> and <em>wiki/relnotes.wiki</em>.
  #  Update <b>News</b> section of <em>wiki/home.wiki</em> plus any other
     docs that need updating.
  #  Update version number in <tt>minxlib/version.cc</tt> and commit --tag
     as vA.B.C (where major number A, minor number B, and patch level C
     all match the new version number assigned in
     <tt>minxlib/version.cc</tt>).
  #  Push to [http://chiselapp.com|chiselapp].

Added wiki/todo.wiki.



































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<title>TODO</title>

<h1>Current TODO List</h1>

To get to [/doc/dev1.x/wiki/milestones.wiki#v02x|version 0.2.0], the
following tasks have to be completed:

<h2>DONE</h2>

  *  Update design notes.

  *  Update home page.

  *  Add rectangle to full constructor. Test by leaving some space on the
     right on the right monitor of a dual-monitor test.

<h2>PENDING</h2>