Public Member Functions | List of all members
minx.core.hooks.hooks Class Reference

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

Detailed Description

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.

Constructor & Destructor Documentation

def minx.core.hooks.hooks.__init__ (   self)

Create an empty hook map.

Returns
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 main window manager object. Refer to the Hooks HOWTO for more on typical usage patterns for this class.

Member Function Documentation

def minx.core.hooks.hooks.add (   self,
  k,
  f,
  p = None 
)

Add a new function for some key.

Parameters
kThe name of the hook.
fThe function to be executed for k.
pThe 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.

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.
def minx.core.hooks.hooks.default_priority (   self)

Default priority for hooks.

Returns
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.
def minx.core.hooks.hooks.max_priority (   self,
  k 
)

Priority value of highest-priority hook for some key.

Parameters
kThe name of the hook.
Returns
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:

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

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.
def minx.core.hooks.hooks.min_priority (   self,
  k 
)

Priority value of lowest-priority hook for some key.

Parameters
kThe name of the hook.
Returns
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:

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

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.
def minx.core.hooks.hooks.names (   self)

Get names of currently defined hooks.

Returns
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).
def minx.core.hooks.hooks.remove (   self,
  k 
)

Remove all hooks for specified name.

Parameters
kName 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.
def minx.core.hooks.hooks.rename (   self,
  k,
  n 
)

Rename the specified hook.

Parameters
kCurrent name of hook to be renamed.
nNew 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.
def minx.core.hooks.hooks.trigger (   self,
  k,
  p 
)

Execute functions for a given key.

Parameters
kThe name of the hook whose functions we want to call.
pParameters to be passed to the hook functions.
Returns
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:

  • Simply ignore the hook return values.
  • Use only the first return value, i.e., the value returned by the highest-priority hook.
  • Use the last return value (i.e., last hook executed).
  • 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.