oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
18,189 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-and-oxidized][OXWM — DWM but Better (and oxidized)]]
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 (and oxidized)
37
A dynamic window manager written in Rust, 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
* Installation
40
** NixOS (with Flakes)
41
*** Adding OXWM to your flake inputs
42
Add oxwm to your =flake.nix= inputs:
43
44
#+begin_src nix
45
{
46
  inputs = {
47
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
48
    oxwm.url = "github:tonybanters/oxwm";
49
    oxwm.inputs.nixpkgs.follows = "nixpkgs";
50
  };
51
52
  outputs = { self, nixpkgs, oxwm, ... }: {
53
    nixosConfigurations.yourhost = nixpkgs.lib.nixosSystem {
54
      system = "x86_64-linux";
55
      modules = [
56
        ./configuration.nix
57
        oxwm.nixosModules.default
58
      ];
59
    };
60
  };
61
}
62
#+end_src
63
64
*** Enabling OXWM in configuration.nix
65
Add this to your =configuration.nix=:
66
67
#+begin_src nix
68
{ config, pkgs, ... }:
69
70
{
71
  services.xserver = {
72
    enable = true;
73
    
74
    windowManager.oxwm.enable = true;
75
  };
76
77
  # Recommended: Install a display manager
78
  services.xserver.displayManager.lightdm.enable = true;
79
  # Or use another display manager like sddm, gdm, etc.
80
}
81
#+end_src
82
83
*** Initialize your config
84
After rebuilding your system with =sudo nixos-rebuild switch=, log in via your display manager.
85
86
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=.
87
88
*** Advanced: Using a specific oxwm version
89
If you want to pin or customize the oxwm package:
90
91
#+begin_src nix
92
{
93
  services.xserver.windowManager.oxwm = {
94
    enable = true;
95
    # Use a specific version or build with custom options
96
    package = oxwm.packages.${pkgs.system}.default;
97
  };
98
}
99
#+end_src
100
101
*** Development setup with Nix
102
For development, use the provided dev shell:
103
104
#+begin_src sh
105
# Clone the repository
106
git clone https://github.com/tonybanters/oxwm
107
cd oxwm
108
109
# Enter the development environment
110
nix develop
111
112
# Build and test
113
cargo build
114
just test
115
#+end_src
116
117
** Arch Linux
118
119
AUR: [[https://aur.archlinux.org/packages/oxwm-git][AUR URL]]
120
#+begin_src
121
yay -S oxwm-git
122
#+end_src
123
This will automatically put a desktop session file into your xsessions directory.
124
125
Manually:
126
Install dependencies:
127
#+begin_src sh
128
sudo pacman -S rust cargo libx11 libxft freetype2 fontconfig pkg-config
129
#+end_src
130
See Build from source
131
132
** Building from Source
133
#+begin_src sh
134
git clone https://github.com/tonybanters/oxwm
135
cd oxwm
136
cargo build --release
137
sudo cp target/release/oxwm /usr/local/bin/
138
#+end_src
139
140
Or use the justfile:
141
#+begin_src sh
142
just install
143
#+end_src
144
145
** Setting up OXWM
146
*** Without a display manager (startx)
147
Add the following to your =~/.xinitrc=:
148
#+begin_src sh
149
exec oxwm
150
#+end_src
151
152
Then start X with:
153
#+begin_src sh
154
startx
155
#+end_src
156
157
*** With a display manager
158
If using a display manager (LightDM, GDM, SDDM), OXWM should appear in the session list after installation.
159
160
* Configuration
161
OXWM uses a clean, functional Lua API for configuration. On first run, a default config is automatically created at =~/.config/oxwm/config.lua=.
162
163
** Quick Example
164
Here's what the new functional API looks like:
165
166
#+begin_src lua
167
-- Set basic options
168
oxwm.set_terminal("st")
169
oxwm.set_modkey("Mod4")
170
oxwm.set_tags({ "1", "2", "3", "4", "5", "6", "7", "8", "9" })
171
172
-- Configure borders
173
oxwm.border.set_width(2)
174
oxwm.border.set_focused_color("#6dade3")
175
oxwm.border.set_unfocused_color("#bbbbbb")
176
177
-- Configure gaps
178
oxwm.gaps.set_enabled(true)
179
oxwm.gaps.set_inner(5, 5)  -- horizontal, vertical
180
oxwm.gaps.set_outer(5, 5)
181
182
-- Set up keybindings
183
oxwm.key.bind({ "Mod4" }, "Return", oxwm.spawn("st"))
184
oxwm.key.bind({ "Mod4" }, "Q", oxwm.client.kill())
185
oxwm.key.bind({ "Mod4", "Shift" }, "Q", oxwm.quit())
186
187
-- Add status bar blocks
188
oxwm.bar.set_blocks({
189
    oxwm.bar.block.datetime({
190
        format = "{}",
191
        date_format = "%H:%M",
192
        interval = 60,
193
        color = "#0db9d7",
194
        underline = true,
195
    }),
196
    oxwm.bar.block.ram({
197
        format = "RAM: {used}/{total} GB",
198
        interval = 5,
199
        color = "#7aa2f7",
200
        underline = true,
201
    }),
202
})
203
#+end_src
204
205
** Features
206
- *Hot-reload*: Changes take effect immediately with =Mod+Shift+R= (no X restart needed)
207
- *LSP Support*: Full autocomplete and type hints for the API (=oxwm.lua= definitions included)
208
- *Functional API*: Clean, discoverable functions instead of nested tables
209
- *No compilation*: Edit and reload instantly
210
211
** Key Configuration Areas
212
Edit =~/.config/oxwm/config.lua= to customize:
213
- Basic settings (terminal, modkey, tags)
214
- Borders and colors
215
- Window gaps
216
- Status bar (font, blocks, color schemes)
217
- Keybindings and keychords
218
- Layout symbols
219
- Autostart commands
220
221
After making changes, reload OXWM with =Mod+Shift+R=
222
223
** Creating Your Config
224
Generate the default config:
225
#+begin_src sh
226
oxwm --init
227
#+end_src
228
229
Or just start OXWM - it will create one automatically on first run. 
230
231
* Contributing
232
When contributing to OXWM:
233
234
1. Never commit your personal =~/.config/oxwm/config.lua=
235
2. Only modify =templates/config.lua= if adding new configuration options
236
3. Test your changes with =just test= using Xephyr/Xwayland
237
4. Document any new features or keybindings
238
239
* Key Bindings
240
Default keybindings (fully customizable in =~/.config/oxwm/config.lua=):
241
242
| Binding                | Action                            |
243
|------------------------+-----------------------------------|
244
| Super+Return           | Spawn terminal                    |
245
| Super+J/K              | Cycle focus through stack         |
246
| Super+Q                | Kill focused window               |
247
| Super+Shift+Q          | Quit WM                           |
248
| Super+Shift+R          | Hot reload WM                     |
249
| Super+1-9              | View tag 1-9                      |
250
| Super+Shift+1-9        | Move window to tag 1-9            |
251
| Super+Ctrl+1-9         | Toggle tag view (multi-tag)       |
252
| Super+Ctrl+Shift+1-9   | Toggle window tag (sticky)        |
253
| Super+S                | Screenshot (maim)                 |
254
| Super+D                | dmenu launcher                    |
255
| Super+A                | Toggle gaps                       |
256
| Super+Shift+F          | Toggle fullscreen                 |
257
| Super+Shift+Space      | Toggle floating                   |
258
| Super+F                | Set normie (floating) layout      |
259
| Super+C                | Set tiling layout                 |
260
| Super+N                | Cycle layouts                     |
261
| Super+Comma/Period     | Focus prev/next monitor           |
262
| Super+Shift+Comma/.    | Send window to prev/next monitor  |
263
| Super+[/]              | Decrease/increase master area     |
264
| Super+I/P              | Inc/dec number of master windows  |
265
| Super+Shift+/          | Show keybinds overlay             |
266
| Super+Button1 (drag)   | Move window (floating)            |
267
| Super+Button3 (drag)   | Resize window (floating)          |
268
269
* Features
270
- *Dynamic Tiling Layout* with adjustable master/stack split
271
  - Master area resizing (mfact)
272
  - Multiple master windows support (nmaster)
273
- *Tag-Based Workspaces* (9 tags by default)
274
  - Multi-tag viewing (see multiple tags at once)
275
  - Sticky windows (window visible on multiple tags)
276
- *Multiple Layouts*
277
  - Tiling (master/stack)
278
  - Normie (floating-by-default)
279
  - Monocle (fullscreen stacking)
280
  - Grid (equal-sized grid)
281
  - Tabbed (tabbed windows)
282
- *Lua Configuration System*
283
  - Hot reload without restarting X (=Mod+Shift+R=)
284
  - LSP support with type definitions and autocomplete
285
  - No compilation needed - instant config changes
286
- *Built-in Status Bar* with modular block system
287
  - Battery, RAM, datetime, shell commands, static text
288
  - Custom colors, update intervals, and underlines
289
  - Click-to-switch tags
290
  - Multi-monitor support (one bar per monitor)
291
- *Advanced Window Management*
292
  - Window focus cycling through stack
293
  - Fullscreen mode
294
  - Floating window support
295
  - Mouse hover to focus (follow mouse)
296
  - Border indicators for focused windows
297
  - Configurable gaps (smartgaps support)
298
  - Window rules (auto-tag, auto-float by class/title)
299
- *Multi-Monitor Support*
300
  - RandR multi-monitor detection
301
  - Independent tags per monitor
302
  - Move windows between monitors
303
- *Keychord Support*
304
  - Multi-key sequences (Emacs/Vim style)
305
  - Example: =Mod+Space= then =T= to spawn terminal
306
- *Persistent State*
307
  - Window tags persist across WM restarts
308
  - Uses X11 properties for state storage
309
310
* Testing with Xephyr
311
Test OXWM in a nested X server without affecting your current session:
312
313
#+begin_src sh
314
just test
315
#+end_src
316
317
This starts Xephyr on display :1 and launches OXWM inside it.
318
319
Or manually:
320
#+begin_src sh
321
Xephyr -screen 1280x800 :1 &
322
DISPLAY=:1 cargo run
323
#+end_src
324
325
* Project Structure
326
#+begin_src sh
327
src/
328
├── bin/
329
│   └── main.rs                          [Entry point - handles CLI args, config loading, WM init]
330
│       ├── main()                       [Parse args, load config, start WM]
331
│       ├── load_config()                [Lua config loading with auto-init]
332
│       └── init_config()                [Create default config.lua + oxwm.lua]
333
334
├── lib.rs                               [Library exports]
335
336
├── window_manager.rs                    [CORE - X11 event handling]
337
│   ├── struct WindowManager
338
│   │   ├── connection: RustConnection   [X11 connection]
339
│   │   ├── windows: Vec<Window>         [All managed windows]
340
│   │   ├── focused_window: Option<Window>
341
│   │   ├── layout: Box<dyn Layout>
342
│   │   ├── window_tags: HashMap<Window, TagMask>
343
│   │   ├── selected_tags: TagMask
344
│   │   └── bars: Vec<Bar>               [Status bars (multi-monitor)]
345
│   │
346
│   ├── new()                            [Initialize WM, grab root, restore tags, scan windows]
347
│   ├── run()                            [Main event loop with block updates]
348
│   ├── handle_event()                   [Route X11 events]
349
│   ├── try_reload_config()              [Hot-reload Lua config]
350
│   └── ...                              [Window/tag/focus management]
351
352
├── config/
353
│   ├── mod.rs                           [Config module exports]
354
│   ├── lua.rs                           [Lua config parser - loads and executes config.lua]
355
│   └── lua_api.rs                       [Functional Lua API implementation]
356
│       ├── register_api()               [Set up oxwm.* functions in Lua]
357
│       ├── register_spawn()             [oxwm.spawn()]
358
│       ├── register_key_module()        [oxwm.key.bind(), oxwm.key.chord()]
359
│       ├── register_gaps_module()       [oxwm.gaps.*]
360
│       ├── register_border_module()     [oxwm.border.*]
361
│       ├── register_client_module()     [oxwm.client.*]
362
│       ├── register_layout_module()     [oxwm.layout.*]
363
│       ├── register_tag_module()        [oxwm.tag.*]
364
│       ├── register_bar_module()        [oxwm.bar.*]
365
│       └── register_misc()              [oxwm.set_terminal(), etc.]
366
367
├── bar/
368
│   ├── mod.rs                           [Re-exports: Bar, BlockCommand, BlockConfig]
369
│   ├── bar.rs
370
│   │   ├── struct Bar                   [Status bar window with XFT support]
371
│   │   ├── new()                        [Create bar X11 window, load font, init blocks]
372
│   │   ├── draw()                       [Render tags + blocks with underlines]
373
│   │   ├── update_blocks()              [Update block content based on intervals]
374
│   │   └── handle_click()               [Detect which tag was clicked]
375
│   ├── font.rs
376
│   │   ├── struct Font                  [XFT font wrapper]
377
│   │   └── draw_text()                  [Render text with color]
378
│   └── blocks/
379
│       ├── mod.rs                       [Block trait, BlockConfig, BlockCommand enum]
380
│       ├── battery.rs                   [Battery status block]
381
│       ├── datetime.rs                  [Date/time formatting block]
382
│       ├── ram.rs                       [RAM usage block]
383
│       ├── shell.rs                     [Shell command execution block]
384
│       └── static.rs                    [Static text block]
385
386
├── keyboard/
387
│   ├── mod.rs                           [Re-exports]
388
│   ├── keysyms.rs                       [X11 keysym constants]
389
│   └── handlers.rs
390
│       ├── enum KeyAction               [All keyboard actions]
391
│       ├── enum Arg                     [Action arguments]
392
│       ├── struct KeyBinding            [Keybinding + keychord support]
393
│       └── struct KeyPress              [Individual key press in chord]
394
395
├── layout/
396
│   ├── mod.rs                           [Layout trait definition]
397
│   ├── tiling.rs                        [Tiling layout with master/stack]
398
│   ├── monocle.rs                       [Fullscreen stacking layout]
399
│   ├── grid.rs                          [Equal-sized grid layout]
400
│   ├── tabbed.rs                        [Tabbed container layout]
401
│   └── normie.rs                        [Floating-by-default layout]
402
403
└── errors.rs                            [Error types: WmError, ConfigError, etc.]
404
405
templates/
406
├── config.lua                           [Default config with functional API]
407
└── oxwm.lua                             [LSP type definitions for autocomplete]
408
#+end_src
409
410
* Architecture Notes
411
** Lua Configuration System
412
OXWM uses mlua to embed a Lua interpreter. The functional API is implemented in =src/config/lua_api.rs=:
413
- Each API function (e.g., =oxwm.border.set_width()=) is registered as a Lua function
414
- Functions modify a shared ConfigBuilder that accumulates settings
415
- When config execution completes, the builder produces the final Config struct
416
- Type definitions in =templates/oxwm.lua= provide LSP autocomplete and documentation
417
418
** Tag System
419
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).
420
421
** Status Bar
422
The bar uses a performance-optimized approach with a modular block system:
423
- Only redraws when invalidated
424
- Pre-calculates tag widths on creation
425
- Blocks update independently based on their configured intervals
426
- Supports custom colors and underline indicators
427
- Color schemes (normal/occupied/selected) control tag appearance
428
- Easily extensible - add new block types in src/bar/blocks/
429
430
** Layout System
431
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.
432
433
* TODO Current Todo List:
434
** PRIORITY High [0/4]
435
- [ ] Add Window Titles to Bar
436
  - Show focused window title in status bar
437
  - Truncate if too long
438
  - Update on window focus change
439
- [ ] Add Horizontal Scroll Layout
440
  - Master window on left, stack scrolls horizontally
441
  - Alternative to vertical tiling
442
- [ ] Add Hide Empty Tag Numbers Option
443
  - Option to hide tags with no windows
444
  - Configurable via =oxwm.bar.set_hide_empty_tags(bool)=
445
- [ ] Add Swap Stack Bind
446
  - Keybind to swap focused window with master
447
  - Similar to dwm's zoom function (=Mod+Return=)
448
  - Should work bidirectionally
449
* Development Roadmap
450
** Current Focus (v0.8.0)
451
- Refactoring to align with dwm's proven patterns
452
- Improving core window management reliability
453
- Maintaining Lua config and bar features while simplifying internals
454
455
** Completed Features [8/8]
456
- [X] Multi-monitor support with RandR
457
- [X] Multiple layouts (tiling, monocle, grid, tabbed, normie)
458
- [X] Master area resizing (mfact) and nmaster support
459
- [X] Window rules (per-program auto-tag, floating)
460
- [X] Lua configuration with hot-reload
461
- [X] Built-in status bar with modular blocks
462
- [X] Keychord support (multi-key sequences)
463
- [X] Tag persistence across restarts
464
465
** Future Enhancements [/]
466
- [ ] Scratchpad functionality
467
- [ ] Dynamic monitor hotplugging (currently only on startup)
468
- [ ] External bar support (polybar, waybar compatibility)
469
- [ ] Additional layouts (deck, spiral, dwindle)
470
- [ ] Window minimize/restore
471
472
* License
473
[[https://www.gnu.org/licenses/gpl-3.0.en.html][GPL v3]]