nwwm
- 4 Devlogs
- 13 Total hours
a WIP tiling window manager for X, inspired by dwm
a WIP tiling window manager for X, inspired by dwm
we’re now shifting from the realm of “experimental” to “experimental but usable”. i’ve added a ton of new features recently and i’m really happy with how nwwm is coming together.
i’ve added 2 new tiling layouts: monocle, and master/stack. monocle is the easiest to understand: all windows are the same size as the screen, and the currently focused window is brought to the front. master/stack is the traditional layout you see in wms like dwm, where there is a “master” window that takes up half of the screen and the rest split vertically (or “stack”) on the other half of the screen. i also added keybinds that switch between layouts
previously, the keybind system was just using raw x11 keycodes which were really annoying because they don’t match up with any other system (25 = w??) and are keymap-dependant. so, i switched to using xkbcommon and now keybinds are defined with more human-readable keysyms like KEY_w or KEY_Return.
i also implemented a small command runner system so now you can launch commands with keybinds. so far i’ve set Mod+Enter to launch kitty and ofc these will all be configurable through the config file
i spent ages trying to debug some weird behaviour where bound keys wouldn’t register as keypresses if no windows had been opened in nwwm yet. after a lot of trial and error, and a few ChatGPT therapy sessions, i discovered that my error was one letter: i had keyboard_mode in the global mouse grab (which i need for click to focus) set to GrabMode::Sync instead of GrabMode::Async (fml)
how many times can i call conn.send_request() in one program??
i made a struct called Config which the wm owns, and it has values like border width, color, and keybinds. eventually it will read from a config.toml file but for now it’s all hard coded in the source code.
windows now have borders with color and width deriving from the Config (meaning they’ll be configurable through a config file at some point!). also, the currently focused window has a different border color (also configurable!)
instead of hard-coding keybinds, i gave Config a child called Keybinds, which are hard coded in the source code… but eventually they’ll be part of the config file. when each keybind is called, it calls an Action which is linked to a function call in the wm. later there’ll be plenty of actions for anything you can think of, but for now theres only FocusNext which… focuses the next window!
x11 is an ancient beast, full of mismatched types (screen height is a u16, window height is a u32, window position is an i32, etc), difficult protocols, and more double colons than you can shake a stick at, but i’m working through it.
i started off by storing a list of open workspaces in the main wm struct, and each workspace has a list of open windows (and a tiling layout). then, i made the wm listen for DestroyNotify events and remove them from their respective workspaces. soon after marvelling at my creation i realised that i could only see one window at a time, so i worked on implementing a basic tiling algorithm. so far, all i have is columns (window_width = screen_width / num_of_windows) but i’m working on adding master-stack tiling (what dwm uses)
i also realised that it’s no use having multiple windows if you can only use type on one, so i made each window grab the left click, and then listen for ButtonPress events, focusing the clicked window.
after working on tundra I decided that I wanted to make a window manager for an actual os instead, so I loaded arch onto an old macbook and got started.
I initially started by loosely following a tutorial that uses xlib for rust, but I soon realised that any direct mapping to C from rust is going to be an absolute horror to use (literally every function call had to be unsafe), so I switched to xcb. it has a slightly different API but it’s cleaner and i3 uses it so it must be good.