oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
15,540 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
- [[#contributing][Contributing]]
15
- [[#key-bindings][Key Bindings]]
16
- [[#features][Features]]
17
- [[#testing-with-xephyr][Testing with Xephyr]]
18
- [[#project-structure][Project Structure]]
19
- [[#architecture-notes][Architecture Notes]]
20
  - [[#tag-system][Tag System]]
21
  - [[#status-bar][Status Bar]]
22
  - [[#layout-system][Layout System]]
23
- [[#current-todo-list][Current Todo List:]]
24
  - [[#priority-high-02][PRIORITY High]]
25
  - [[#priority-medium-14][PRIORITY Medium]]
26
  - [[#priority-low-11][PRIORITY Low]]
27
- [[#development-roadmap][Development Roadmap]]
28
  - [[#current-focus][Current Focus]]
29
  - [[#future-enhancements][Future Enhancements]]
30
- [[#license][License]]
31
32
* OXWM — DWM but Better (and oxidized)
33
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.
34
35
* Installation
36
** NixOS (with Flakes)
37
*** Adding OXWM to your flake inputs
38
Add oxwm to your =flake.nix= inputs:
39
40
#+begin_src nix
41
{
42
  inputs = {
43
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
44
    oxwm.url = "github:tonybanters/oxwm";
45
    oxwm.inputs.nixpkgs.follows = "nixpkgs";
46
  };
47
48
  outputs = { self, nixpkgs, oxwm, ... }: {
49
    nixosConfigurations.yourhost = nixpkgs.lib.nixosSystem {
50
      system = "x86_64-linux";
51
      modules = [
52
        ./configuration.nix
53
        oxwm.nixosModules.default
54
      ];
55
    };
56
  };
57
}
58
#+end_src
59
60
*** Enabling OXWM in configuration.nix
61
Add this to your =configuration.nix=:
62
63
#+begin_src nix
64
{ config, pkgs, ... }:
65
66
{
67
  services.xserver = {
68
    enable = true;
69
    
70
    windowManager.oxwm.enable = true;
71
  };
72
73
  # Recommended: Install a display manager
74
  services.xserver.displayManager.lightdm.enable = true;
75
  # Or use another display manager like sddm, gdm, etc.
76
}
77
#+end_src
78
79
*** Initialize your config
80
After rebuilding your system with =sudo nixos-rebuild switch=, log in via your display manager.
81
82
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=.
83
84
*** Advanced: Using a specific oxwm version
85
If you want to pin or customize the oxwm package:
86
87
#+begin_src nix
88
{
89
  services.xserver.windowManager.oxwm = {
90
    enable = true;
91
    # Use a specific version or build with custom options
92
    package = oxwm.packages.${pkgs.system}.default;
93
  };
94
}
95
#+end_src
96
97
*** Development setup with Nix
98
For development, use the provided dev shell:
99
100
#+begin_src sh
101
# Clone the repository
102
git clone https://github.com/tonybanters/oxwm
103
cd oxwm
104
105
# Enter the development environment
106
nix develop
107
108
# Build and test
109
cargo build
110
just test
111
#+end_src
112
113
** Arch Linux
114
115
AUR: [[https://aur.archlinux.org/packages/oxwm-git][AUR URL]]
116
#+begin_src
117
yay -S oxwm-git
118
#+end_src
119
This will automatically put a desktop session file into your xsessions directory.
120
121
Manually:
122
Install dependencies:
123
#+begin_src sh
124
sudo pacman -S rust cargo libx11 libxft freetype2 fontconfig pkg-config
125
#+end_src
126
See Build from source
127
128
** Building from Source
129
#+begin_src sh
130
git clone https://github.com/tonybanters/oxwm
131
cd oxwm
132
cargo build --release
133
sudo cp target/release/oxwm /usr/local/bin/
134
#+end_src
135
136
Or use the justfile:
137
#+begin_src sh
138
just install
139
#+end_src
140
141
** Setting up OXWM
142
*** Without a display manager (startx)
143
Add the following to your =~/.xinitrc=:
144
#+begin_src sh
145
exec oxwm
146
#+end_src
147
148
Then start X with:
149
#+begin_src sh
150
startx
151
#+end_src
152
153
*** With a display manager
154
If using a display manager (LightDM, GDM, SDDM), OXWM should appear in the session list after installation.
155
156
* Configuration
157
OXWM uses a clean, functional Lua API for configuration. On first run, a default config is automatically created at =~/.config/oxwm/config.lua=.
158
159
** Quick Example
160
Here's what the new functional API looks like:
161
162
#+begin_src lua
163
-- Set basic options
164
oxwm.set_terminal("st")
165
oxwm.set_modkey("Mod4")
166
oxwm.set_tags({ "1", "2", "3", "4", "5", "6", "7", "8", "9" })
167
168
-- Configure borders
169
oxwm.border.set_width(2)
170
oxwm.border.set_focused_color("#6dade3")
171
oxwm.border.set_unfocused_color("#bbbbbb")
172
173
-- Configure gaps
174
oxwm.gaps.set_enabled(true)
175
oxwm.gaps.set_inner(5, 5)  -- horizontal, vertical
176
oxwm.gaps.set_outer(5, 5)
177
178
-- Set up keybindings
179
oxwm.key.bind({ "Mod4" }, "Return", oxwm.spawn("st"))
180
oxwm.key.bind({ "Mod4" }, "Q", oxwm.client.kill())
181
oxwm.key.bind({ "Mod4", "Shift" }, "Q", oxwm.quit())
182
183
-- Add status bar blocks
184
oxwm.bar.add_block("{}", "DateTime", "%H:%M", 60, "#0db9d7", true)
185
oxwm.bar.add_block("RAM: {used}/{total} GB", "Ram", nil, 5, "#7aa2f7", true)
186
#+end_src
187
188
** Features
189
- *Hot-reload*: Changes take effect immediately with =Mod+Shift+R= (no X restart needed)
190
- *LSP Support*: Full autocomplete and type hints for the API (=oxwm.lua= definitions included)
191
- *Functional API*: Clean, discoverable functions instead of nested tables
192
- *No compilation*: Edit and reload instantly
193
194
** Key Configuration Areas
195
Edit =~/.config/oxwm/config.lua= to customize:
196
- Basic settings (terminal, modkey, tags)
197
- Borders and colors
198
- Window gaps
199
- Status bar (font, blocks, color schemes)
200
- Keybindings and keychords
201
- Layout symbols
202
- Autostart commands
203
204
After making changes, reload OXWM with =Mod+Shift+R=
205
206
** Creating Your Config
207
Generate the default config:
208
#+begin_src sh
209
oxwm --init
210
#+end_src
211
212
Or just start OXWM - it will create one automatically on first run. 
213
214
* Contributing
215
When contributing to OXWM:
216
217
1. Never commit your personal =~/.config/oxwm/config.lua=
218
2. Only modify =templates/config.lua= if adding new configuration options
219
3. Test your changes with =just test= using Xephyr/Xwayland
220
4. Document any new features or keybindings
221
222
* Key Bindings
223
Default keybindings (customizable in config.rs):
224
225
| Binding           | Action                  |
226
|-------------------+-------------------------|
227
| Super+Return      | Spawn terminal          |
228
| Super+J/K         | Cycle focus down/up     |
229
| Super+Q           | Kill focused window     |
230
| Super+Shift+Q     | Quit WM                 |
231
| Super+Shift+R     | Hot reload WM           |
232
| Super+1-9         | View tag 1-9            |
233
| Super+Shift+1-9   | Move window to tag 1-9  |
234
| Super+S           | Screenshot (maim)       |
235
| Super+D           | dmenu launcher          |
236
| Super+A           | Toggle gaps             |
237
| Super+Shift+F     | Toggle fullscreen       |
238
| Super+Shift+Space | Toggle floating         |
239
240
* Features
241
- Dynamic tiling layout with master/stack
242
- Tag-based workspaces (9 tags by default)
243
- Configurable gaps between windows
244
- Status bar with modular block system
245
  - Battery, RAM, datetime, shell commands
246
  - Custom colors and update intervals
247
  - Click-to-switch tags
248
- Window focus cycling
249
- Hot reload without restarting X
250
- Persistent window tags across restarts
251
- Mouse hover to focus
252
- Border indicators for focused windows
253
- Fullscreen mode
254
- Move Windows with Super HJKL
255
256
* Testing with Xephyr
257
Test OXWM in a nested X server without affecting your current session:
258
259
#+begin_src sh
260
just test
261
#+end_src
262
263
This starts Xephyr on display :1 and launches OXWM inside it.
264
265
Or manually:
266
#+begin_src sh
267
Xephyr -screen 1280x800 :1 &
268
DISPLAY=:1 cargo run
269
#+end_src
270
271
* Project Structure
272
#+begin_src sh
273
src/
274
├── bin/
275
│   └── main.rs                          [Entry point - handles CLI args, config loading, WM init]
276
│       ├── main()                       [Parse args, load config, start WM]
277
│       ├── load_config()                [Lua config loading with auto-init]
278
│       └── init_config()                [Create default config.lua + oxwm.lua]
279
280
├── lib.rs                               [Library exports]
281
282
├── window_manager.rs                    [CORE - X11 event handling]
283
│   ├── struct WindowManager
284
│   │   ├── connection: RustConnection   [X11 connection]
285
│   │   ├── windows: Vec<Window>         [All managed windows]
286
│   │   ├── focused_window: Option<Window>
287
│   │   ├── layout: Box<dyn Layout>
288
│   │   ├── window_tags: HashMap<Window, TagMask>
289
│   │   ├── selected_tags: TagMask
290
│   │   └── bars: Vec<Bar>               [Status bars (multi-monitor)]
291
│   │
292
│   ├── new()                            [Initialize WM, grab root, restore tags, scan windows]
293
│   ├── run()                            [Main event loop with block updates]
294
│   ├── handle_event()                   [Route X11 events]
295
│   ├── try_reload_config()              [Hot-reload Lua config]
296
│   └── ...                              [Window/tag/focus management]
297
298
├── config/
299
│   ├── mod.rs                           [Config module exports]
300
│   ├── lua.rs                           [Lua config parser - loads and executes config.lua]
301
│   └── lua_api.rs                       [Functional Lua API implementation]
302
│       ├── register_api()               [Set up oxwm.* functions in Lua]
303
│       ├── register_spawn()             [oxwm.spawn()]
304
│       ├── register_key_module()        [oxwm.key.bind(), oxwm.key.chord()]
305
│       ├── register_gaps_module()       [oxwm.gaps.*]
306
│       ├── register_border_module()     [oxwm.border.*]
307
│       ├── register_client_module()     [oxwm.client.*]
308
│       ├── register_layout_module()     [oxwm.layout.*]
309
│       ├── register_tag_module()        [oxwm.tag.*]
310
│       ├── register_bar_module()        [oxwm.bar.*]
311
│       └── register_misc()              [oxwm.set_terminal(), etc.]
312
313
├── bar/
314
│   ├── mod.rs                           [Re-exports: Bar, BlockCommand, BlockConfig]
315
│   ├── bar.rs
316
│   │   ├── struct Bar                   [Status bar window with XFT support]
317
│   │   ├── new()                        [Create bar X11 window, load font, init blocks]
318
│   │   ├── draw()                       [Render tags + blocks with underlines]
319
│   │   ├── update_blocks()              [Update block content based on intervals]
320
│   │   └── handle_click()               [Detect which tag was clicked]
321
│   ├── font.rs
322
│   │   ├── struct Font                  [XFT font wrapper]
323
│   │   └── draw_text()                  [Render text with color]
324
│   └── blocks/
325
│       ├── mod.rs                       [Block trait, BlockConfig, BlockCommand enum]
326
│       ├── battery.rs                   [Battery status block]
327
│       ├── datetime.rs                  [Date/time formatting block]
328
│       ├── ram.rs                       [RAM usage block]
329
│       ├── shell.rs                     [Shell command execution block]
330
│       └── static.rs                    [Static text block]
331
332
├── keyboard/
333
│   ├── mod.rs                           [Re-exports]
334
│   ├── keysyms.rs                       [X11 keysym constants]
335
│   └── handlers.rs
336
│       ├── enum KeyAction               [All keyboard actions]
337
│       ├── enum Arg                     [Action arguments]
338
│       ├── struct KeyBinding            [Keybinding + keychord support]
339
│       └── struct KeyPress              [Individual key press in chord]
340
341
├── layout/
342
│   ├── mod.rs                           [Layout trait definition]
343
│   └── tiling.rs                        [Tiling layout implementation]
344
345
└── errors.rs                            [Error types: WmError, ConfigError, etc.]
346
347
templates/
348
├── config.lua                           [Default config with functional API]
349
└── oxwm.lua                             [LSP type definitions for autocomplete]
350
#+end_src
351
352
* Architecture Notes
353
** Lua Configuration System
354
OXWM uses mlua to embed a Lua interpreter. The functional API is implemented in =src/config/lua_api.rs=:
355
- Each API function (e.g., =oxwm.border.set_width()=) is registered as a Lua function
356
- Functions modify a shared ConfigBuilder that accumulates settings
357
- When config execution completes, the builder produces the final Config struct
358
- Type definitions in =templates/oxwm.lua= provide LSP autocomplete and documentation
359
360
** Tag System
361
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).
362
363
** Status Bar
364
The bar uses a performance-optimized approach with a modular block system:
365
- Only redraws when invalidated
366
- Pre-calculates tag widths on creation
367
- Blocks update independently based on their configured intervals
368
- Supports custom colors and underline indicators
369
- Color schemes (normal/occupied/selected) control tag appearance
370
- Easily extensible - add new block types in src/bar/blocks/
371
372
** Layout System
373
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.
374
375
* TODO Current Todo List:
376
** PRIORITY High [0/2]
377
- [ ] Convert keycodes to keysyms for cross-keyboard compatibility
378
  - Current hardcoded keycodes only work on specific keyboards
379
  - Need to use XKeysymToKeycode() for runtime conversion
380
  - Follow DWM's approach: keysym → keycode conversion
381
- [ ] Fix fullscreen to persist across tags
382
  - Fullscreen state should be maintained when switching tags
383
  - Window should remain fullscreen when returning to its tag
384
385
** PRIORITY Medium [2/4]
386
- [ ] Add keybindings to increase/decrease window size
387
  - Master area resize (Mod+H / Mod+L)
388
  - Individual window resize for floating windows
389
- [X] Keychords
390
  - Implemented with =oxwm.key.chord()= in the functional API
391
  - Example: =oxwm.key.chord({ { {"Mod4"}, "Space" }, { {}, "T" } }, oxwm.spawn("st"))=
392
- [X] Fix cursor on hover for bar
393
  - Bar should show pointer cursor on hover
394
  - Indicate clickable tag areas
395
- [ ] Add auto-detect terminal to default config
396
  - Auto-detect available terminal emulator
397
  - Priority order: st → alacritty → kitty → wezterm → xterm
398
  - Fallback to xterm if none found
399
400
** PRIORITY Low [1/1]
401
- [X] Create AUR package
402
  - Write PKGBUILD
403
  - Submit to AUR
404
  - Add installation instructions to README
405
* Development Roadmap
406
** Current Focus
407
- Multi-monitor support
408
- Additional layouts (monocle, floating)
409
- Master area resizing
410
- Window swapping in layout
411
412
** Future Enhancements
413
- Per-window floating behavior
414
- Per-program rules (auto-tag assignment, floating rules)
415
- External bar support (polybar, etc)
416
- Scratchpad functionality
417
- Window minimize/restore
418
419
* License
420
[[https://www.gnu.org/licenses/gpl-3.0.en.html][GPL v3]]