Acdwm, Part 2

schemify, schemify!

I've decided to write my own X window manager, despite the fact that X is dying and all that. I'm doing it for fun but also to get more better at scheme (CHICKEN) and C interop, I think... Anyway, I'm going to write about my experiences here. You can view the current state of the project at its git repository.

Hi there, it's been a minute -- since uh, January 2. Oh so just like 2 weeks, that's not so bad. ANYWAY.

I've made a good number of changes in the repo. I did that thing where I moved ~/src/acdwm to ~/src/acdwm_ and re-typed the whole thing while referring to the original. I reorganized the project from a one-file pure translation of tinywm.c to a more modular project with schemier wrappers for things (I hope). You can check out the code for this iteration on git or download a tarball.

Now, I have three submodules—xlib, keys, and events—and a utility module (aptly named util).

(acdwm xlib)

Eventually, I'd like to have only this library do anything with raw X calls. Until then, I've re-exported CHICKEN's xlib library so that other libraries in acdwm only have to import (acdw xlib).

Since last time, I've written a macro to define event predicates for all the types of events xlib defines. This means I can write (buttonpress? event) instead of (= BUTTONPRESS (xevent‑type event)), which I find much easier to deal with. I also figured out the Xevent structure's ... structure, and written a procedure-writing macro to convert the union type to its constituent parts. I suppose I could write a xevent-subtype procedure to check the type and just convert the thing to that. Though really I should wrap all these types in an Xevent record type ... anyway that's for next time I suppose!

Things I really need to work on as I continue include

(acdwm keys)

A major addition was made in my key- and button-handling code, which makes sense because tinywm's is minimal, to say the least. I added record types for keybinds and mousebinds, set up code to collect bindings in a list parameter to be grabbed and decided upon later in execution (so you just have to define a binding once), and keybind-parsing code so you can define keys using strings like "C-M-r", which I'm actually fairly proud of. Now,the M-F1 binding from tinywm can be defined simply as

(bind "M-<F1>" (lambda (ev dpy)
    (let ((win (xevent-xkey-subwindow ev)))
    (when (some? win)
    (xraisewindow dpy win)))))

which, indeed, it is.

I considered writing a macro for bind that would let me not specify the lambda bit, going straight into the body... but I realized that I'd need to inject the event and display into the definition, or do something really evil like making the current event a parameter. shudder

(acdwm events)

The main differences here are refactoring handle-events to dispatch based on the event and new dragging code to allow more customizability. The dragging bit was pretty complicated because of the amount of state held in the tinywm event loop, and the apparently multiple ways to actually grab the mouse in Xlib. I finally figured it out by creating a new drag record type and creating a parameter to hold an instance of that type. Honestly, I will proably refactor that again because having a record type with one instance is ... meh.

(acdw util)

My utility library is trying to be as minimal as possible, but you know how it is with Scheme (if you don't, projects tend to accrete utility functions). So far, the most useful is the define-public macro, stolen from guile, and dprint procedure, which prints debugging stuff when needed.

shoutouts

This project is teaching me a lot but I also am learning from good people. These include

addendum

(not really; I haven't even finished writing the post proper but was getting distracted by the thought of porting to xcb, a terrible idea for now)

I just found the guile-xcb project by Mark Witmer, which features a tinywm port. I like the way this code looks in the wm, so I'm defiitely going to be studying the ideas in this codebase for acdwm.

You've just read an exciting episode of my journey into writing an X window manager in CHICKEN scheme. Feel free to read the code (it's linked above) and tell me how awful it is by sending me an email!