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 do's and don'ts when writing your own hooks.
The basic pattern for defining hooks is to create the main window manager object and call the add() method of its hooks attribute before calling the wm object's start() method. The following subsections illustrate the procedure.
Minx triggers the manage_hook when a new window is created. It will pass to each manage_hook a minxlib.window object and expects a True or False return value to decide whether the new window should be managed by Minx or ignored.
Typically, in a manage_hook, you will examine the new window's properties and decide whether to return True (to have Minx manage the window) or False (to have the window ignored). For example, the following start-up script makes Minx ignore GKrellM but manage everything else:
#!/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()
With that in place, you can position GKrellM at one of your screen corners and Minx will leave it alone.
Multiple Hook Functions
For something like the manage_hook, 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:
#!/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()
Now, if you start a few xmessages with the following commands:
xmessage -name foo 'Minx, please ignore me.' & xmessage -name bar 'Minx, please ignore me too.' & xmessage 'Minx, don't you dare ignore me!' &
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 manage_hook functions to achieve the above. But this example was only for illustration.
Short-circuiting a Hook Chain
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 short_circuit exception:
#!/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()
Now, if ignore_foo() finds its condition is satisfied, there's no need to execute the remaining manage_hook functions. So, it raises a short_circuit exception and passes back a False through the exception to make Minx skip the remaining manage_hook functions and to make it ignore the xmessage named "foo".
If, however, the new window is not an xmessage named "foo", ignore_foo() will return True without raising an exception and Minx will continue to the next function in the manage_hook chain, viz., ignore_bar(). Since ignore_bar() is the last manage_hook 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 manage_hook.
Hook Do's and Don'ts
Here are some things to keep in mind when writing hook functions:
- Do make it snappy! That is, don't 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.
- Don't 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.
NOTE: The only exception to raising exceptions from inside hooks is when you want to short-circuit the remaining hooks in a chain with a minx.core.hooks.short_circuit 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).
- Do collapse multiple hooks into a single one where possible (if, of course, that actually makes sense). In other words, don't 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 manage_hook functions are almost never necesary.
- Don't 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.