Skip to content

tonybanters/oxwm

Repository files navigation

./images/oxwm1.png

Table of Contents

OXWM — DWM but Better (and oxidized)

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.

Documentation: ox-docs.vercel.app

Installation

NixOS (with Flakes)

Adding OXWM to your flake inputs

Add oxwm to your flake.nix inputs:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    oxwm.url = "github:tonybanters/oxwm";
    oxwm.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = { self, nixpkgs, oxwm, ... }: {
    nixosConfigurations.yourhost = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        ./configuration.nix
        oxwm.nixosModules.default
      ];
    };
  };
}

Enabling OXWM in configuration.nix

Add this to your configuration.nix:

{ config, pkgs, ... }:

{
  services.xserver = {
    enable = true;
    
    windowManager.oxwm.enable = true;
  };

  # Recommended: Install a display manager
  services.xserver.displayManager.lightdm.enable = true;
  # Or use another display manager like sddm, gdm, etc.
}

Initialize your config

After rebuilding your system with sudo nixos-rebuild switch, log in via your display manager.

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.

Advanced: Using a specific oxwm version

If you want to pin or customize the oxwm package:

{
  services.xserver.windowManager.oxwm = {
    enable = true;
    # Use a specific version or build with custom options
    package = oxwm.packages.${pkgs.system}.default;
  };
}

Development setup with Nix

For development, use the provided dev shell:

# Clone the repository
git clone https://github.com/tonybanters/oxwm
cd oxwm

# Enter the development environment
nix develop

# Build and test
cargo build
just test

Arch Linux

AUR: AUR URL

yay -S oxwm-git

This will automatically put a desktop session file into your xsessions directory.

Manually: Install dependencies:

sudo pacman -S rust cargo libx11 libxft freetype2 fontconfig pkg-config

See Build from source

Building from Source

git clone https://github.com/tonybanters/oxwm
cd oxwm
cargo build --release
sudo cp target/release/oxwm /usr/local/bin/

Or use the justfile:

just install

Setting up OXWM

Without a display manager (startx)

Add the following to your ~/.xinitrc:

exec oxwm

Then start X with:

startx

With a display manager

If using a display manager (LightDM, GDM, SDDM), OXWM should appear in the session list after installation.

Configuration

OXWM uses a clean, functional Lua API for configuration. On first run, a default config is automatically created at ~/.config/oxwm/config.lua.

Quick Example

Here’s what the new functional API looks like:

-- Set basic options
oxwm.set_terminal("st")
oxwm.set_modkey("Mod4")
oxwm.set_tags({ "1", "2", "3", "4", "5", "6", "7", "8", "9" })

-- Configure borders
oxwm.border.set_width(2)
oxwm.border.set_focused_color("#6dade3")
oxwm.border.set_unfocused_color("#bbbbbb")

-- Configure gaps
oxwm.gaps.set_enabled(true)
oxwm.gaps.set_inner(5, 5)  -- horizontal, vertical
oxwm.gaps.set_outer(5, 5)

-- Set up keybindings
oxwm.key.bind({ "Mod4" }, "Return", oxwm.spawn("st"))
oxwm.key.bind({ "Mod4" }, "Q", oxwm.client.kill())
oxwm.key.bind({ "Mod4", "Shift" }, "Q", oxwm.quit())

-- Add status bar blocks
oxwm.bar.set_blocks({
    oxwm.bar.block.datetime({
        format = "{}",
        date_format = "%H:%M",
        interval = 60,
        color = "#0db9d7",
        underline = true,
    }),
    oxwm.bar.block.ram({
        format = "RAM: {used}/{total} GB",
        interval = 5,
        color = "#7aa2f7",
        underline = true,
    }),
})

Features

  • Hot-reload: Changes take effect immediately with Mod+Shift+R (no X restart needed)
  • LSP Support: Full autocomplete and type hints for the API (oxwm.lua definitions included)
  • Functional API: Clean, discoverable functions instead of nested tables
  • No compilation: Edit and reload instantly

Key Configuration Areas

Edit ~/.config/oxwm/config.lua to customize:

  • Basic settings (terminal, modkey, tags)
  • Borders and colors
  • Window gaps
  • Status bar (font, blocks, color schemes)
  • Keybindings and keychords
  • Layout symbols
  • Autostart commands

After making changes, reload OXWM with Mod+Shift+R

Creating Your Config

Generate the default config:

oxwm --init

Or just start OXWM - it will create one automatically on first run.

Contributing

When contributing to OXWM:

  1. Never commit your personal ~/.config/oxwm/config.lua
  2. Only modify templates/config.lua if adding new configuration options
  3. Test your changes with just test using Xephyr/Xwayland
  4. Document any new features or keybindings

Key Bindings

