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-->  <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><<em>minxdude@gmail.com</em>></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> |