oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
15,547 bytes raw
1
#+AUTHOR: Tony
2
#+STARTUP: overview
3
4
[[file:./images/oxwm1.png]]
5
6
* Table of Contents :toc:
7
- [[#oxwm--dwm-but-better][OXWM — DWM but Better]]
8
- [[#installation][Installation]]
9
  - [[#nixos-with-flakes][NixOS (with Flakes)]]
10
  - [[#arch-linux][Arch Linux]]
11
  - [[#building-from-source][Building from Source]]
12
  - [[#setting-up-oxwm][Setting up OXWM]]
13
- [[#configuration][Configuration]]
14
  - [[#quick-example][Quick Example]]
15
  - [[#features][Features]]
16
  - [[#key-configuration-areas][Key Configuration Areas]]
17
  - [[#creating-your-config][Creating Your Config]]
18
- [[#contributing][Contributing]]
19
- [[#key-bindings][Key Bindings]]
20
- [[#features-1][Features]]
21
- [[#testing-with-xephyr][Testing with Xephyr]]
22
- [[#project-structure][Project Structure]]
23
- [[#architecture-notes][Architecture Notes]]
24
  - [[#lua-configuration-system][Lua Configuration System]]
25
  - [[#tag-system][Tag System]]
26
  - [[#status-bar][Status Bar]]
27
  - [[#layout-system][Layout System]]
28
- [[#current-todo-list][Current Todo List:]]
29
  - [[#priority-high-04][PRIORITY High]]
30
- [[#development-roadmap][Development Roadmap]]
31
  - [[#current-focus-v080][Current Focus (v0.8.0)]]
32
  - [[#completed-features-88][Completed Features]]
33
  - [[#future-enhancements-][Future Enhancements]]
34
- [[#license][License]]
35
36
* OXWM — DWM but Better
37
A dynamic window manager written in Zig, inspired by dwm but designed to evolve beyond it. OXWM features a clean, functional Lua API for configuration with hot-reloading support, ditching the suckless philosophy of *"edit + recompile"*. Instead, we focus on lowering friction for users with sane defaults, LSP-powered autocomplete, and instant configuration changes without restarting your X session.
38
39
*Documentation:* [[https://ox-docs.vercel.app/][ox-docs.vercel.app]]
40
41
* Installation
42
** NixOS (with Flakes)
43
*** Adding OXWM to your flake inputs
44
Add oxwm to your =flake.nix= inputs:
45
46
#+begin_src nix
47
{
48
  inputs = {
49
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
50
    oxwm.url = "github:tonybanters/oxwm";
51
    oxwm.inputs.nixpkgs.follows = "nixpkgs";
52
  };
53
54
  outputs = { self, nixpkgs, oxwm, ... }: {
55
    nixosConfigurations.yourhost = nixpkgs.lib.nixosSystem {
56
      system = "x86_64-linux";
57
      modules = [
58
        ./configuration.nix
59
        oxwm.nixosModules.default
60
      ];
61
    };
62
  };
63
}
64
#+end_src
65
66
*** Enabling OXWM in configuration.nix
67
Add this to your =configuration.nix=:
68
69
#+begin_src nix
70
{ config, pkgs, ... }:
71
72
{
73
  services.xserver = {
74
    enable = true;
75
    
76
    windowManager.oxwm.enable = true;
77
  };
78
79
  # Recommended: Install a display manager
80
  services.xserver.displayManager.lightdm.enable = true;
81
  # Or use another display manager like sddm, gdm, etc.
82
}
83
#+end_src
84
85
*** Initialize your config
86
After rebuilding your system with =sudo nixos-rebuild switch=, log in via your display manager.
87
88
On first launch, your initial config file will be automatically created and placed in =~/.config/oxwm/config.lua=. Edit it and reload with =Mod+Shift+R=.
89
90
*** Advanced: Using a specific oxwm version
91
If you want to pin or customize the oxwm package:
92
93
#+begin_src nix
94
{
95
  services.xserver.windowManager.oxwm = {
96
    enable = true;
97
    # Use a specific version or build with custom options
98
    package = oxwm.packages.${pkgs.system}.default;
99
  };
100
}
101
#+end_src
102
103
*** Development setup with Nix
104
For development, use the provided dev shell:
105
106
#+begin_src sh
107
# Clone the repository
108
git clone https://github.com/tonybanters/oxwm
109
cd oxwm
110
111
# Enter the development environment
112
nix develop
113
114
# Build and test
115
zig build
116
zig build test
117
#+end_src
118
119
** Arch Linux
120
121
AUR: [[https://aur.archlinux.org/packages/oxwm-git][AUR URL]]
122
#+begin_src
123
yay -S oxwm-git
124
#+end_src
125
This will automatically put a desktop session file into your xsessions directory.
126
127
Manually:
128
Install dependencies:
129
#+begin_src sh
130
sudo pacman -S zig lua libx11 libxft freetype2 fontconfig libxinerama
131
#+end_src
132
See Build from source
133
134
** Building from Source
135
#+begin_src sh
136
git clone https://github.com/tonybanters/oxwm
137
cd oxwm
138
zig build -Doptimize=ReleaseFast
139
zig build install-system  # installs to /usr/bin, adds desktop file and man page
140
#+end_src
141
142
To uninstall:
143
#+begin_src sh
144
zig build uninstall
145
#+end_src
146
147
** Setting up OXWM
148
*** Without a display manager (startx)
149
Add the following to your =~/.xinitrc=:
150
#+begin_src sh
151
exec oxwm
152
#+end_src
153
154
Then start X with:
155
#+begin_src sh
156
startx
157
#+end_src
158
159
*** With a display manager
160
If using a display manager (LightDM, GDM, SDDM), OXWM should appear in the session list after installation.
161
162
* Configuration
163
OXWM uses a clean, functional Lua API for configuration. On first run, a default config is automatically created at =~/.config/oxwm/config.lua=.
164
165
** Quick Example
166
Here's what the new functional API looks like:
167
168
#+begin_src lua
169
-- Set basic options
170
oxwm.set_terminal("st")
171
oxwm.set_modkey("Mod4")
172
oxwm.set_tags({ "1", "2", "3", "4", "5", "6", "7", "8", "9" })
173
174
-- Configure borders
175
oxwm.border.set_width(2)
176
oxwm.border.set_focused_color("#6dade3")
177
oxwm.border.set_unfocused_color("#bbbbbb")
178
179
-- Configure gaps
180
oxwm.gaps.set_enabled(true)
181
oxwm.gaps.set_inner(5, 5)  -- horizontal, vertical
182
oxwm.gaps.set_outer(5, 5)
183
184
-- Set up keybindings
185
oxwm.key.bind({ "Mod4" }, "Return", oxwm.spawn("st"))
186
oxwm.key.bind({ "Mod4" }, "Q", oxwm.client.kill())
187
oxwm.key.bind({ "Mod4", "Shift" }, "Q", oxwm.quit())
188
189
-- Add status bar blocks
190
oxwm.bar.set_blocks({
191
    oxwm.bar.block.datetime({
192
        format = "{}",
193
        date_format = "%H:%M",
194
        interval = 60,
195
        color = "#0db9d7",
196
        underline = true,
197
    }),
198
    oxwm.bar.block.ram({
199
        format = "RAM: {used}/{total} GB",
200
        interval = 5,
201
        color = "#7aa2f7",
202
        underline = true,
203
    }),
204
})
205
#+end_src
206
207
** Features
208
- *Hot-reload*: Changes take effect immediately with =Mod+Shift+R= (no X restart needed)
209
- *LSP Support*: Full autocomplete and type hints for the API (=oxwm.lua= definitions included)
210
- *Functional API*: Clean, discoverable functions instead of nested tables
211
- *No compilation*: Edit and reload instantly
212
213
** Key Configuration Areas
214
Edit =~/.config/oxwm/config.lua= to customize:
215
- Basic settings (terminal, modkey, tags)
216
- Borders and colors
217
- Window gaps
218
- Status bar (font, blocks, color schemes)
219
- Keybindings and keychords
220
- Layout symbols
221
- Autostart commands
222
223
After making changes, reload OXWM with =Mod+Shift+R=
224
225
** Creating Your Config
226
Generate the default config:
227
#+begin_src sh
228
oxwm --init
229
#+end_src
230
231
Or just start OXWM - it will create one automatically on first run. 
232
233
* Contributing
234
When contributing to OXWM:
235
236
1. Never commit your personal =~/.config/oxwm/config.lua=
237
2. Only modify =templates/config.lua= if adding new configuration options
238
3. Test your changes with =zig build xephyr= using Xephyr or =zig build xwayland= using Xwayland
239
4. Document any new features or keybindings
240
241
* Key Bindings
242
Default keybindings (fully customizable in =~/.config/oxwm/config.lua=):
243
244
| Binding                | Action                            |
245
|------------------------+-----------------------------------|
246
| Super+Return           | Spawn terminal                    |
247
| Super+J/K              | Cycle focus through stack         |
248
| Super+Q                | Kill focused window               |
249
| Super+Shift+Q          | Quit WM                           |
250
| Super+Shift+R          | Hot reload WM                     |
251
| Super+1-9              | View tag 1-9                      |
252
| Super+Shift+1-9        | Move window to tag 1-9            |
253
| Super+Ctrl+1-9         | Toggle tag view (multi-tag)       |
254
| Super+Ctrl+Shift+1-9   | Toggle window tag (sticky)        |
255
| Super+S                | Screenshot (maim)                 |
256
| Super+D                | dmenu launcher                    |
257
| Super+A                | Toggle gaps                       |
258
| Super+Shift+F          | Toggle fullscreen                 |
259
| Super+Shift+Space      | Toggle floating                   |
260
| Super+F                | Set normie (floating) layout      |
261
| Super+C                | Set tiling layout                 |
262
| Super+N                | Cycle layouts                     |
263
| Super+Comma/Period     | Focus prev/next monitor           |
264
| Super+Shift+Comma/.    | Send window to prev/next monitor  |
265
| Super+[/]              | Decrease/increase master area     |
266
| Super+I/P              | Inc/dec number of master windows  |
267
| Super+Shift+/          | Show keybinds overlay             |
268
| Super+Button1 (drag)   | Move window (floating)            |
269
| Super+Button3 (drag)   | Resize window (floating)          |
270
271
* Features
272
- *Dynamic Tiling Layout* with adjustable master/stack split
273
  - Master area resizing (mfact)
274
  - Multiple master windows support (nmaster)
275
- *Tag-Based Workspaces* (9 tags by default)
276
  - Multi-tag viewing (see multiple tags at once)
277
  - Sticky windows (window visible on multiple tags)
278
- *Multiple Layouts*
279
  - Tiling (master/stack)
280
  - Normie (floating-by-default)
281
  - Monocle (fullscreen stacking)
282
  - Grid (equal-sized grid)
283
  - Tabbed (tabbed windows)
284
- *Lua Configuration System*
285
  - Hot reload without restarting X (=Mod+Shift+R=)
286
  - LSP support with type definitions and autocomplete
287
  - No compilation needed - instant config changes
288
- *Built-in Status Bar* with modular block system
289
  - Battery, RAM, datetime, shell commands, static text
290
  - Custom colors, update intervals, and underlines
291
  - Click-to-switch tags
292
  - Multi-monitor support (one bar per monitor)
293
- *Advanced Window Management*
294
  - Window focus cycling through stack
295
  - Fullscreen mode
296
  - Floating window support
297
  - Mouse hover to focus (follow mouse)
298
  - Border indicators for focused windows
299
  - Configurable gaps (smartgaps support)
300
  - Window rules (auto-tag, auto-float by class/title)
301
- *Multi-Monitor Support*
302
  - RandR multi-monitor detection
303
  - Independent tags per monitor
304
  - Move windows between monitors
305
- *Keychord Support*
306
  - Multi-key sequences (Emacs/Vim style)
307
  - Example: =Mod+Space= then =T= to spawn terminal
308
- *Persistent State*
309
  - Window tags persist across WM restarts
310
  - Uses X11 properties for state storage
311
312
* Testing with Xephyr
313
Test OXWM in a nested X server without affecting your current session:
314
315
#+begin_src sh
316
zig build xephyr
317
#+end_src
318
319
This starts Xephyr on display :2 and launches OXWM inside it.
320
321
For multi-monitor testing:
322
#+begin_src sh
323
zig build xephyr-multi
324
#+end_src
325
326
Or manually:
327
#+begin_src sh
328
Xephyr -screen 1280x800 :2 &
329
DISPLAY=:2 zig build run
330
#+end_src
331
332
* Project Structure
333
#+begin_src sh
334
src/
335
├── main.zig                             [Entry point - handles CLI args, config loading, WM init]
336
├── client.zig                           [Client/window management]
337
├── monitor.zig                          [Monitor handling and multi-monitor support]
338
├── overlay.zig                          [Overlay rendering]
339
├── animations.zig                       [Animation support]
340
341
├── config/
342
│   ├── config.zig                       [Config struct and defaults]
343
│   └── lua.zig                          [Lua config parser - loads and executes config.lua]
344
345
├── bar/
346
│   ├── bar.zig                          [Status bar with XFT support]
347
│   └── blocks/
348
│       ├── blocks.zig                   [Block system core]
349
│       ├── format.zig                   [Block formatting utilities]
350
│       ├── battery.zig                  [Battery status block]
351
│       ├── datetime.zig                 [Date/time formatting block]
352
│       ├── ram.zig                      [RAM usage block]
353
│       ├── cpu_temp.zig                 [CPU temperature block]
354
│       ├── shell.zig                    [Shell command execution block]
355
│       └── static.zig                   [Static text block]
356
357
├── layouts/
358
│   ├── tiling.zig                       [Tiling layout with master/stack]
359
│   ├── monocle.zig                      [Fullscreen stacking layout]
360
│   ├── floating.zig                     [Floating layout]
361
│   └── scrolling.zig                    [Scrolling layout]
362
363
└── x11/
364
    ├── xlib.zig                         [X11/Xlib bindings]
365
    ├── display.zig                      [Display management]
366
    └── events.zig                       [X11 event handling]
367
368
templates/
369
├── config.lua                           [Default config with functional API]
370
└── oxwm.lua                             [LSP type definitions for autocomplete]
371
#+end_src
372
373
* Architecture Notes
374
** Lua Configuration System
375
OXWM embeds a Lua 5.4 interpreter using Zig's C interop. The functional API is implemented in =src/config/lua.zig=:
376
- Each API function (e.g., =oxwm.border.set_width()=) is registered as a Lua function
377
- Functions modify the config state that accumulates settings
378
- When config execution completes, the final Config struct is produced
379
- Type definitions in =templates/oxwm.lua= provide LSP autocomplete and documentation
380
381
** Tag System
382
Tags are implemented as bitmasks (TagMask = u32), allowing windows to belong to multiple tags simultaneously. Each window has an associated TagMask stored in a HashMap. Tags persist across WM restarts using X11 properties (_NET_CURRENT_DESKTOP for selected tags, _NET_CLIENT_INFO for per-window tags).
383
384
** Status Bar
385
The bar uses a performance-optimized approach with a modular block system:
386
- Only redraws when invalidated
387
- Pre-calculates tag widths on creation
388
- Blocks update independently based on their configured intervals
389
- Supports custom colors and underline indicators
390
- Color schemes (normal/occupied/selected) control tag appearance
391
- Easily extensible - add new block types in src/bar/blocks/
392
393
** Layout System
394
The tiling layout divides the screen into a master area (left half) and stack area (right half). The master window occupies the full height of the master area, while stack windows split the stack area vertically. Gaps are configurable and can be toggled at runtime.
395
396
* TODO Current Todo List:
397
** PRIORITY High [0/4]
398
- [ ] Add Window Titles to Bar
399
  - Show focused window title in status bar
400
  - Truncate if too long
401
  - Update on window focus change
402
- [ ] Add Horizontal Scroll Layout
403
  - Master window on left, stack scrolls horizontally
404
  - Alternative to vertical tiling
405
- [ ] Add Hide Empty Tag Numbers Option
406
  - Option to hide tags with no windows
407
  - Configurable via =oxwm.bar.set_hide_empty_tags(bool)=
408
- [ ] Add Swap Stack Bind
409
  - Keybind to swap focused window with master
410
  - Similar to dwm's zoom function (=Mod+Return=)
411
  - Should work bidirectionally
412
* Development Roadmap
413
** Current Focus (v0.8.0)
414
- Refactoring to align with dwm's proven patterns
415
- Improving core window management reliability
416
- Maintaining Lua config and bar features while simplifying internals
417
418
** Completed Features [8/8]
419
- [X] Multi-monitor support with RandR
420
- [X] Multiple layouts (tiling, monocle, grid, tabbed, normie)
421
- [X] Master area resizing (mfact) and nmaster support
422
- [X] Window rules (per-program auto-tag, floating)
423
- [X] Lua configuration with hot-reload
424
- [X] Built-in status bar with modular blocks
425
- [X] Keychord support (multi-key sequences)
426
- [X] Tag persistence across restarts
427
428
** Future Enhancements [/]
429
- [ ] Scratchpad functionality
430
- [ ] Dynamic monitor hotplugging (currently only on startup)
431
- [ ] External bar support (polybar, waybar compatibility)
432
- [ ] Additional layouts (deck, spiral, dwindle)
433
- [ ] Window minimize/restore
434
435
* License
436
[[https://www.gnu.org/licenses/gpl-3.0.en.html][GPL v3]]