Simple and flexible interface to develop FVWM modules
Project description
fvwmpy -- framework for developing FVWM modules in python
This module defines class fvwmpy
, that can be used by itself or as a
base for derived classes for writing FVWM modules.
Version fvwmpy_v1.2.0
License
This module is released under GPL-3.0 license.
Declaration
I love FVWM
Features
- Simple interface for communication with the window manager.
- Asyncronous access to the packet queue.
- Possibility of maintaining dynamically updated list of windows and their properties.
- Possibility to iterate over windows satisfying given conditions.
- Possibility of dynamically changing configuration
- Simple interface for accessing FVWM's variables and infostore database.
- Compatible with tkinter
- Simple interface for masking packets from FVWM
- Support for the concept of module aliases
A simple example of a module using fvwmpy may be written along the following lines
#!/usr/bin/python3
import fvwmpy
class myfvwmmodule(fvwmpy.fvwmpy):
def h_config(self,pack):
# process config lines from FVWM database
def h_handler1(self,pack):
# respond to the pack
def h_handler2(self,pack):
# respond to the pack
...
m = myfvwmmodule()
m.logger.setLevel(fvwmpy.L_DEBUG)
### Keep FVWM mute while we are setting things up
m.mask = 0
m.syncmask = 0
m.nograbmask = 0
### Check command line arguments
for arg in m.args:
# process arg
### If we want to dynamically update configuration:
m.register_handler(fvwmpy.M_SENDCONFIG, m.h_config)
### If we want to keep config database up to date:
m.register_handler(fvwmpy.M_SENDCONFIG, m.h_saveconfig)
### If we want to have up to date list of windows
m.register_handler(fvwmpy.M_FOR_WINLIST, m.h_updatewl)
### Register handlers
m.register_handler(mask1,m.h_handler1)
m.register_handler(mask2,m.h_handler2)
...
### set masks
m.mask = <some mask>
m.syncmask = <some smask>
m.nograbmask = <some ngmask>
### for up to date winlist
m.mask |= fvwmpy.M_FOR_WINLIST
### for updating config dynamically
m.mask |= fvwmpy.M_SENDCONFIG
### If we want FVWM to wait while we update config
m.syncmask |= fvwmpy.M_SENDCONFIG
m.register_handler(fvwmpy.M_SENDCONFIG, m.h_unlock)
### Tell FVWM that we are ready
m.finishedconfig()
### Fill the config database
m.getconfig()
### Read FVWM's database of module configuration lines and parse them
m.getconfig(m.h_config)
### Fill the winlist database
m.getwinlist()
### Do some other module stuff
m.info(' Looks like FVWM manages {} windows now',len(m.winlist))
...
### If the module is persistent (listens to FVWM and executes handlers)
m.run()
### otherwise
m.exit()
More snippets and examples are below.
Structure of the fvwmpy
module
The module define the following constants, functions and classes.
Constants
The following constants are defined within the module
-
fvwmpy.C_*
Integers.
These constants refer to FVWM decoration contexts. See FVWM module interface for the complete list and definitions.
-
fvwmpy.contextnames
,fvwmpy.contextcodes
fvwmpy.contextnames
is a dictionary with keys being contexts, and values -- character strings containing the names of the corresponding context.fvwmpy.contextcodes
is the inverse of thefvwmpy.contextnames
dictionary. -
fvwmpy.M[X]_*
Integers.
Types of packets send from FVWM to the module. See section packets and FVWM module interface for the full list and meaning of packet types and other details. In addition the following masks are defined:
fvwmpy.M_ALL
- matches all packet types;fvwmpy.M_FOR_WINLIST
matches packets emitted by FVWM during response to 'Send_WindowList' command andfvwmpy.M_DESTROY_WINDOW
andfvwmpy.M_ADD_WINDOW
fvwmpy.M_FOR_CONFIG
-- mask matching all packets emitted by FVWM in response to 'Send_ConfigInfo' command andfvwmpy.M_SENDCONFIG
-
fvwmpy.packetnames
,fvwmpy.packetcodes
fvwmpy.packetnames
is a dictionary for converting packet types to their names. E.g.fvwmpy.packetnames[fvwmpy.MX_LEAVE_WINDOW] == 'MX_LEAVE_WINDOW'
fvwmpy.packetcodes
is the inverse dictionary offvwmpy.packetnames
-
fvwmpy.FVWM_PACK_START
andfvwmpy.FVWM_PACK_START_b
Delimiter used by FVWM to tag the start of each packet.
FVWM_PACK_START
is an integer andFVWM_PACK_START_b
is its bytes representation. -
fvwmpy.FINISHED
andfvwmpy.NOT_FINISHED
bytearrays containing tags to be sent to FVWM at the end of every message to notify whether module intends to continue or has finished working and is about to exit.
-
fvwmpy.LONG_SIZE
Integer. The size of C's long in bytes.
-
fvwmpy.FVWM_STR_CODEX
String. Codex for en/de-coding strings during communication with FVWM.
-
fvwmpy.VERSION
String. Naturally contains information about current version of the module.
-
fvwmpy.L_CRITICAL
,fvwmpy.L_ERROR
,fvwmpy.L_WARN
,fvwmpy.L_INFO
,fvwmpy.L_DEBUG
,fvwmpy.L_NOTSET
Integer.
Constants for setting logging level. Instances of
fvwmpy.fvwmpy
andfvwmpy._packet_queue
have their own loggers. Logging level can be set like thisobject.logger.setLevel(fvwmpy.L_DEBUG)
to see a lot of output from inner working of these objects. See alsoobject.debug
,...,object.critical
methods below.
Exceptions
-
fvwmpy.FvwmPyException
Base exception from which others are derived.
-
fvwmpy.FvwmLaunch
This exception is raised when the module can not start up normally, e.g it is not executed by FVWM, pipes can not be opened, etc.
-
fvwmpy.IllegalOperation
raised when one trying restore masks without saving them first, etc. It is also raised when one attempts to assign to FVWM variables (not infostore)
-
fvwmpy.FvwmError
raised when FVWM does not understand communication from the module or the other way around.
-
fvwmpy.PipeDesync
This exception is raised if pipe desyncronization is detected, e.g. when the packet from FVWM does not have begin-tag or when the content of the packet does not match its format. Instances of
fvwmpy._packet_queue
class have method._resync()
to seek the stream to the next pack. See packet queue section for more details.
Helper functions
-
fvwmpy.split_mask(mask)
mask
is a mask used for packet matching.Returns a tuple of all packet types, that match the given mask. If all the packet types in the list are bitwise
or
ed, one gets themask
back. -
fvwmpy.unique_id()
Returns a unique string, which almost guarantied not to match anything ever sent by FVWM. Can be used for tagging 'SendReply' FVWM-command. Each invocation returns a different string.
-
fvwmpy.picker(mask=None,**kwargs)
Returns a callable object, that can be called on a packet and returns boolean value. See Picker factory section for more details.
-
fvwmpy.glob(globstring)
,fvwmpy.Glob(globstring)
Both create glob patterns, against which you can match other strings.
globstring
is a string, that may contain '*' and '?' characters and '[chars]' substrings. Pattern '[chars]' may also contain ranges like '[a-z0-9]'. Wildcard '*' matches any substring, '?' matches any single character. '[chars]' matches any single character which is one of 'chars'. To match '*' or '?' literally, use the corresponding character enclosed in '[]'.When [gG]lob instance is compared to another string with
==
or!=
operator, it checks whether another string matches the pattern.E.g.
'abc*efg?xyz' == glob('*c[*]EFg[?]x??')
returnsTrue
.The difference between
glob
andGlob
is that in the former matching is case insensitive, while objects of the later match string in a case-sensitive way, so'abc*efg?xyz' == Glob('*c[*]EFg[?]x??')
will beFalse
.
Class fvwmpy.fvwmpy
m=fvwmpy.fvwmpy()
Instances of fvwmpy
have the following attributes and methods
Attributes
-
m.me
String. The name of the executable file containing the module
-
m.alias
String. Alias of the module. Alias is guessed from the command line arguments of the module during initialization. If the first command line argument does not start with '-', then it is assumed to be the alias of the module. Then
m.alias
is set (which affects logging functions and pruning of configuration lines) and this argument is not included inm.args
. If the first argument is a single '-', then it is also removed fromm.args
andm.alias
will be the same asm.me
.m.alias
can not be changed afterwards.This alias guessing seems to be consistent with what FVWM does. So module with alias 'FvwmAkaModule' will receive strings sent by
SendToModule FvwmAkaModule <string>
and can be terminated byKillModule FvwmAkaModule
command. -
m.args
List of strings. Contains command line arguments of the module. If the first argument does not start with '-', then it is assumed to be the alias of the module. Then
m.alias
is set (which affects logging functions and pruning of configuration lines) and this argument is not included inm.args
. If the first argument is a single '-', then it is also removed fromm.args
.-
If the module FvwmMyModule is invoked by FVWM command
Module FvwmMyModule FvwmAkaModule arg1 arg2 ...
then
m.alias == 'FvwmAkaModule'
andm.args == ['arg1', 'arg2', ...]
-
If the module is invoked by
Module FvwmMyModule - FvwmAkaModule arg1 arg2 ...
then
m.alias == 'FvwmMyModule'
andm.args == ['FvwmAkaModule', 'arg1', 'arg2', ...]
-
If the module is invoked by
Module FvwmMyModule -geometry 200x200+24+0 ...
then
m.alias == 'FvwmMyModule'
andm.args == ['-geometry', '200x200+24+0', ...]
-
-
m.mask
Integer. Mask for communication from FVWM. The mask controls what kind of packets FVWM sends to the module. The normal and extended (bits higher then 32) masks are treated the same, so, for example
m.mask = fvwmpy.MX_LEAVE_WINDOW | fvwmpy.M_VISIBLE_NAME
is a legal instruction with intended consequences.Setting the mask to a new value will trigger communication with FVWM to let it know the new value, but only if the new value is different from the old, so no unnecessary communication takes place. Note, that if you previously changed the mask by some other method (sending an appropriate message to FVWM) the new value might not be communicated to the window manager when executing
m.mask = <new_value>
. Methodsm.push_mask()
andm.restore_mask()
are safe to use in this respect.Every time new mask is set by
m.mask = newmask
,m.mask_setter_hook('mask',newmask)
is called.m.mask_setter_hook(...)
does nothing by default, but you may overload it, for example, to communicate new value of the mask to other parts of the program, e.g. gui.See
fvwmpy.M[X]_*
for possible values of masks and interpretation thereof.See also
m.push_masks(...)
andm.restore_masks()
methods for temporarily changing masks.See FVWM module interface for the explanation of the concepts of masking.
-
m.syncmask
andm.nograbmask
are similar to
m.mask
but contain values of syncmask and nograbmask, respectively. When new value is set,m.mask_setter_hook('syncmask',newmask)
orm.mask_setter_hook('nograbmask',newmask)
is called. -
m.context_window
Integer. Contains id of the window in whose context the module was started or 0 if the module was executed outside of any window context. This will be used for all methods requiring context_window parameter if
None
is passed. -
m.context_deco
Window decoration context in which module was started or 0 if the module was executed outside of any window context. See
fvwmpy.C_*
and FVWM module interface for explanation of decoration contexts. -
m.logger
A logger object associated with the instance. You may call
m.logger.setLevel(<new_level>)
to change the severity threshold for logging messages. Here<new_level>
is one of thefvwmpy.L_*
constants described above.m.logger.getEffectiveLevel()
is the current level. See alsom.debug
,...,m.critical
methods below. The default level isfvwmpy.L_WARN
, which keeps it relatively quiet. -
m.config
m.config
is the database containing information sent by FVWM during execution of Send_ConfigInfo command and withM_SENDCONFIG
packets. See alsom.getconfig()
method andm.h_saveconfig()
handler. For more details see section Config database below. -
m.winlist
m.winlist
is the database of windows known to FVWM indexed by window id's. It can be filled by callingm.getwinlist()
method. It is also possible to arrange to havem.winlist
to be up to date at all times. See information onm.h_updatewl
handler.m.winlist
inherits fromdict
.m.winlist[<window_id>]
is an instance offvwmpy._window
class and contains all the information about the window, that FVWM cares to communicate to us. For more details see winlist database belowIn addition to the usual
dict
methods it also has methodw.winlist.filter(conditions)
which return an iterator for cycling through windows satisfying conditions. It is described in more details in winlist database section. -
m.handlers
A dictionary whose keys are packet types and values are lists of handler functions, each of which takes one argument, which is a packet. Initially all lists are empty. It is not advised to access it directly. See
m.register_handler()
,m.unregister_handler()
,m.clear_handlers()
,m.registered_handler()
andm.call_handlers()
methods and handlers section below. -
m.var
andm.infostore
These are special objects providing access to FVWM variables and infostore database.
See section FVWM variables and infostore below.
-
m.packets
A packets queue from FVWM.
See Packets section for the description and the structure of the packet data type.
Methods
For all methods requiring context_window parameter if `None` is
given, module's own context window is assumed.
-
m.debug()
,m.info()
,m.warn()
,m.error()
andm.critical()
logging functions. They should be called
m.<log_fcn>(message_string, *arguments)
and use
message_string.format(*arguments)
formatting paradigm. Logging messages are directed to stderr. For the module stderr-stream will be the same as for FVWM. Logging functions print the severity level followed by the alias of the module followed by the formatted message. The behavior of these functions is affected by the value returned bym.logger.getEffectiveLevel()
. Only messages with severity not less then that level will be printed. Usem.logger.setLevel(value)
to change logging level. -
m.sendmessage(msg, context_window=None, finished=False)
Send a (possibly multi-line) message to FVWM for execution in the context of
context_window
.msg
is a multi-line string conatining FVWM commands. Empty lines (only with white spaces) are ignored. For example the following workscmds=""" Focus WarpToWindow {} {} """ m.sendmessage(cmds.format(30,50), context_window = wid )
If
context_window
is not given orNone
, then the window context will be equal to the context window of the module (that ism.context_window
). Ifcontext_window==0
, then FVWM executes commands without window context.If
finished
then FVWM will be notified that the module is done working and is about to exit soon.Every time
m.sendmessage(...)
is executedm.sendmessage_hook()
with the same arguments will also be called.m.sendmessage_hook()
does nothing, but can be overloaded, for example, to let GUI part know that a message was sent. -
m.getreply(msg,context_window=None,timeout=0.5)
Send string message
msg
to FVWM and request to send it back in the contextcontext_window
. Iftimeout
is given and notNone
, then return not later then after timeout seconds. If for some reason no reply was received from FVWM,None
is returned.There is no need to change masks before/after invoking this method, it works independently of the current values of masks and does not change them.
This method works reliably independently whether there are unhandled packets in the packet queue. The reply will be picked and removed from the queue and returned. The following code works correctly.
### Pollute the queue m.push_masks(M_FOR_WINLIST|MX_REPLY,0,0) m.sendmessage('Send_WindowList') m.sendmessage('Send_Reply unrelated reply') m.restore_masks() ### Now packet queue is full of packets w_name = m.getreply('$[w.name]',context_window=123456789) ### reply packet is found in the queue and is removed from it # do something with w_name # handle packets remaining in the queue
-
m.getconfig(handler=None, match=None,timeout=0.5)
Ask FVWM for configuration info. Each received packet is passed to the
handler
. This method returnsTrue
upon successful operation orFalse
if something went wrong, pehapsM_END_CONFIG_INFO
packet was not received for timeout seconds. (Experimentation shows that FVWM needs not more then 0.05 seconds to send config under normal circumstances)handler
must beNone
or a callable taking one argument, which is a packet of type matchingfvwmpy.M_FOR_CONFIG
. Ifhandler
is not supplied or isNone
, then the default handlerm.h_saveconfig
is used.m.h_saveconfig
just fillsm.config
database with the information received from FVWM. See section Config database below.match
must beNone
or a string to match module configuration lines against. If not supplied then'*' + m.alias
is assumed. Ifmatch == ""
then all configuration lines for all modules are received and processed.There is no need to change masks before/after invoking this method, it works independently of the current values of masks and does not change them.
This method works reliably independently of the state of the packet queue. Even if the queue is not empty at the start of this call, configuration packets will be found in the queue and removed from it. So the following works reliably
### Pollute the queue m.push_masks(M_FOR_WINLIST|MX_REPLY,0,0) m.sendmessage('Send_WindowList') m.restore_masks() ### Now queue is full of packets m.getconfig() ### m.config is updated and config messages are removed from the ### queue # handle the packets remaining in the queue
If you want to keep config database up to date all the time, then include the following
m.getconfig() m.register_handler(fvwmpy.M_SENDCONFIG, m.h_saveconfig) m.mask |= fvwmpy.M_SENDCONFIG
somewhere in your code.
See Config database for more information and how to have config database up to date all the time.
-
m.getwinlist(handler = None,timeout=0.5)
Ask FVWM for the list of all windows it manages. Each packet received in response is passed to the handler. Return
True
if operation was successful. Wait for at most timeout seconds forM_END_WINLIST
packet from FVWM before returning.handler
should be a callable taking one argument, which is a packet of type matchingfvwmpy.M_FOR_WINLIST
. Ifhandler
is not supplied then default handlerm.h_updatewl
is used.m.h_updatewl
simply updatesm.winlist
database with the information received from FVWM. It also understandsfvwmpy.M_ADD_WINDOW
andfvwmpy.M_DESTROY_WINDOW
packets removing/adding the corresponding entries from the database.It is not necessary to adjust the values of the masks before or after invoking
fvwmpy.getwinlist()
. It works independently of the current values of masks and preserves them.This method works reliably independently of the state of the packet queue. Even if queue is not empty at the start of this call,
fvwmpy.M_FOR_WINDOWLIST
-type packets will be found in the queue and removed from it. So the following works reliably### Pollute the queue m.push_masks(M_FOR_WINLIST|MX_REPLY,0,0) m.sendmessage('Send_ConfigInfo') m.restore_masks() ### Now queue is full of packets ### Mute FVWM m.mask = 0 m.getwinlist() ### m.winlist is updated and the corresponding packets are ### removed from the queue ### m.mask is still 0 # handle the packets remaining in the queue
Note that
m.getwinlist()
will also pick packets of typeM_ADD_WINDOW
orM_DESTROY_WINDOW
(these packets are not send in response 'Send_WindowList' request, but correspond to events in FVWM) and they will be also removed from the queue.If you want to keep
m.winlist
up to date all the time, then include the followingm.getwinlist() m.register_handler(fvwmpy.M_FOR_WINLIST, m.h_updatewl) m.mask |= fvwmpy.M_FOR_WINLIST
somewhere in your code.
-
m.finishedstartup()
Tell FVWM that the module has finished setting things up and is ready to start working.
-
m.exit(n=0)
Clean up and exit with exit status
n
. See alsom.h_exit()
handler. -
m.unlock(finished=False)
During synchronous operations, tell FVWM that module is ready to continue working and is listening to FVWM.
If
finished
then notify FVWM that the module is about to exit. -
m.push_masks(mask,syncmask,nograbmask)
Set mask, syncmask and nograbmask to new values temporarily. If any of the values is
None
than the corresponding mask is left unchanged.It is possible to have several embedded
m.push_masks
--m.restore_masks
constructs. -
m.restore_masks()
Restore masks previously overridden by
m.push_masks
. If mask stack is empty (morem.restore_masks()
's thenm.push_masks()
's)fvwmpy.IllegalOperation
exception is raised. -
m.register_handler(mask, handler)
Register
handler
for packets of type matchingmask
. The default mainloop executes all the handlers for all matching packets in the order they were registered.handler
should be a callable taking one argument, which is a packet of type matchingmask
and should be capable of processing such a packet. Handlers should not raise any non-terminal exceptions.If
handler
is already registered previously for some packet types, it will not be registered again, neither it will be moved to the end of execution queue for that type. If you want to move some registered handler to the end of the queue, you have to unregister it first.There are some predefined packet handlers, (see below) but one could define more as functions or as methods in the derived class.
-
m.unregister_handler(mask, handler)
Remove handler from the execution queue for the packets matching
mask
. It is not an error to try to unregister a handler, which is not registered. So, for example,m.unregister_handler(fvwmpy.M_ALL, m.h_handler)
removes
m.h_handler
from all queues where it is present. -
m.call_handlers(pack)
Execute all handlers in the queue corresponding to the
pack
's packet type passing packetpack
to them. The default mainloop callsm.call_handlers()
on all packets received from FVWM except those which are removed from the queue bym.get*
methods orm.packets.pick(...,keep=False)
method. -
m.clear_handlers(mask)
Clear all execution queues for packets matching
mask
. -
m.registered_handler(handler)
Return the mask for the queues where handler is registered.
-
m.run()
Enter mainloop which simply reads packets from FVWM and for each packet executes handlers in the queue, until
m.exit()
orm.h_exit()
method is called. It could be overloaded in the derived class.
Supplied handlers
-
m.h_saveconfig(pack)
Packets type:
M_FOR_CONFIG
This handler is capable of processing packets matching
fvwmpy.M_FOR_CONFIG|fvwmpy.M_SENDCONFIG
. It simply records the information inm.config
database. You can insert the following lines in your code to keep the database up to datem.getconfig() m.register_handler(fvwmpy.M_FOR_CONFIG, m.h_saveconfig) m.mask |= fvwmpy.M_SENDCONFIG | fvwmpy.M_CONFIG_INFO ### If you want to process config in a synchronous manner m.register_handler(fvwmpy.M_FOR_CONFIG, m.h_unlock) m.syncmask |= fvwmpy.M_SENDCONFIG | fvwmpy.M_FOR_CONFIG
m.h_saveconfig(pack)
does not send NOP UNLOCK command to FVWM. In case you want to process configuration information synchronously registerm.h_unlock
afterm.h_saveconfig
. -
m.h_unlock(pack)
Packets type:
M_ALL
This handler completely ignores its argument and sends the NOP UNLOCK command to FVWM. FVWM waits for NOP UNLOCK after sending packets matching
m.syncmask
, so it make sense to alwaysm.register_handler(m.syncmask,m.h_unlock)
after all other handlers are added. If syncmask changes one should
m.unregister_handler(fvwmpy.M_ALL, m.h_unlock) m.register_handler(m.syncmask, m.h_unlock)
to make sure that
m.h_unlock
is the last one in the queues -
m.h_exit(pack)
Packet types:
M_ALL
This handler ignores its argument, cleans things up and terminates the module.
-
m.h_nop(pack)
Packet types:
M_ALL
Do nothing.
-
m.h_updatewl(pack)
Packet types:
M_FOR_WINLIST | M_ADD_WINDOW | M_DESTROY_WINDOW
This handler is capable to process packets matching
fvwmpy.M_FOR_WINLIST|M_ADD_WINDOW|M_DESTROY_WINDOW
. It uses information in the packet to updatem.winlist
database.
FVWM variables and InfoStore
Instances of fvwmpy.fvwmpy
have two special objects m.var
and
m.infostore
, which provide access to FVWM variables and FVWM
infostore database in a transparent manner.
The value of a variable (even non-existent) is always a string.
If variable no.such.var
does not exist in FVWM environment,
the access methods below will return the literal string
'$[no.such.var]'
. It is client's business to check for this and to
perform type casting, when necessary.
The behavior of infostore database is analogous.
-
m.var
One can access FVWM variables in two ways
-
m.var.<var_name_with_underscores>
will be equal to the value of FVWM variable as a string. FVWM variables often have a dot in their names. To use this method you have to replace dots with underscores. That ism.var.w_id
will return the value$[w.id]
. You can not assign to or delete FVWM variables, som.var.w_id = <value>
ordel m.var.w_id
will raisefvwmpy.IllegalOperation()
exception. -
m.var('var_name1',...,context_window=None)
will return a tuple with string-values of variables, whose names are given as string arguments. It is not necessary (but allowed) to replace dots with underscore in variable names, when using this method. Ifcontext_window == None
then module's context_window is assumed. Ifcontext_window == 0
then variable values are obtained outside of any context.
The second method obtains all variable values in one communication cycle with FVWM, so it is preferable, when values of several variables are needed.
It is not possible to get value of a variable, whose name contains underscore. To the best of my knowledge there are no such variables, at least none are mentioned in the FVWM man pages.
-
-
m.infostore
Similarly, one can access FVWM infostore database in two ways
-
m.infostore.<var_name_with_underscores>
will be equal to the value of FVWM infostore variable as a string. You have to replace dots with underscores in variable names. For examplem.infostore.my_variable
will return the FVWM's expansion of$[infostore.my.variable]
. You can also assign to or delete FVWM infostore variables, som.infostore.my_variable = <value>
ordel m.infostore.my_variable
are legal. -
Similarly
m.infostore('var_name1',...)
will return a tuple with string-values of variables, whose names are given as string arguments. It is not necessary (but allowed) to replace dots with underscore in variable names.
The second method obtains all variable values in one communication cycle with FVWM, so it is preferable, when values of several variables are needed.
Beware that it is not possible to get the value of, assign to, or delete an infostore variable, whose name contains underscore.
-
Access methods for both FVWM variables and infostore variables work reliably independently of the state of the packet queue. So you can have some stale packets in the queue and still get the correct values.
Note that each access attempt results in communication with FVWM, so it is better access once and store values, if needed.
### Bad practice, 4 communication cycles with FVWM
area = int(m.var.w_width) * int(m.var.w_height)
perimeter = 2*int(m.var.w_width) + 2*int(m.var.w_height)
### Good practice, 1 communication with FVWM
width, height = map( int, m.var('w.width','w.height') )
area = width * height
perimeter = 2 * (width + height)
Winlist database m.winlist
m.winlist
is a dictionary of windows indexed by window id's. Each
window is an instance of fvwmpy._window
class and has the attributes
and methods listed below.
m.winlist has all the usual methods inherited from dict
and one extra described below.
-
m.winlist.filter(conditions)
This method returns an iterator that cycle through windows matching
conditions
conditions
is a string containing the same conditions that are allowed in FVWM's conditional commands. See FVWM manual pages for explanations. For formatting convenienceconditions
may be a multi-line string. As an example look at the following (not very useful) snippetcondition = """ !FixedSize, !FixedPosition, !Shaded,!Iconic,CurrentPage !Fvwm*, !stalonetray """ for w in m.windowlist.filter(condition): dx = max( w.wdx//2, w.hints_min_width ) dy = max( w.wdy//2, w.hints_min_height ) m.sendmessage( 'Resize {}p {}p'.format(dx,dy), context_window=w.window )
Note that
winlist.filter
may have troubles, if the winlist database is not up to date.Winlist has __str__ method which gives some nice human readable representation of entire database. The following very simple module will print the database into the file when it is instructed to do so by FVWM command 'SendToModule MyModule dumpwinlist'
class MyModule(fvwmpy.fvwmpy): def h_dumpwinlist(self,p): if p.string == glob('dumpwinlist *'): with open('winlist.txt','wt') as file: print(self.winlist,file=file) elif p.string == glob('exit *'): self.exit() m=MyModule() m.register_handler(fvwmpy.M_STRING,m.h_dumpwinlist) m.register_handler(fvwmpy.M_FOR_WINLIST,m.h_updatewl) m.finishedconfig() m.mask = fvwmpy.M_STRING | fvwmpy.M_FOR_WINLIST m.syncmask = 0 m.nograbmask = 0 m.getwinlist() m.run()
Attributes and methods of instances of fvwmpy._window
class.
For more comprehensive information and meaning of different attributes refer to FVWM module interface and consult fvwm.h, window_flags.h, Module.h vpacket.h files in FVWM source tree.
Each value of m.winlist
is fvwmpy._window
object.
fvwmpy._window
inherits from dict
. For syntactic convenience
values of the dictionary can also be accessed as attributes via
w.key
, which is completely equivalent to w['key']
. Also both
raise KeyError()
exception, if the key/attribute is missing.
The attributes/keys are
-
w.window
window id -
w.frame
id of the frame window -
w.wx
,w.wy
x,y location of the window’s frame -
w.wdx
,w.wdy
width and height of the window’s frame -
w.desk
desktop number -
w.layer
layer -
w.hints_base_width
,w.hints_base_height
window base width and height -
w.hints_width_inc
,w.hints_height_inc
window resize width/height increment -
w.orig_hints_width_inc
,w.orig_hints_height_inc
original window resize width/height increment -
w.hints_min_width
,w.hints_min_height
,w.hints_max_width
,w.hints_max_height
window minimum/maximum width/height -
w.icon_w
icon label window id, or 0 -
w.icon_pixmap_w
icon pixmap window id, or 0 -
w.hints_win_gravity
window gravity -
w.text_pixel
pixel value of the text color -
w.back_pixel
pixel value of the window border color -
w.ewmh_hint_layer
ewmh layer -
w.ewmh_hint_desktop
ewmh desktop -
w.ewmh_window_type
ewmh window type -
w.title_height
window title height -
w.border_width
border width -
w.flags
is a bytearray containing style flags and action flags. See alsow.flag()
method. -
w.win_name
window name -
w.ico_name
icon name -
w.win_vis_name
window visible name -
w.ico_vis_name
icon visible name -
w.res_class
resolution class -
w.res_name
resolution name -
w.mini_ico_dx
,w.mini_ico_dy
ToDo these -
w.mini_ico_depth
-
w.winid_pix
-
w.winid_mask
-
w.mini_ico_filename
NOTE there seems to be a bug in FVWM. This value can not be decoded to a meaningful string with neither 'ascii' nor 'utf8' codex. -
w.ico_filename
-
w.flag(i)
returns the value of the i^th flag as 0/1 integer.ToDo: access flags by meaningful names.
ToDo: It seems that FVWM sends window position relative to the current viewport. Shall we recalculate it to be absolute within the desk?
The winlist database is filled by m.getwinlist()
method.
You can keep it up to date, see examples above.
Config database m.config
m.config
is a database of configuration information sent in response
to Send_ConfigInfo command. It is a list of strings, each is a
module configuration line.
Note: Each configuration line is concatenation of module name and
configuration parameters without any delimiter. So the line
*FvwmMymodule:Geometry 100x100+0-0
in FVWM's config is passed to
the module as '*FvwmMymoduleGeometry 100x100+0-0'. I am not sure
whether this is a FVWM bug or intentional.
In addition it has the following attributes
-
m.config.DesktopSize
the size of the desktop (in pages) -
m.config.ImagePath
a tuple of strings, each is the path where FVWM searches for images -
m.config.XineramaConfig
a tuple of integers. See FVWM manual pages for the meaning. -
m.config.ClickTime
integer. Click time in milliseconds -
m.config.IgnoreModifiers
tuple of integers. Modifiers that are ignored. -
m.config.colorsets
list of colorsets, each represented as a list of strings.ToDo: We really need to parse colorsets and create meaningful access to them.
m.config
has __str__ method that returns human readable
representation of the database. The following module prints config
database to the file when instructed by SendToModule MyModule dumpconfig
command.
from fvwmpy import *
class MyModule(fvwmpy):
def h_cmd(self,p):
if p.string == glob('dumpwinlist *'):
self.info('Save window list to winlist.txt')
with open('winlist.txt','wt') as file:
print(self.winlist,file=file)
if p.string == glob('dumpconfig *'):
self.info('Save config to config.txt')
with open('config.txt','wt') as file:
print(self.config,file=file)
elif p.string == glob('exit *'):
self.info('Exiting...')
self.exit()
m=MyModule()
m.register_handler(M_STRING, m.h_cmd)
m.register_handler(M_FOR_WINLIST, m.h_updatewl)
m.register_handler(M_SENDCONFIG, m.h_saveconfig)
m.mask = ( M_STRING | M_FOR_WINLIST |
M_FOR_CONFIG | M_SENDCONFIG )
m.syncmask = 0
m.nograbmask = 0
m.finishedconfig()
m.getwinlist()
m.getconfig()
m.run()
Packet queue
An instance of fvwmpy.fvwmpy
class has attribute m.packets
that
represents the queue of packets from FVWM. The structure of each packet
data type is described below.
m.packets
is an object of fvwmpy._packet_queue
class.
One can change the level of logging produced by m.packets
by calling
m.packets.logger.setLevel(<new_level>)
where <new_level> is
one of fvwmpy.L_*
constants described above. The default level is
fvwmpy.L_WARN
, which makes it mostly quiet.
The packets are read from the FVWM-to-module pipe asynchronously and put into the queue for processing by the module.
m.packets
has the following attributes and methods
-
m.packets.__len__
You can see how many packets are waiting to be handled with
len(m.packets)
. -
m.packets.__bool__
bool(m.packets)
returnsTrue
iff the queue is not empty. -
m.packets.clear()
Empty the queue discarding all of its content.
-
m.packets.read(keep=False,timeout=None)
Returns and removes the packet from the top of the queue. If queue is empty and
timeout
isNone
it waits for the packet to arrive. If queue is empty andtimeout
is given and notNone
, return valueNone
, if no packet arrived in the pipe during timeout seconds. -
m.packets.peek(timeout=None)
This is like
m.packets.read
method, except the packet remains in the queue and will be returned with the nextm.packets.read
orm.packets.peek
call, unless it will have beenm.packets.pick()
'ed meanwhile. -
m.packets.pick(picker, until=None, keep=False, timeout=0.500)
Return all packets from the queue for which
picker
evaluates to true, possibly removing them from the queue, depending on the parameterkeep
. The queue is searched until packet for whichuntil
evaluates to true is found. Even if no packets are found, return aftertimeout
seconds.Note: the return value is always a
tuple
, even if returning one or zero packets.-
picker
must be a callable, taking a packet as a single parameter and returning boolean value. It is used to prune the queue. See Picker factory for creating pickers. -
until
is the same type aspicker
. The search in the queue will be terminated once the packet for whichuntil
evaluated toTrue
is encountered. If not given orNone
thenuntil
is set to be equal topicker
. In that case the first (oldest) packet matchingpicker
will be found and returned (if it arrives withintimeout
seconds). -
keep
is a boolean that indicates whether packets should be removed from the queue. -
timeout
indicates how many seconds shall the method wait foruntil(p)==True
-packet. Iftimeout
isNone
, wait indefinitely.
Examples:
from fvwmpy import * m=fvwmpy() ... ### Find all config lines about colorsets in he queue packs = m.packets.pick( picker = picker( mask = M_FOR_CONFIG, string = glob("colorset*") ), until = picker( mask = M_END_CONFIG_INFO ) ) ### Find the oldest MX_ENTER_WINDOW PACKET (pack,) = m.packets.pick( picker = picker( mask = M_ENTER_WINDOW )) ### Find all `SendToModule`-messages from FVWM until this moment tag = unique_id() m.sendmessage("SendReply {}".format(tag)) packs = m.packets.pick (picker = picker(mask=M_STRING), until = picker(mask=MX_REPLY, string=glob(tag))) ### In the last example MX_REPLY packet will not be returned and ### will remain in the queue. If this is undesired change the last ### line to end = picker(mask=MX_REPLY,string=glob(tag)) pick = picker(mask=M_STRING) | end packs = m.packets.pick (picker=pick, until=end)
-
FVWM packets
m.packets.{read,peek,pick}()
return an instance of fvwmpy._packet
class, which inherits from dict
. Values can also be accessed via
p.key
or p['key']
which are completely equivalent in that both
raise KeyError()
exception, if the key is missing.
The available keys/attributes depend on the packet and described below for all types of packets. See FVWM module interface when each packet is sent and what information it contains.
Any packet has always the following attributes
p.ptype
- Integer. Type of the packet. Seefvwmpy.M[X]_*
constants.p.name
- String. Type of the packet as a character string matchingglob('MX_*|M_*')
. This is a property, there is no corresponding key in the dictionary.p.time
- Integer. Time stampp.body
- Bytearray. The raw body of the packet without the header.
Other attributes/keys depend on the packet. Below they are listed for each type of packets.
-
fvwmpy.M_NEW_PAGE
p.px
,p.py
- Integer. Coordinates of the NW corner of the current viewport.p.desk
- Integer. Current desk number.p.max_x
,p.max_y
- Integer. Sizes of the current viewport.p.nx
,p.ny
- Integer. Number of pages in the desktop in x- and y-directions.
-
fvwmpy.M_NEW_DESK
p.desk
- Integer. Current desk number.
-
fvwmpy.M_OLD_ADD_WINDOW
,fvwmpy.M_EXTENDED_MSG
,fvwmpy.M_UNKNOWN1
,fvwmpy.END_WINDOWLIST
,M_END_CONFIG_INFO
None
-
fvwmpy.M_RAISE_WINDOW
,fvwmpy.M_LOWER_WINDOW
,fvwmpy.M_DESTROY_WINDOW
,fvwmpy.M_MAP
,fvwmpy.M_WINDOWSHADE
,fvwmpy.M_DEWINDOWSHADE
,fvwmpy.MX_ENTER_WINDOW
,fvwmpy.MX_LEAVE_WINDOW
p.window
- Integer. Window idp.frame
- Integer. Frame window id
-
fvwmpy.M_FOCUS_CHANGE
p.window
- As above.p.frame
- As above.p.focus_change_type
p.text_pix
p.border_pix
-
fvwmpy.M_ICONIFY
,fvwmpy.M_DEICONIFY
p.window
- As above.p.frame
- As above.p.ix
,p.iy
- These and below are integers.p.idx
,p.idy
p.fx
,p.fy
p.fdx
,p.fdy
-
fvwmpy.M_WINDOW_NAME
p.window
- As above.p.frame
- As above.p.win_name
- String. Name of the window.
-
fvwmpy.M_ICON_NAME
p.window
- As above.p.frame
- As above.p.ico_name
- String. Name of the icon window.
-
fvwmpy.M_RES_CLASS
p.window
- As above.p.frame
- As above.p.res_class
- String.
-
fvwmpy.M_RES_NAME
p.window
- As above.p.frame
- As above.p.res_name
- String.
-
fvwmpy.M_ICON_LOCATION
p.window
- As above.p.frame
- As above.p.ix
,p.iy
- These and below are integers.p.idx
,p.dy
-
fvwmpy.M_ERROR
,fvwmpy.M_CONFIG_INFO
,fvwmpy.M_SENDCONFIG
p.string
- String. The content depends on the type of the packet.
-
fvwmpy.M_ICON_FILE
p.window
- As above.p.frame
- As above.p.ico_filename
- String. Name of the image file.
-
fvwmpy.M_DEFAULTICON
p.ico_defaultfilename
- Supposed to be a string, but FVWM seems to send garbage.
-
fvwmpy.M_STRING
,fvwmpy.MX_REPLY
p.window
- As above.p.frame
- As above.p.string
- String.
-
fvwmpy.M_MINI_ICON
p.window
- As above.p.frame
- As above.p.mini_ico_dx
,p.mini_ico_dy
- Integer.p.mini_ico_depth
- Integerp.winid_pix
p.winid_mask
p.mini_ico_filename
- String.
-
fvwmpy.M_VISIBLE_NAME
p.window
- As above.p.frame
- As above.p.win_vis_name
- String.
-
fvwmpy.M_RESTACK
p.win_stack
- List of triples of integers.
-
fvwmpy.MX_VISIBLE_ICON_NAME
p.window
- As above.p.frame
- As above.p.ico_vis_name
- String.
-
fvwmpy.MX_PROPERTY_CHANGE
p.prop_type
- Integerp.val_1
,p.val_2
- Integerp.prop_str
- String.
-
fvwmpy.ADD_WINDOW
,fvwmpy.M_CONFIGURE_WINDOW
The attributes of the packets of these types are the same as the first 29 attributes of an instance offvwmpy._window
class above (up to and includingw.flags
)
ToDo: Details of the packet attributes above.
Picker factory
The fvwmpy
module defines a special class fvwmpy.picker
that can be
used for creating callables that take a packet as an argument and
return a boolean value. There are two invocation signatures
-
fvwmpy.picker(fcn=None)
fcn
is a callable with packet as an argument orNone
. Return a callable (picker object) equivalent to thefcn
in the sense thatfvwmpy.picker(fcn)(p) == bool(fcn(p))
for any packetp
.If
fcn
isNone
then return a picker object, that is always True. -
fvwmpy.picker(mask=None,**kwargs)
Returns a callable object, that can be called on a packet and returns boolean value.
If
pck = picker(mask=M, key1=val1, key2=val2,...)
then
pck(p)
returnsTrue
iff the packetp
matches maskM
and has key:value pairskey1:val1
,key2:val2
,...If one of the keys is missing in packet
p
, then the return value ofpck(p)
isFalse
. If mask isNone
, then no mask matching is performed.In place of
val1
,val2
, you can useglob
andGlob
objects , described above to check matching of strings against glob patterns. See examples below.fvwmpy.picker
objects can be conjoined with|
,&
or unary~
operators. The resulting picker evaluated on packetp
returns value which isor
,and
ornot
of the value(s) of operand(s) evaluated onp
. These operators short-circuit from left to right. You can build arbitrary boolean polynomials with picker objects and the above operators.For example, if
pck1 = ( picker(win_name=glob('Fvwm*') ) | picker(res_name=glob('*term*') ) ) pck2 = picker(mask = M_ENTER_WINDOW|M_LEAVE_WINDOW, window=1234567) pck3 = picker(window = 987654321) & ~picker(mask=M_DESTROY_WINDOW)
then
pck1(p)
will be true iff packetp
has key 'win_name' with a string value starting with 'fvwm' OR ifp
has key 'res_name' with a value containing 'term'.pck2(p)
will be only true for packets emitted by FVWM when pointer enters of leaves window withid==1234567
.pck3(p)
will evaluate true on all packets related to window withid==987654321
exceptM_DESTROY_WINDOW
packet.picker
objects are handy form.packets.pick()
method, described above and also for use in packet handlers.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file fvwmpy-1.2.0.tar.gz
.
File metadata
- Download URL: fvwmpy-1.2.0.tar.gz
- Upload date:
- Size: 69.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.8 tqdm/4.62.3 importlib-metadata/4.8.3 keyring/23.4.1 rfc3986/1.5.0 colorama/0.4.4 CPython/3.6.15
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | e5d0ae43b50ee9eb362e7fad2ca99da84d0dbe0ce374b3df2edc12486c25271d |
|
MD5 | 49dfc187e52c3c039a9503c7e7a61725 |
|
BLAKE2b-256 | d282b7cbb0dd101f83360194e7d4d2c9c6d116e441bd04e7f58f44fef0add202 |
File details
Details for the file fvwmpy-1.2.0-py3-none-any.whl
.
File metadata
- Download URL: fvwmpy-1.2.0-py3-none-any.whl
- Upload date:
- Size: 45.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.8 tqdm/4.62.3 importlib-metadata/4.8.3 keyring/23.4.1 rfc3986/1.5.0 colorama/0.4.4 CPython/3.6.15
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | e6dcf6f68f3ae3c94bbf02a136b2d6e0f85a0e01fbfc587c9c75b88ba9fe45da |
|
MD5 | bcf7398cd2d5c0b4a958dc17a6efd823 |
|
BLAKE2b-256 | 1fbd0f418bf72da28dadd7d940265a17773ec5e32b93da8c68b052dd6980cf35 |