Default keybindings (fully customizable in ~/.config/oxwm/config.lua):

BindingAction
Super+ReturnSpawn terminal
Super+J/KCycle focus through stack
Super+QKill focused window
Super+Shift+QQuit WM
Super+Shift+RHot reload WM
Super+1-9View tag 1-9
Super+Shift+1-9Move window to tag 1-9
Super+Ctrl+1-9Toggle tag view (multi-tag)
Super+Ctrl+Shift+1-9Toggle window tag (sticky)
Super+SScreenshot (maim)
Super+Ddmenu launcher
Super+AToggle gaps
Super+Shift+FToggle fullscreen
Super+Shift+SpaceToggle floating
Super+FSet normie (floating) layout
Super+CSet tiling layout
Super+NCycle layouts
Super+Comma/PeriodFocus prev/next monitor
Super+Shift+Comma/.Send window to prev/next monitor
Super+[/]Decrease/increase master area
Super+I/PInc/dec number of master windows
Super+Shift+/Show keybinds overlay
Super+Button1 (drag)Move window (floating)
Super+Button3 (drag)Resize window (floating)

Features

  • Dynamic Tiling Layout with adjustable master/stack split
    • Master area resizing (mfact)
    • Multiple master windows support (nmaster)
  • Tag-Based Workspaces (9 tags by default)
    • Multi-tag viewing (see multiple tags at once)
    • Sticky windows (window visible on multiple tags)
  • Multiple Layouts
    • Tiling (master/stack)
    • Normie (floating-by-default)
    • Monocle (fullscreen stacking)
    • Grid (equal-sized grid)
    • Tabbed (tabbed windows)
  • Lua Configuration System
    • Hot reload without restarting X (Mod+Shift+R)
    • LSP support with type definitions and autocomplete
    • No compilation needed - instant config changes
  • Built-in Status Bar with modular block system
    • Battery, RAM, datetime, shell commands, static text
    • Custom colors, update intervals, and underlines
    • Click-to-switch tags
    • Multi-monitor support (one bar per monitor)
  • Advanced Window Management
    • Window focus cycling through stack
    • Fullscreen mode
    • Floating window support
    • Mouse hover to focus (follow mouse)
    • Border indicators for focused windows
    • Configurable gaps (smartgaps support)
    • Window rules (auto-tag, auto-float by class/title)
  • Multi-Monitor Support
    • RandR multi-monitor detection
    • Independent tags per monitor
    • Move windows between monitors
  • Keychord Support
    • Multi-key sequences (Emacs/Vim style)
    • Example: Mod+Space then T to spawn terminal
  • Persistent State
    • Window tags persist across WM restarts
    • Uses X11 properties for state storage

Testing with Xephyr

Test OXWM in a nested X server without affecting your current session:

just test

This starts Xephyr on display :1 and launches OXWM inside it.

Or manually:

Xephyr -screen 1280x800 :1 &
DISPLAY=:1 cargo run

Project Structure

