Python Window Manager
31.3.2006: Suggestions for feature enhancements wanted! Note that packaging (debianizing especially) is being worked on.
Please join email@example.com and shoot.
26.3.2006: New release with better docs and smarter window placement (whoa, something new ;)
19.3.2006: A new release with more code cleaning
13.3.2006: Some maintaining already done =), mainly cleaning and some minor bugs and a new release, see below...
27.2.2006: A new maintainer: Elmo Mäntynen (that's me) is going to try to do some maintaining
on pywm, mainly helping interested people and bug hunting, but is hoping to do some developing also.
A new release has been made already, see below...
8/3/2005: I'm currently concentrating on figuring out how to write the event catcher portion
of PyWM, as I think that it is the most immediately useful, and doesn't require much from the
other portions to be useful.
6/28/2005: PyWM has recently had a change of developers: After two years of no activity
on the project, David has offered the Sourceforge admin/developer stick to Jon Wilson.
Jon intends to (not sure if this is going to happen, Jon has been busy) largely rewrite the window manager, using the current PyWM codebase as a
jumping off point. See Design Philosophy.
PYWM is a small, simple python-programmable X window manager that's packed with features,
yet very easy to learn and use. It gives you easy-to-use tools to create your own personal dream desktop.
Control Freak Heaven.
Some window managers are mouse heaven and keyboard hell. Other window
managers are the other way around.
But PYWM aims to be very comfortable to use from either.
At the moment PYWM is a "pythonised" version of the fast and light FLWM window manager,
but it migth grow up and lose all the c(++) code.
So What Can I Do With It?
All sorts of stuff, limited only by your imagination. Here's a short
(and very incomplete) list:
- Infinite-sized desktop with keyboard panning (and zooming!!)
- Ability to create new desktops on the fly
- 'Lock' certain windows, so they won't be moved or resized during
zooming or panning.
- Move/resize/close individual windows with key bindings
- Detect when windows are created/destroyed/moved/resized, and take
- For instance, detect certain applications, and move/resize them
- Set timers, to take actions once or repeatedly (one of the examples has a function called
'hallucinate' which randomly moves/resizes all the windows on the
- Turn window borders and
titlebars on and off
- Dock unrelated application windows together. Or, if one
application is started, launch another one automatically
- Diaplay a different wallpaper when each given window is activated
(would you really want this???)
- Have a different set of key bindings for each active window
- In addition to this, I'm currently working on an (FLTK-based) API
to allow you to create 'in-window-manager' windows, so you can very
easily build your own applets.
(Also, I'm hoping at some time to incorporate joystick-driven zoom/pan
(anyone wanna volunteer?)
I've seen dozens of window managers in my time.
At one extreme are the morbidly obese KDE and Gnome desktops, which can
take longer to fire up than Linux itself! One wonders if development of
these two projects is funded by manufacturers of memory and hard disks
At the other extreme are hard-core 'minimalist' window managers like
'LWM' and 'TWM', which can be very functionality-challenged, or have
some annoying quirks. For example, one WM I tried requires you to hold
down the ALT key while using the mouse within a window!
On the fringes are 'rodentophobic' window managers like Matchbox,
RatPoison, Ion etc. One thinks of certain people (who will go nameless)
who take pride in still using ASCII dumb terminals.
On the advanced end of the spectrum is the wonderful LISP-driven
'Sawfish' window manager.
But PyWM is aimed at the middle ground. On one hand, it's easy to set
up magickal key bindings to do pretty much what you want. But on the
other hand, it's also comfortable and courteous for mouse users. I find
myself often switching from mouse/keyboard to straight keyboard, so
PyWM is there for me all the way.
And, above all, it's built to support easy
customisation in Python,
the world's coolest
The window manager itself should have four main components:
This will be made EWMH and ICCCM compliant. Then it will be able to be
used underneath gnome, kde, etc.
- a program which catches all events from the X server and sends them on to be handled. This would be
in C, for speed as well as closer interaction with X. Since this should be quite simple, the relative
difficulty of changing it (as compared to parts written in python or other scripting languages) would
not be an issue.
- a set of scripts, probably in python, that actually handle the events caught by the above. This is
where the bulk of what distinguishes one window manager from another occurs.
Python is chosen so that the behavior of the window manager is easily changed by the user on the
fly. Also, using a full scale programming language as configuration means that the window manager
can be configured in ways that the developers never dreamed of.
- a bare-bones window management server which manages the windows (takes care of placing them,
resizing them, etc.) as well as doing various virtual desktop/multiple
desktop stuff. This would probably be written in C as well, for the same reasons.
- a client library which includes functions to control the server, and to
return requested information from the server to the clients. It would
communicate with the server by means of a unix domain socket.
This would be similar to sawfish-client from the sawfish
window manager, but would be implemented as a shared library rather than a
LISP interpreter. Various language bindings to this library would be provided
by means of swig or
or a similar tool. Most likely swig, as I'm familiar with it, and it provides
support for a large number of popular languages.
The window manager will NOT implement:
- desktop pagers
- a GUI toolkit
- configuration dialogs
These would all be separate programs and/or scripts and/or libraries.
When the event catcher gets an event, it would spawn a new thread, and go back to
listening for new events (spawning a new thread to actually handle the events means
that we can get back to listening much more quickly, which would hopefully improve
the system's responsiveness.). The new thread would then start the python interpreter,
calling a function to actually handle the event. Anything from this point would be
completely reprogrammable on the fly by the user. For example, on a button click on
the root window, some users might want to start a menu process, and some users might
want to make an icon selection box. Or, on a window map event, some users might want
reparent the window into a frame, and some users might want to position the window to
tile nicely with all the other windows on the screen, but leave it frameless (a la Ratpoison).
Some actions, such as clicking and dragging on a frame window, might want to communicate
with the window management server (tell it to move or resize the window). In this case,
the script would need access to the client library, so it could send signals to the server.
- Menus would be standalone programs which would be executed by
the event handling scripts. Or, they could be coded into the scripts directly.
Large possiblities are open here.
It would be possible, of course, and perhaps preferable, to create
a program which took as an argument the name of a menu-describing file,
then read and parsed that file to populate the menu. This would enable the
creation and editing of menus without any sort of programming overhead.
Additionally, a graphical menu editor could be written with ease in this scenario.
- Frames would similarly be implemented by standalone programs. Whenever a
window is mapped on the screen, the event handler would (for example) call a new program.
This program could then create a frame window,
and ask the wm (via the client lib) to associate it with the newly mapped window. A good frame manager
might cache frames, so that if a window is unmapped (e.g. by being iconified) and remapped, the frame
would not need to be regenerated. Frames could be managed on a per-window basis, or
held constant over all windows, depending on the program. Additionally, a frame manager could be written
that would understand and use any number of different window manager's themes. For example,
an Enlightenment theme, or blackbox theme frame manager could be written.
- Users would be free to run gnome-panel, or kicker, or any other panel/toolbar/menubar
of their choosing (or writing!). Of course, one benefit to running well-established toolbars would be
the number of applets already available.
- When a window is iconified, an icon manager could be notified, and add that window to
its icon list. Or, a window list could be notified whenever the virtual workspace changes, and only
display windows present in that workspace (a la gnome's window list applet).
- A config dialog could be created using the client lib, or, using the various scripting language
bindings and an interpreter, it would be easily possible to control the window manager interactively.
A number of these clients would be written as part of the PyWM project,
but would not be part of the PyWM distribution itself. They would instead have their own separate
distributions, as befits separate projects. Some packagers might choose to bundle a number of
clients along with PyWM itself, but that would naturally be up to their discretion.
I think that this is very much in the spirit of unix development as a
whole (do one thing well, and not anything else at all), as well as
being closest to what I've been looking for in a window manager.
What's the Python Scenario?
I've taken the FLWM
window manager and wrapped it into a Python module as a 'window manager
You drive PYWM by creating a subclass of the basic pywm.WM window manager class. If
you want even more per-window control, you can subclass the pywm.window class as well. Plenty of
examples in the PYWM distribution you can use as a starting point.
If you like, why not browse the documentation
Within your derived classes, you write event handlers, which receive
all kinds of window manager related events, and within the event handler
methods, can pick from a large range of actions.
The PyWM API is kept clean, simple and intuitive. So you won't be
dragging your ass through unreadable source code and
incomplete/inaccurate documentation for hours just to figure out how to
do basic stuff. There are some
programmers who get a perverse rush from making their APIs as
complicated and obscure as possible. For example, in raw X, it takes 12
args to a function to get just the title of a window! But that's not
how I work...
Within your handlers, you can:
Your handlers can receive events, such as:
- Move/resize windows
- Hide/Show/Close windows
- Launch other apps
- Switch between desktops
- Dynamically bind, rebind and unbind keystrokes
- Create screen 'hotspots' and 'hot-edges' - which are activated
when the mouse goes to an area on the screen (or clicks there).
- Set timers to fire your own callbacks - once or repeatedly
In contrast to other Python-driven window managers, this one is so easy
and intuitive that you'll be hacking your own window manager script in a
couple of minutes. A set of easily-undersood example scripts is included
with the distribution.
- Window manager startup
- Window gets created
- Window gets destroyed
- Mouse enters a window
- Window gets moved or resized
- Custom key sequence is received
- Mouse click is received
- Timers (set by yourself)
Caveat - due to some quirks in Pyrex, some exceptions may not appear on
stdout - if things ever look weird, just sprinkle in a few print
statements while debugging, until you figure out what's happening.
Also, while you're testing/debugging your Python script, you're best
advised to put 'xterm' in your .xinitrc, and launch your script
manually within the xterm window, or, even better from a virtual console.
What Do I Need?
Requirements (read INSTALL):
- Python >=2.2
- Pyrex - the Python<->C wrapper generator: http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/
(only if building from source)
- FLTK version 1.0 (the new release should work with 1.1, which is distributed with debian at least) - available from here
on the FLTK
homepage (only if building from source)
- xlibs-dev (only if building from source)
- The Leo
metastructural code editor (optional) - makes the source much more
- if your system has glibc 2.2 or later, and Python 2.2.1 or later,
you can save yourself the need to download/install/compile FLTK 1.0 and
and use the the orignal 0.1 tarball, link below
though I will probably release binaries in the future, especially if requested...).
Where's It At?
PyWM is in a prototype state, but it's
working well enough to offer for download and review.
Be warned that if your scripting has errors, it can take the X server
down with it, killing off your apps and causing possible loss of data.
There may also be bugs in the FLWM core, or in the PyWM code, which
cause stability problems as well.
So if you want to play around with PyWM, please observe the following:
- While working on your scripts, write your ~/.xinitrc file to
launch xterm (or your favourite console window). Then, launch your PyWM
script from within a virtual console. That way, if your script crashes (and
doesn't take down X), you can fix it and re-launch it
- Never, NEVER have any applications open with important data while
you're working on your PyWM scripts. Don't trust your script until
you've tested it thoroughly.
- When running other applications within your PyWM environment, be
sure to save your data often.
- If you see any really weird and unexplainable things happening on
your desktop, or apps refusing to run, try restarting the X server. If
this doesn't work, try rebooting.
I'm Curious - Gimme a Copy!
You're encouraged try it on your own, but if after some serious effort (I intend to make it frendlier)
you can't get it to work, please join pywm-talk and post your questions there (or mail me, drayko *at* users.sf.net).
Download PYWM from the sf.net files here (recommended),
or the old 0.1 release here (the original archive from David Mcnab).
Page updated 2 Apr,
2006 by Elmo Mäntynen