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.contextcodesfvwmpy.contextnamesis a dictionary with keys being contexts, and values -- character strings containing the names of the corresponding context.fvwmpy.contextcodesis the inverse of thefvwmpy.contextnamesdictionary. -
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_WINLISTmatches packets emitted by FVWM during response to 'Send_WindowList' command andfvwmpy.M_DESTROY_WINDOWandfvwmpy.M_ADD_WINDOWfvwmpy.M_FOR_CONFIG-- mask matching all packets emitted by FVWM in response to 'Send_ConfigInfo' command andfvwmpy.M_SENDCONFIG
-
fvwmpy.packetnames,fvwmpy.packetcodesfvwmpy.packetnamesis a dictionary for converting packet types to their names. E.g.fvwmpy.packetnames[fvwmpy.MX_LEAVE_WINDOW] == 'MX_LEAVE_WINDOW'fvwmpy.packetcodesis the inverse dictionary offvwmpy.packetnames -
fvwmpy.FVWM_PACK_STARTandfvwmpy.FVWM_PACK_START_bDelimiter used by FVWM to tag the start of each packet.
FVWM_PACK_STARTis an integer andFVWM_PACK_START_bis its bytes representation. -
fvwmpy.FINISHEDandfvwmpy.NOT_FINISHEDbytearrays 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_SIZEInteger. The size of C's long in bytes.
-
fvwmpy.FVWM_STR_CODEXString. Codex for en/de-coding strings during communication with FVWM.
-
fvwmpy.VERSIONString. 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_NOTSETInteger.
Constants for setting logging level. Instances of
fvwmpy.fvwmpyandfvwmpy._packet_queuehave 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.criticalmethods below.
Exceptions
-
fvwmpy.FvwmPyExceptionBase exception from which others are derived.
-
fvwmpy.FvwmLaunchThis 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.IllegalOperationraised 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.FvwmErrorraised when FVWM does not understand communication from the module or the other way around.
-
fvwmpy.PipeDesyncThis 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_queueclass have method._resync()to seek the stream to the next pack. See packet queue section for more details.
Helper functions
-
fvwmpy.split_mask(mask)maskis 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
ored, one gets themaskback. -
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.
globstringis 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
globandGlobis 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.meString. The name of the executable file containing the module
-
m.aliasString. 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.aliasis 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.argsandm.aliaswill be the same asm.me.m.aliascan 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 FvwmAkaModulecommand. -
m.argsList 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.aliasis 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.maskInteger. 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_NAMEis 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.syncmaskandm.nograbmaskare similar to
m.maskbut 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_windowInteger. 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
Noneis passed. -
m.context_decoWindow 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.loggerA 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.criticalmethods below. The default level isfvwmpy.L_WARN, which keeps it relatively quiet. -
m.configm.configis the database containing information sent by FVWM during execution of Send_ConfigInfo command and withM_SENDCONFIGpackets. See alsom.getconfig()method andm.h_saveconfig()handler. For more details see section Config database below. -
m.winlistm.winlistis 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.winlistto be up to date at all times. See information onm.h_updatewlhandler.m.winlistinherits fromdict.m.winlist[<window_id>]is an instance offvwmpy._windowclass 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
dictmethods 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.handlersA 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.varandm.infostoreThese are special objects providing access to FVWM variables and infostore database.
See section FVWM variables and infostore below.
-
m.packetsA 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.msgis 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_windowis 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
finishedthen 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
msgto FVWM and request to send it back in the contextcontext_window. Iftimeoutis given and notNone, then return not later then after timeout seconds. If for some reason no reply was received from FVWM,Noneis 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 returnsTrueupon successful operation orFalseif something went wrong, pehapsM_END_CONFIG_INFOpacket was not received for timeout seconds. (Experimentation shows that FVWM needs not more then 0.05 seconds to send config under normal circumstances)handlermust beNoneor a callable taking one argument, which is a packet of type matchingfvwmpy.M_FOR_CONFIG. Ifhandleris not supplied or isNone, then the default handlerm.h_saveconfigis used.m.h_saveconfigjust fillsm.configdatabase with the information received from FVWM. See section Config database below.matchmust beNoneor a string to match module configuration lines against. If not supplied then'*' + m.aliasis 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 queueIf 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_SENDCONFIGsomewhere 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
Trueif operation was successful. Wait for at most timeout seconds forM_END_WINLISTpacket from FVWM before returning.handlershould be a callable taking one argument, which is a packet of type matchingfvwmpy.M_FOR_WINLIST. Ifhandleris not supplied then default handlerm.h_updatewlis used.m.h_updatewlsimply updatesm.winlistdatabase with the information received from FVWM. It also understandsfvwmpy.M_ADD_WINDOWandfvwmpy.M_DESTROY_WINDOWpackets 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 queueNote that
m.getwinlist()will also pick packets of typeM_ADD_WINDOWorM_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.winlistup 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_WINLISTsomewhere 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
finishedthen 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
Nonethan the corresponding mask is left unchanged.It is possible to have several embedded
m.push_masks--m.restore_masksconstructs. -
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.IllegalOperationexception is raised. -
m.register_handler(mask, handler)Register
handlerfor packets of type matchingmask. The default mainloop executes all the handlers for all matching packets in the order they were registered.handlershould be a callable taking one argument, which is a packet of type matchingmaskand should be capable of processing such a packet. Handlers should not raise any non-terminal exceptions.If
handleris 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_handlerfrom all queues where it is present. -
m.call_handlers(pack)Execute all handlers in the queue corresponding to the
pack's packet type passing packetpackto 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_CONFIGThis handler is capable of processing packets matching
fvwmpy.M_FOR_CONFIG|fvwmpy.M_SENDCONFIG. It simply records the information inm.configdatabase. 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_CONFIGm.h_saveconfig(pack)does not send NOP UNLOCK command to FVWM. In case you want to process configuration information synchronously registerm.h_unlockafterm.h_saveconfig. -
m.h_unlock(pack)Packets type:
M_ALLThis 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_unlockis the last one in the queues -
m.h_exit(pack)Packet types:
M_ALLThis handler ignores its argument, cleans things up and terminates the module.
-
m.h_nop(pack)Packet types:
M_ALLDo nothing.
-
m.h_updatewl(pack)Packet types:
M_FOR_WINLIST | M_ADD_WINDOW | M_DESTROY_WINDOWThis 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.winlistdatabase.
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.varOne 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_idwill return the value$[w.id]. You can not assign to or delete FVWM variables, som.var.w_id = <value>ordel m.var.w_idwill 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 == Nonethen module's context_window is assumed. Ifcontext_window == 0then 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.infostoreSimilarly, 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_variablewill 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_variableare 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
conditionsconditionsis a string containing the same conditions that are allowed in FVWM's conditional commands. See FVWM manual pages for explanations. For formatting convenienceconditionsmay 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.filtermay 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.windowwindow id -
w.frameid of the frame window -
w.wx,w.wyx,y location of the window’s frame -
w.wdx,w.wdywidth and height of the window’s frame -
w.deskdesktop number -
w.layerlayer -
w.hints_base_width,w.hints_base_heightwindow base width and height -
w.hints_width_inc,w.hints_height_incwindow resize width/height increment -
w.orig_hints_width_inc,w.orig_hints_height_incoriginal window resize width/height increment -
w.hints_min_width,w.hints_min_height,w.hints_max_width,w.hints_max_heightwindow minimum/maximum width/height -
w.icon_wicon label window id, or 0 -
w.icon_pixmap_wicon pixmap window id, or 0 -
w.hints_win_gravitywindow gravity -
w.text_pixelpixel value of the text color -
w.back_pixelpixel value of the window border color -
w.ewmh_hint_layerewmh layer -
w.ewmh_hint_desktopewmh desktop -
w.ewmh_window_typeewmh window type -
w.title_heightwindow title height -
w.border_widthborder width -
w.flagsis a bytearray containing style flags and action flags. See alsow.flag()method. -
w.win_namewindow name -
w.ico_nameicon name -
w.win_vis_namewindow visible name -
w.ico_vis_nameicon visible name -
w.res_classresolution class -
w.res_nameresolution name -
w.mini_ico_dx,w.mini_ico_dyToDo these -
w.mini_ico_depth -
w.winid_pix -
w.winid_mask -
w.mini_ico_filenameNOTE 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.DesktopSizethe size of the desktop (in pages) -
m.config.ImagePatha tuple of strings, each is the path where FVWM searches for images -
m.config.XineramaConfiga tuple of integers. See FVWM manual pages for the meaning. -
m.config.ClickTimeinteger. Click time in milliseconds -
m.config.IgnoreModifierstuple of integers. Modifiers that are ignored. -
m.config.colorsetslist 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)returnsTrueiff 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
timeoutisNoneit waits for the packet to arrive. If queue is empty andtimeoutis 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.readmethod, except the packet remains in the queue and will be returned with the nextm.packets.readorm.packets.peekcall, 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
pickerevaluates to true, possibly removing them from the queue, depending on the parameterkeep. The queue is searched until packet for whichuntilevaluates to true is found. Even if no packets are found, return aftertimeoutseconds.Note: the return value is always a
tuple, even if returning one or zero packets.-
pickermust 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. -
untilis the same type aspicker. The search in the queue will be terminated once the packet for whichuntilevaluated toTrueis encountered. If not given orNonethenuntilis set to be equal topicker. In that case the first (oldest) packet matchingpickerwill be found and returned (if it arrives withintimeoutseconds). -
keepis a boolean that indicates whether packets should be removed from the queue. -
timeoutindicates how many seconds shall the method wait foruntil(p)==True-packet. IftimeoutisNone, 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_PAGEp.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_DESKp.desk- Integer. Current desk number.
-
fvwmpy.M_OLD_ADD_WINDOW,fvwmpy.M_EXTENDED_MSG,fvwmpy.M_UNKNOWN1,fvwmpy.END_WINDOWLIST,M_END_CONFIG_INFONone
-
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_WINDOWp.window- Integer. Window idp.frame- Integer. Frame window id
-
fvwmpy.M_FOCUS_CHANGEp.window- As above.p.frame- As above.p.focus_change_typep.text_pixp.border_pix
-
fvwmpy.M_ICONIFY,fvwmpy.M_DEICONIFYp.window- As above.p.frame- As above.p.ix,p.iy- These and below are integers.p.idx,p.idyp.fx,p.fyp.fdx,p.fdy
-
fvwmpy.M_WINDOW_NAMEp.window- As above.p.frame- As above.p.win_name- String. Name of the window.
-
fvwmpy.M_ICON_NAMEp.window- As above.p.frame- As above.p.ico_name- String. Name of the icon window.
-
fvwmpy.M_RES_CLASSp.window- As above.p.frame- As above.p.res_class- String.
-
fvwmpy.M_RES_NAMEp.window- As above.p.frame- As above.p.res_name- String.
-
fvwmpy.M_ICON_LOCATIONp.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_SENDCONFIGp.string- String. The content depends on the type of the packet.
-
fvwmpy.M_ICON_FILEp.window- As above.p.frame- As above.p.ico_filename- String. Name of the image file.
-
fvwmpy.M_DEFAULTICONp.ico_defaultfilename- Supposed to be a string, but FVWM seems to send garbage.
-
fvwmpy.M_STRING,fvwmpy.MX_REPLYp.window- As above.p.frame- As above.p.string- String.
-
fvwmpy.M_MINI_ICONp.window- As above.p.frame- As above.p.mini_ico_dx,p.mini_ico_dy- Integer.p.mini_ico_depth- Integerp.winid_pixp.winid_maskp.mini_ico_filename- String.
-
fvwmpy.M_VISIBLE_NAMEp.window- As above.p.frame- As above.p.win_vis_name- String.
-
fvwmpy.M_RESTACKp.win_stack- List of triples of integers.
-
fvwmpy.MX_VISIBLE_ICON_NAMEp.window- As above.p.frame- As above.p.ico_vis_name- String.
-
fvwmpy.MX_PROPERTY_CHANGEp.prop_type- Integerp.val_1,p.val_2- Integerp.prop_str- String.
-
fvwmpy.ADD_WINDOW,fvwmpy.M_CONFIGURE_WINDOWThe attributes of the packets of these types are the same as the first 29 attributes of an instance offvwmpy._windowclass 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)fcnis a callable with packet as an argument orNone. Return a callable (picker object) equivalent to thefcnin the sense thatfvwmpy.picker(fcn)(p) == bool(fcn(p))for any packetp.If
fcnisNonethen 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)returnsTrueiff the packetpmatches maskMand 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 useglobandGlobobjects , described above to check matching of strings against glob patterns. See examples below.fvwmpy.pickerobjects can be conjoined with|,&or unary~operators. The resulting picker evaluated on packetpreturns value which isor,andornotof 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 packetphas key 'win_name' with a string value starting with 'fvwm' OR ifphas 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==987654321exceptM_DESTROY_WINDOWpacket.pickerobjects 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
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
|