Spook is an X11 Window Manager, focusing on modularity, and clean, well designed, object-oriented code. It is written in C++.
Spook is licensed under an unrestrictive X/MIT license. Basically, you just have to retain the license text.
The idea design- and implementation-wise is basically to take the time to think things through, instead of tossing together what works and saying I'll clean it up later. Also, I think it's important to avoid monoliths -- monolithic code blocks, monolithic files, monolithic libraries and applications. In fact, probably most of my time spent on Spook has been outside of Spook itself. :)
There will be no prejudice against keyboard or mouse, and for the most part, the behavior of the window manager with regard to input will be completely defined outside of the core of the window manager.
Callbacks are used extensively. You can put your own callbacks into the main loop itself. You can put callbacks into the X event handler for arbitrary X event types. The X event handler itself is simply a callback registered with the main loop. This stuff works right now. And of course there are a ton of ideas in my head of where to go.
Modules will be used, somewhat similar to gaim's plugins (or those of many other apps). Basically, compiled dynamic objects which the window manager will load and then communicate with. It is through this interface that you can register your callbacks and do whatever else you want. The window manager itself will have no "configuration files" or other such end-user-ish things; they will be implemented as modules. There could be a module which reads a text configuration file and registers key and mouse bindings based on what it parses. There could be modules which wrap scripting language interpreters so that you could script things in your favorite scripting language, just as you can do in Kahakai (python & ruby) and Sawfish (lisp). This is still being hashed out -- it works, but I still want to do some more reworking.
Me, Nick Welch, aka mackstann. A computer nerd in Iowa, US.
Spook is yet another spinoff of aewm, and Decklin Foster wrote that.
WIR! Basically - you definitely don't want to use it right now.
The thing runs and works with few crashes/etc., but it's not even worthy of calling alpha. Slow and steady is the key... I plan on this being a long-term project.
You can browse viewarch here, though it is often out of sync with my local copy. The arch archive itself is here (not always online).
I stripped out all of the Xlib drawing stuff that aewm had, and have not replaced it with anything, so right now you just get a random-colored titlebar with no text or buttons. :P Left mouse button moves the window, and right mouse button resizes it. Eventually I'll implement decor.
The problem with X event handling comes in when you consider that you essentially have to handle X errors, and they're called via a function pointer that you pass to xlib. This means that you can't really access the running program data from inside of the error handler, unless you have some global variables, singletons, or functions in the sky to use to grab onto the rest of the running program.
So after quite a bit of thinking (I may be a bit slow), and after seeing
Metacity's error handling scheme, I realized that it was pretty simple, and
allowed me to handle X errors without resorting to global variables, and in
fact, presented a solution somewhat similar to the try/catch
pattern for exception handling used in many languages. How it works is simple:
when you expect an X error may occur, you instantiate an
xerror_catch. You then do whatever it is you think might cause an
error, and afterwards, you check your xerror_catch instance and
see if it caught anything during that time. You can then retrieve the error
and do whatever is appropriate with it. You can nest them, and you can also
use a traditional X error handling function on the "outside" to catch
unexpected X errors.
sig_atomic_ts. You have no idea when your signal handler will be
called, so to be safe, you have to resort to things like blocking signals at
various parts of your code. A lot of people just ignore those restrictions
(it'll usually compile and run fine), which can cause extremely sporadic and
hard to detect bugs.
The solution is also similar to xerror_catch, but a little
different. Basically you set up a super simple signal handler that just
records the fact that that signal was received, and then you poll that
indicator at regular intervals, and if it is set, you take appropriate
action and then clear it. I don't want to explain it too much, because it
could change, so see the source. (libspook/signal_check.{cc,hh})
Modules are just dynamically loaded objects, like linux kernel modules, or the modules that Gaim, XMMS, The Golem WM, and many other apps use. They will be implemented using Glib::Module, which is a convenience wrapper around dlopen(), dlsym(), etc.
Callbacks are implemented using the boost signal/bind/function libraries. Essentially, the whole inner core of the window manager will just be a bunch of signals (events) that you connect slots (callback functions) to. This can be a platform not only for the default window manager behavior, but for (almost) any behavior a person would want to implement.
stderr. There are three formatter callbacks (one for a
prefix, one for formatting the actual log message, and one for a suffix),
which can be pointed at any function so that you can override them with
your own formatting. And that's about it. Simple and easy to wrap your
brain around, yet decently flexible.
Update: And the answer is... don't worry about it. This stuff (drawing) doesn't need to be in the core anyways. But the other part of the decor problem is how to organize the different areas of the decor, i.e. buttons, labels, handles, grips, etc. I think I'll basically give each decor object a container which contains sub-windows, each representing a thing like a button, label, etc. Each would have no specific meaning to the window manager; only to your module (or others that are aware of it). You'd create, say, a button decor piece, make it a certain size, set it to be at certain coordinates within the decor, give it drawing logic, and then register it with the core. You can then write modules that implement decor with different shapes, different drawing libraries, or whatever. The only restrictions within Spook will be that you can't nest decor pieces (I don't think that would be very useful, and it would be much much hairier), and, well.. that's it, I think. Oh, and geometry. There needs to be some way to tell Spook to put N pixels of padding on each of the 4 sides. And I'm not sure about shape extension support (for non-rectangular decor), but I'll probably do it eventually. I also suppose the client window should be at the bottom of the internal stacking of the whole frame window, so that decor can have little parts that hang over it if they want, for gee-whiz effects.