src/
├── bin/
│   └── main.rs                          [Entry point - handles CLI args, config loading, WM init]
│       ├── main()                       [Parse args, load config, start WM]
│       ├── load_config()                [Lua config loading with auto-init]
│       └── init_config()                [Create default config.lua + oxwm.lua]
│
├── lib.rs                               [Library exports]
│
├── window_manager.rs                    [CORE - X11 event handling]
│   ├── struct WindowManager
│   │   ├── connection: RustConnection   [X11 connection]
│   │   ├── windows: Vec<Window>         [All managed windows]
│   │   ├── focused_window: Option<Window>
│   │   ├── layout: Box<dyn Layout>
│   │   ├── window_tags: HashMap<Window, TagMask>
│   │   ├── selected_tags: TagMask
│   │   └── bars: Vec<Bar>               [Status bars (multi-monitor)]
│   │
│   ├── new()                            [Initialize WM, grab root, restore tags, scan windows]
│   ├── run()                            [Main event loop with block updates]
│   ├── handle_event()                   [Route X11 events]
│   ├── try_reload_config()              [Hot-reload Lua config]
│   └── ...                              [Window/tag/focus management]
│
├── config/
│   ├── mod.rs                           [Config module exports]
│   ├── lua.rs                           [Lua config parser - loads and executes config.lua]
│   └── lua_api.rs                       [Functional Lua API implementation]
│       ├── register_api()               [Set up oxwm.* functions in Lua]
│       ├── register_spawn()             [oxwm.spawn()]
│       ├── register_key_module()        [oxwm.key.bind(), oxwm.key.chord()]
│       ├── register_gaps_module()       [oxwm.gaps.*]
│       ├── register_border_module()     [oxwm.border.*]
│       ├── register_client_module()     [oxwm.client.*]
│       ├── register_layout_module()     [oxwm.layout.*]
│       ├── register_tag_module()        [oxwm.tag.*]
│       ├── register_bar_module()        [oxwm.bar.*]
│       └── register_misc()              [oxwm.set_terminal(), etc.]
│
├── bar/
│   ├── mod.rs                           [Re-exports: Bar, BlockCommand, BlockConfig]
│   ├── bar.rs
│   │   ├── struct Bar                   [Status bar window with XFT support]
│   │   ├── new()                        [Create bar X11 window, load font, init blocks]
│   │   ├── draw()                       [Render tags + blocks with underlines]
│   │   ├── update_blocks()              [Update block content based on intervals]
│   │   └── handle_click()               [Detect which tag was clicked]
│   ├── font.rs
│   │   ├── struct Font                  [XFT font wrapper]
│   │   └── draw_text()                  [Render text with color]
│   └── blocks/
│       ├── mod.rs                       [Block trait, BlockConfig, BlockCommand enum]
│       ├── battery.rs                   [Battery status block]
│       ├── datetime.rs                  [Date/time formatting block]
│       ├── ram.rs                       [RAM usage block]
│       ├── shell.rs                     [Shell command execution block]
│       └── static.rs                    [Static text block]
│
├── keyboard/
│   ├── mod.rs                           [Re-exports]
│   ├── keysyms.rs                       [X11 keysym constants]
│   └── handlers.rs
│       ├── enum KeyAction               [All keyboard actions]
│       ├── enum Arg                     [Action arguments]
│       ├── struct KeyBinding            [Keybinding + keychord support]
│       └── struct KeyPress              [Individual key press in chord]
│
├── layout/
│   ├── mod.rs                           [Layout trait definition]
│   ├── tiling.rs                        [Tiling layout with master/stack]
│   ├── monocle.rs                       [Fullscreen stacking layout]
│   ├── grid.rs                          [Equal-sized grid layout]
│   ├── tabbed.rs                        [Tabbed container layout]
│   └── normie.rs                        [Floating-by-default layout]
│
└── errors.rs                            [Error types: WmError, ConfigError, etc.]

templates/
├── config.lua                           [Default config with functional API]
└── oxwm.lua                             [LSP type definitions for autocomplete]

Architecture Notes

Lua Configuration System

OXWM uses mlua to embed a Lua interpreter. The functional API is implemented in src/config/lua_api.rs:

  • Each API function (e.g., oxwm.border.set_width()) is registered as a Lua function
  • Functions modify a shared ConfigBuilder that accumulates settings
  • When config execution completes, the builder produces the final Config struct
  • Type definitions in templates/oxwm.lua provide LSP autocomplete and documentation

Tag System

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).

Status Bar

The bar uses a performance-optimized approach with a modular block system:

  • Only redraws when invalidated
  • Pre-calculates tag widths on creation
  • Blocks update independently based on their configured intervals
  • Supports custom colors and underline indicators
  • Color schemes (normal/occupied/selected) control tag appearance
  • Easily extensible - add new block types in src/bar/blocks/

Layout System

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.

Current Todo List:

PRIORITY High [0/4]

  • [ ] Add Window Titles to Bar
    • Show focused window title in status bar
    • Truncate if too long
    • Update on window focus change
  • [ ] Add Horizontal Scroll Layout
    • Master window on left, stack scrolls horizontally
    • Alternative to vertical tiling
  • [ ] Add Hide Empty Tag Numbers Option
    • Option to hide tags with no windows
    • Configurable via oxwm.bar.set_hide_empty_tags(bool)
  • [ ] Add Swap Stack Bind
    • Keybind to swap focused window with master
    • Similar to dwm’s zoom function (Mod+Return)
    • Should work bidirectionally

Development Roadmap

Current Focus (v0.8.0)

  • Refactoring to align with dwm’s proven patterns
  • Improving core window management reliability
  • Maintaining Lua config and bar features while simplifying internals

Completed Features [8/8]

  • [X] Multi-monitor support with RandR
  • [X] Multiple layouts (tiling, monocle, grid, tabbed, normie)
  • [X] Master area resizing (mfact) and nmaster support
  • [X] Window rules (per-program auto-tag, floating)
  • [X] Lua configuration with hot-reload
  • [X] Built-in status bar with modular blocks
  • [X] Keychord support (multi-key sequences)
  • [X] Tag persistence across restarts

Future Enhancements [/]

  • [ ] Scratchpad functionality
  • [ ] Dynamic monitor hotplugging (currently only on startup)
  • [ ] External bar support (polybar, waybar compatibility)
  • [ ] Additional layouts (deck, spiral, dwindle)
  • [ ] Window minimize/restore

License

GPL v3

About

Resources

License

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published