Mapping arbitrary key types to callable objects. More...
Public Member Functions | |
def | __init__ |
Create an empty hook map. More... | |
def | add |
Add a new function for some key. More... | |
def | remove |
Remove all hooks for specified name. More... | |
def | rename |
Rename the specified hook. More... | |
def | trigger |
Execute functions for a given key. More... | |
def | names |
Get names of currently defined hooks. More... | |
def | max_priority |
Priority value of highest-priority hook for some key. More... | |
def | min_priority |
Priority value of lowest-priority hook for some key. More... | |
def | default_priority |
Default priority for hooks. More... | |
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.
def minx.core.hooks.hooks.__init__ | ( | self) |
Create 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.
def minx.core.hooks.hooks.add | ( | self, | |
k, | |||
f, | |||
p = None |
|||
) |
Add a new function for some key.
k | The name of the hook. |
f | The function to be executed for k. |
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:
wm.hooks.add('foo', my_foo_hook, wm.hooks.MAX_PRIORITY)
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:
wm.hooks.add('foo', A, wm.hooks.MAX_PRIORITY) wm.hooks.add('foo', B, wm.hooks.MAX_PRIORITY)
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:
wm.hooks.add('foo', A, wm.hooks.MAX_PRIORITY) wm.hooks.add('foo', B, wm.hooks.max_priority('foo'))
The above code will first add A at the current highest priority for "foo" and then add B at the same priority as A.
def minx.core.hooks.hooks.default_priority | ( | self) |
Default priority for hooks.
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.
def minx.core.hooks.hooks.max_priority | ( | self, | |
k | |||
) |
Priority value of highest-priority hook for some key.
k | The name of the hook. |
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:
#!/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()
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:
wm.hooks.add('foo', my_foo_hook, wm.hooks.MAX_PRIORITY)
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.
def minx.core.hooks.hooks.min_priority | ( | self, | |
k | |||
) |
Priority value of lowest-priority hook for some key.
k | The name of the hook. |
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:
#!/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()
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:
wm.hooks.add('foo', my_foo_hook, wm.hooks.MIN_PRIORITY)
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.
def minx.core.hooks.hooks.names | ( | self) |
Get 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.
def minx.core.hooks.hooks.remove | ( | self, | |
k | |||
) |
Remove all hooks for specified name.
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.
def minx.core.hooks.hooks.rename | ( | self, | |
k, | |||
n | |||
) |
Rename the specified hook.
k | Current name of hook to be renamed. |
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).
def minx.core.hooks.hooks.trigger | ( | self, | |
k, | |||
p | |||
) |
Execute functions for a given key.
k | The name of the hook whose functions we want to call. |
p | Parameters to be passed to the hook functions. |
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:
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.