Design and Implementation Notes
The following diagram shows a high-level view of the different classes and roughly how they're connected to each other.
The minx.core and minx.layout classes are written in Python whereas the minxlib classes are written in C++ and exposed to Minx's Python core.
The organization of the code mirrors the above diagram. All the minx.core classes are in the minx/core directory, the minx.layout classes in minx/layout, and the minxlib classes are in the minx/minxlib directory.
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 wm object, you can supply a config 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 wm.hooks object. For layouts, you can deal with the wm.layouts object, which is an instance of the minx.core.layman class.
After these setup steps, call wm.start() to run the window manager. The start() method connects to the X server by creating a minxlib::display 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 minx.core.xevents object, which has the necessary event handler callbacks.
X errors are handled by minx.core.wm as part of its event loop.
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 "x_something" (x_map_request, x_create_notify, etc.). Most end-user hooks are of the form "some_hook". Key bindings are also handled as hooks (their names are not of the form "some_hook"; they follow a different pattern).
All objects within the system that have a reference to the wm 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).
The xevents class is a simple helper. Initially, all the X event handlers were in minx.core.wm. But that made wm too big. So we split the event handlers into their own class, viz., minx.core.xevents.
When end-user code instantiates minx.core.wm, the wm constructor creates an xevents object, passing it a reference to itself. Through this reference to wm, xevents is able to add its handlers to wm.hooks.
Now, when wm gets events from the X server, it triggers the appropriate handler in xevents via its map of hooks.
This class implements a layout manager, which keeps track of the different layouts. The layman class maintains a list of layout objects and provides an API for adding layouts, looking for them, and so on.
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 focus_list by the xevents object. This usually happens when the X server sends a MapNotify event for a top-level window to Minx. When minx.core.wm receives an UnmapNotify for a top-level window, xevents will remove the corresponding minxlib::window from the focus_list.
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 config object should be passed to the minx.core.wm constructor. Any object that has a reference to the wm object can then get at its config instance to access the different settings.
If end-users do not create a custom config, Minx will use default values for all its supported customizations.
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 minx.layout.base module contains a few event handlers for various bits of layout related functionality.
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.
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 python-xlib instead of writing our own custom Xlib wrapper. Unfortunately, the 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 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.
The display 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.
minxlib::window and minxlib::root_window
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 root_window class is derived from minxlib::window and provides an encapsulation of X's root windows, taking into account support for Xinerama. Minx provides one root_window for each physical screen. If Xinerama is active, there'll only be one logical screen; however, Minx will return multiple root_window objects, each with the same X ID but different geometries.
minxlib::event and minxlib::exception
These two classes provide an object-oriented interface to X events and errors. Different types of events are converted into instances of subclasses of minxlib::event. Similarly, different kinds of errors are converted into instances of classes derived from minxlib::exception (which, on the Python side, is derived from Python's Exception 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.
The keymap 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.
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 logging module. The minxlib::logging class provides a C++ logging API that uses the Python logging 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 minxlib::logging 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.