Architecture

Technical documentation for developers and contributors.

Overview

DWN is written in ANSI C (C99) and follows a modular single-responsibility architecture. A global DWNState singleton manages all state, and the main event loop dispatches X11 events to specialized modules.

Project Statistics

~10K
Lines of Code
12
Core Modules
C99
Standard
MIT
License

Directory Structure

Project Layout
dwn/
├── src/                  # Source files (.c)
│   ├── main.c           # Entry point, event loop
│   ├── client.c         # Window management
│   ├── workspace.c      # Virtual desktops
│   ├── layout.c         # Tiling algorithms
│   ├── decorations.c    # Title bars, borders
│   ├── panel.c          # Top/bottom panels
│   ├── systray.c        # System tray widgets
│   ├── notifications.c  # D-Bus notifications
│   ├── atoms.c          # X11 atoms (EWMH/ICCCM)
│   ├── keys.c           # Keyboard handling
│   ├── config.c         # INI parser
│   ├── ai.c             # AI integration
│   └── util.c           # Utilities
├── include/             # Header files (.h)
├── site/                # Documentation website
├── Makefile             # Build system
├── CLAUDE.md            # AI assistant context
└── README.md            # Project readme

Core Modules

Module File Responsibility
Main main.c X11 initialization, event loop, signal handling, module orchestration
Client client.c Window lifecycle, focus management, frame creation, client list
Workspace workspace.c 9 virtual desktops, per-workspace state, window assignment
Layout layout.c Tiling (master+stack), floating, monocle layout algorithms
Decorations decorations.c Window title bars, borders, decoration rendering
Panel panel.c Top panel (taskbar, workspace indicators), bottom panel (clock)
Systray systray.c System tray with WiFi/audio/battery indicators, dropdowns
Notifications notifications.c D-Bus notification daemon (org.freedesktop.Notifications)
Atoms atoms.c X11 EWMH/ICCCM atom management and property handling
Keys keys.c Keyboard shortcut capture, keybinding registry, callbacks
Config config.c INI-style config loading and parsing
AI ai.c Async OpenRouter API integration, Exa semantic search
Util util.c Logging, memory allocation, string utilities, file helpers

Module Dependencies

main.c (orchestrator)
    ├── client.c
    │   ├── decorations.c
    │   ├── config.c
    │   └── atoms.c
    ├── workspace.c
    │   ├── client.c
    │   ├── layout.c
    │   └── atoms.c
    ├── panel.c
    │   ├── client.c
    │   └── config.c
    ├── systray.c
    │   └── config.c
    ├── notifications.c (independent)
    ├── ai.c (independent)
    └── keys.c
        └── config.c

Global State (DWNState)

All window manager state is centralized in a single DWNState structure. This simplifies state management and makes the codebase easier to understand.

include/dwn.h (simplified)
typedef struct {
    Display *display;           // X11 connection
    Window root;                // Root window
    int screen;                 // Default screen
    Client *clients[MAX_CLIENTS];   // All managed windows
    int client_count;
    Workspace workspaces[MAX_WORKSPACES];  // Virtual desktops
    int current_workspace;
    Panel top_panel;
    Panel bottom_panel;
    Config config;              // User configuration
    KeyBinding keys[MAX_KEYBINDINGS];
    // EWMH atoms
    Atom atoms[ATOM_COUNT];
} DWNState;
extern DWNState *dwn;  // Global singleton

Event Loop

DWN uses a traditional X11 event loop with XNextEvent. Events are dispatched to appropriate handlers based on type.

main.c (simplified)
int main(int argc, char *argv[]) {
    dwn_init();           // Initialize X11, atoms, config
    setup_keybindings();  // Register keyboard shortcuts
    setup_panels();       // Create panel windows
    XEvent event;
    while (running) {
        XNextEvent(dwn->display, &event);
        switch (event.type) {
            case MapRequest:
                handle_map_request(&event.xmaprequest);
                break;
            case UnmapNotify:
                handle_unmap_notify(&event.xunmap);
                break;
            case KeyPress:
                handle_key_press(&event.xkey);
                break;
            case ButtonPress:
                handle_button_press(&event.xbutton);
                break;
            case ConfigureRequest:
                handle_configure_request(&event.xconfigurerequest);
                break;
            // ... more event types
        }
    }
    dwn_cleanup();
    return 0;
}

Key Constants

Constant Value Purpose
MAX_CLIENTS 256 Maximum managed windows
MAX_WORKSPACES 9 Number of virtual desktops
MAX_MONITORS 8 Multi-monitor support limit
MAX_NOTIFICATIONS 32 Concurrent notifications
MAX_KEYBINDINGS 64 Registered keyboard shortcuts

Coding Conventions

Naming

  • snake_case for functions and variables
  • CamelCase for types and structs
  • Module prefix for functions (e.g., client_focus())
  • Constants in UPPER_SNAKE_CASE

Style

  • 4-space indentation
  • K&R brace style
  • Max 100 characters per line
  • clang-format for consistency
Example Function
void client_focus(Client *c) {
    if (!c) return;
    // Unfocus previous
    if (dwn->focused && dwn->focused != c) {
        client_unfocus(dwn->focused);
    }
    dwn->focused = c;
    XSetInputFocus(dwn->display, c->window, RevertToPointerRoot, CurrentTime);
    XRaiseWindow(dwn->display, c->frame);
    decorations_update(c);
    atoms_set_active_window(c->window);
}

EWMH/ICCCM Support

DWN implements key Extended Window Manager Hints and ICCCM protocols for compatibility with modern applications.

EWMH Atoms

  • _NET_SUPPORTED
  • _NET_CLIENT_LIST
  • _NET_CLIENT_LIST_STACKING
  • _NET_ACTIVE_WINDOW
  • _NET_CURRENT_DESKTOP
  • _NET_NUMBER_OF_DESKTOPS
  • _NET_WM_STATE
  • _NET_WM_STATE_FULLSCREEN
  • _NET_WM_STATE_MAXIMIZED_*
  • _NET_WM_WINDOW_TYPE
  • _NET_WM_NAME

ICCCM Support

  • WM_STATE
  • WM_PROTOCOLS
  • WM_DELETE_WINDOW
  • WM_TAKE_FOCUS
  • WM_NORMAL_HINTS
  • WM_SIZE_HINTS
  • WM_CLASS
  • WM_NAME
  • WM_TRANSIENT_FOR

Build System

DWN uses a simple Makefile-based build system with pkg-config for dependency detection.

Target Command Description
Build (release) make Optimized build with -O2
Build (debug) make debug Debug symbols, -DDEBUG flag
Install sudo make install Install to PREFIX (/usr/local)
Clean make clean Remove build artifacts
Format make format Run clang-format on sources
Check make check Run cppcheck static analysis
Test make run Run in Xephyr nested server
Dependencies make deps Auto-install for your distro

Contributing

Contributions are welcome! Here's how to get started:

1

Fork & Clone

Fork the repository and clone your fork locally.

2

Create a Branch

Create a feature branch: git checkout -b feature/my-feature

3

Make Changes

Follow coding conventions. Run make format and make check.

4

Test

Test your changes with make run in a nested X server.

5

Submit PR

Push your branch and open a pull request with a clear description.