2026-01-24 15:17:47 +00:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< title > Architecture - DWN Documentation</ title >
< link rel = "stylesheet" href = "css/style.css" >
</ head >
< body >
< button class = "mobile-menu-btn" > Menu</ button >
< div class = "layout" >
< aside class = "sidebar" >
< div class = "sidebar-header" >
< h1 > DWN</ h1 >
2026-02-07 12:04:52 +00:00
< span class = "version" > v2.0.0</ span >
2026-01-24 15:17:47 +00:00
</ div >
< div class = "search-box" >
< input type = "text" class = "search-input" placeholder = "Search docs..." >
</ div >
< nav class = "sidebar-nav" >
< div class = "nav-section" >
< div class = "nav-section-title" > Getting Started</ div >
< a href = "index.html" class = "nav-link" > Introduction</ a >
< a href = "installation.html" class = "nav-link" > Installation</ a >
< a href = "quickstart.html" class = "nav-link" > Quick Start</ a >
</ div >
< div class = "nav-section" >
< div class = "nav-section-title" > User Guide</ div >
< a href = "features.html" class = "nav-link" > Features</ a >
< a href = "shortcuts.html" class = "nav-link" > Keyboard Shortcuts</ a >
< a href = "configuration.html" class = "nav-link" > Configuration</ a >
< a href = "layouts.html" class = "nav-link" > Layouts</ a >
< a href = "ai-features.html" class = "nav-link" > AI Integration</ a >
</ div >
< div class = "nav-section" >
< div class = "nav-section-title" > API Reference</ div >
< a href = "api-overview.html" class = "nav-link" > API Overview</ a >
< a href = "api-reference.html" class = "nav-link" > API Reference</ a >
< a href = "api-examples.html" class = "nav-link" > API Examples</ a >
</ div >
< div class = "nav-section" >
< div class = "nav-section-title" > Advanced</ div >
< a href = "architecture.html" class = "nav-link active" > Architecture</ a >
2026-02-07 12:04:52 +00:00
< a href = "abstraction-layer.html" class = "nav-link" > Abstraction Layer</ a >
< a href = "plugin-development.html" class = "nav-link" > Plugin Development</ a >
2026-01-24 15:17:47 +00:00
< a href = "building.html" class = "nav-link" > Building from Source</ a >
</ div >
</ nav >
</ aside >
< main class = "main-content" >
< div class = "content" >
< div class = "page-header" >
< h1 > Architecture</ h1 >
< p class = "lead" > Technical overview of DWN's design and implementation</ p >
</ div >
< div class = "toc" >
< div class = "toc-title" > On this page</ div >
< ul class = "toc-list" >
< li >< a href = "#overview" > Overview</ a ></ li >
2026-02-07 12:04:52 +00:00
< li >< a href = "#abstraction" > Abstraction Layer</ a ></ li >
2026-01-24 15:17:47 +00:00
< li >< a href = "#modules" > Module Structure</ a ></ li >
< li >< a href = "#event-loop" > Event Loop</ a ></ li >
< li >< a href = "#data-structures" > Core Data Structures</ a ></ li >
< li >< a href = "#protocols" > X11 Protocols</ a ></ li >
< li >< a href = "#design-patterns" > Design Patterns</ a ></ li >
</ ul >
</ div >
< h2 id = "overview" > Overview</ h2 >
2026-02-07 12:04:52 +00:00
< p > DWN is written in ANSI C for X11/Xorg. It uses a modular architecture with a global state singleton and event-driven design. Version 2.0 introduces a comprehensive abstraction layer enabling backend portability and plugin extensibility.</ p >
< h2 id = "abstraction" > Abstraction Layer (v2.0)</ h2 >
< p > The new abstraction layer provides backend-agnostic types and a plugin system:</ p >
2026-01-24 15:17:47 +00:00
< div class = "code-block" >
< pre >< code > ┌─────────────────────────────────────────────────────────┐
2026-02-07 12:04:52 +00:00
│ DWN Application │
2026-01-24 15:17:47 +00:00
├─────────────────────────────────────────────────────────┤
2026-02-07 12:04:52 +00:00
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ Layout │ │ Widget │ │ AI Provider │ │
│ │ Plugin │ │ Plugin │ │ API │ │
│ │ System │ │ System │ │ (future) │ │
│ └──────┬──────┘ └──────┬──────┘ └─────────────────┘ │
│ │ │ │
│ ┌──────┴────────────────┴───────────────────────────┐ │
│ │ Abstract Client Manager │ │
│ │ (wm_client.h/c - bidirectional sync) │ │
│ └───────────────────────┬───────────────────────────┘ │
│ │ │
│ ┌───────────────────────┴───────────────────────────┐ │
│ │ Backend Abstraction Interface │ │
│ │ (backend_interface.h - vtable-based) │ │
│ └───────────────────────┬───────────────────────────┘ │
│ │ │
│ ┌───────────────────────┴───────────────────────────┐ │
│ │ X11 Backend │ Wayland Backend │ Headless │ │
│ │ (complete) │ (future) │ (future) │ │
│ └───────────────────────────────────────────────────┘ │
2026-01-24 15:17:47 +00:00
└─────────────────────────────────────────────────────────┘</ code ></ pre >
</ div >
2026-02-07 12:04:52 +00:00
< h3 > Core Abstractions</ h3 >
< ul >
< li >< strong > wm_types.h</ strong > - Abstract handles, geometry, colors, events</ li >
< li >< strong > wm_string.h/c</ strong > - Safe dynamic strings</ li >
< li >< strong > wm_list.h/c</ strong > - Dynamic arrays</ li >
< li >< strong > wm_hashmap.h/c</ strong > - Hash tables</ li >
< li >< strong > wm_client.h/c</ strong > - Abstract client type</ li >
</ ul >
< h3 > Plugin System</ h3 >
< ul >
< li >< strong > Layout Plugins</ strong > - Custom window arrangements (tiling, floating, monocle, grid)</ li >
< li >< strong > Widget Plugins</ strong > - Panel components (taskbar, clock, system stats)</ li >
< li >< strong > Dynamic Loading</ strong > - Load plugins from shared libraries</ li >
</ ul >
< h3 > Backend Interface</ h3 >
< p > The backend interface defines 80+ operations for window management, events, and rendering. Current implementations:</ p >
< ul >
< li >< strong > X11</ strong > - Full implementation with event translation</ li >
< li >< strong > Wayland</ strong > - Planned for future</ li >
< li >< strong > Headless</ strong > - For testing and CI</ li >
</ ul >
2026-01-24 15:17:47 +00:00
< h2 id = "modules" > Module Structure</ h2 >
< p > Each module has a header in < code > include/</ code > and implementation in < code > src/</ code > .</ p >
< div class = "table-container" >
< table >
< thead >
< tr >
< th > Module</ th >
< th > Responsibility</ th >
</ tr >
</ thead >
< tbody >
< tr >
< td >< code > main.c</ code ></ td >
< td > X11 initialization, event loop, signal handling</ td >
</ tr >
< tr >
< td >< code > client.c</ code ></ td >
< td > Window management, focus, frame creation</ td >
</ tr >
< tr >
< td >< code > workspace.c</ code ></ td >
< td > 9 virtual desktops, per-workspace state</ td >
</ tr >
< tr >
< td >< code > layout.c</ code ></ td >
< td > Tiling, floating, monocle algorithms</ td >
</ tr >
< tr >
< td >< code > decorations.c</ code ></ td >
< td > Window title bars and borders</ td >
</ tr >
< tr >
< td >< code > panel.c</ code ></ td >
< td > Top/bottom panels, taskbar, workspace indicators</ td >
</ tr >
< tr >
< td >< code > systray.c</ code ></ td >
< td > XEmbed system tray, WiFi/audio/battery widgets</ td >
</ tr >
< tr >
< td >< code > notifications.c</ code ></ td >
< td > D-Bus notification daemon</ td >
</ tr >
< tr >
< td >< code > atoms.c</ code ></ td >
< td > X11 EWMH/ICCCM atom management</ td >
</ tr >
< tr >
< td >< code > keys.c</ code ></ td >
< td > Keyboard shortcut capture and callbacks</ td >
</ tr >
< tr >
< td >< code > config.c</ code ></ td >
< td > INI-style config loading</ td >
</ tr >
< tr >
< td >< code > api.c</ code ></ td >
< td > WebSocket JSON API server</ td >
</ tr >
< tr >
< td >< code > screenshot.c</ code ></ td >
< td > X11 capture + PNG encoding</ td >
</ tr >
< tr >
< td >< code > ocr.c</ code ></ td >
< td > Tesseract OCR integration</ td >
</ tr >
< tr >
< td >< code > ai.c</ code ></ td >
< td > OpenRouter API, Exa search</ td >
</ tr >
< tr >
< td >< code > util.c</ code ></ td >
< td > Logging, memory, string utilities</ td >
</ tr >
</ tbody >
</ table >
</ div >
< h2 id = "event-loop" > Event Loop</ h2 >
< p > The main event loop uses < code > select()</ code > for multiplexed I/O across X11, D-Bus, and timers.</ p >
< div class = "code-block" >
< pre >< code > void dwn_run(void) {
int x11_fd = ConnectionNumber(dwn->display);
int dbus_fd = /* from dbus_connection */;
while (dwn->running) {
// 1. Process all pending X11 events
while (XPending(dwn->display)) {
XEvent ev;
XNextEvent(dwn->display, &ev);
dwn_handle_event(&ev);
}
// 2. Process D-Bus messages
notifications_process_messages();
// 3. Process async AI/Exa requests
ai_process_pending();
// 4. Check notification timeouts
notifications_update();
// 5. Handle delayed focus (focus-follow mode)
handle_pending_focus();
// 6. Periodic updates (animation, clock)
if (now - last_update >= 16) { // 60fps
news_update();
panel_render_all();
}
// 7. Wait for events with timeout
fd_set fds;
FD_SET(x11_fd, &fds);
FD_SET(dbus_fd, &fds);
struct timeval tv = {0, 16000}; // 16ms
select(max_fd + 1, & fds, NULL, NULL, &tv);
}
}</ code ></ pre >
</ div >
< h3 > X11 Event Dispatch</ h3 >
< div class = "table-container" >
< table >
< thead >
< tr >
< th > Event</ th >
< th > Handler</ th >
</ tr >
</ thead >
< tbody >
< tr >
< td >< code > MapRequest</ code ></ td >
< td > New window → client_manage()</ td >
</ tr >
< tr >
< td >< code > UnmapNotify</ code ></ td >
< td > Window hidden → possibly client_unmanage()</ td >
</ tr >
< tr >
< td >< code > DestroyNotify</ code ></ td >
< td > Window destroyed → client_unmanage()</ td >
</ tr >
< tr >
< td >< code > ConfigureRequest</ code ></ td >
< td > Window resize request</ td >
</ tr >
< tr >
< td >< code > PropertyNotify</ code ></ td >
< td > Property changed → update title</ td >
</ tr >
< tr >
< td >< code > Expose</ code ></ td >
< td > Repaint needed → render</ td >
</ tr >
< tr >
< td >< code > ButtonPress</ code ></ td >
< td > Mouse click → focus, drag, panel click</ td >
</ tr >
< tr >
< td >< code > MotionNotify</ code ></ td >
< td > Mouse move → window drag/resize</ td >
</ tr >
< tr >
< td >< code > KeyPress</ code ></ td >
< td > Key pressed → shortcut callback</ td >
</ tr >
< tr >
< td >< code > ClientMessage</ code ></ td >
< td > EWMH requests, systray dock</ td >
</ tr >
</ tbody >
</ table >
</ div >
< h2 id = "data-structures" > Core Data Structures</ h2 >
< h3 > DWNState</ h3 >
< p > Global singleton containing all window manager state.</ p >
< div class = "code-block" >
< pre >< code > typedef struct {
Display *display; // X11 connection
int screen; // Default screen
Window root; // Root window
int screen_width, screen_height;
Monitor monitors[MAX_MONITORS];
int monitor_count;
Workspace workspaces[MAX_WORKSPACES]; // 9 workspaces
int current_workspace;
Client *client_list; // Doubly-linked list head
int client_count;
Panel *top_panel;
Panel *bottom_panel;
Config *config;
bool running;
bool ai_enabled;
// Drag state
Client *drag_client;
int drag_start_x, drag_start_y;
bool resizing;
// Alt-Tab state
bool is_alt_tabbing;
Client *alt_tab_client;
} DWNState;</ code ></ pre >
</ div >
< h3 > Client</ h3 >
< p > Represents a managed window with decoration frame.</ p >
< div class = "code-block" >
< pre >< code > struct Client {
Window window; // Application window
Window frame; // Decoration frame (parent)
int x, y, width, height; // Current geometry
int old_x, old_y; // Saved for restore
int old_width, old_height;
uint32_t flags; // CLIENT_FLOATING, etc.
unsigned int workspace; // Workspace index (0-8)
char title[256];
char class[64];
SnapConstraint snap; // Snap state
Client *next, *prev; // Global list
Client *mru_next, *mru_prev; // MRU stack
};</ code ></ pre >
</ div >
< h3 > Workspace</ h3 >
< p > Per-workspace layout and window state.</ p >
< div class = "code-block" >
< pre >< code > struct Workspace {
Client *clients; // Workspace client list
Client *focused; // Currently focused
Client *mru_head, *mru_tail; // MRU stack
LayoutType layout; // tiling/floating/monocle
float master_ratio; // 0.1 to 0.9
int master_count; // 1 to 10
char name[32];
};</ code ></ pre >
</ div >
< h3 > Client Flags</ h3 >
< div class = "code-block" >
< pre >< code > #define CLIENT_NORMAL 0
#define CLIENT_FLOATING (1 < < 0 )
# define CLIENT_FULLSCREEN ( 1 << 1 )
# define CLIENT_URGENT ( 1 << 2 )
# define CLIENT_MINIMIZED ( 1 << 3 )
# define CLIENT_STICKY ( 1 << 4 )
# define CLIENT_MAXIMIZED ( 1 << 5 )
// Usage
if ( c- > flags & CLIENT_FLOATING) { ... }
c->flags |= CLIENT_FLOATING; // Set
c->flags & = ~CLIENT_FLOATING; // Clear</ code ></ pre >
</ div >
< h2 id = "protocols" > X11 Protocols</ h2 >
< h3 > EWMH (Extended Window Manager Hints)</ h3 >
< p > Standard hints for modern window manager features.</ p >
< ul >
< li >< code > _NET_SUPPORTED</ code > - List of supported atoms</ li >
< li >< code > _NET_CLIENT_LIST</ code > - List of managed windows</ li >
< li >< code > _NET_CURRENT_DESKTOP</ code > - Current workspace</ li >
< li >< code > _NET_ACTIVE_WINDOW</ code > - Focused window</ li >
< li >< code > _NET_WM_STATE</ code > - Window state (fullscreen, etc.)</ li >
< li >< code > _NET_WM_WINDOW_TYPE</ code > - Window type (dialog, etc.)</ li >
</ ul >
< h3 > ICCCM (Inter-Client Communication)</ h3 >
< p > Core X11 window manager protocol.</ p >
< ul >
< li >< code > WM_PROTOCOLS</ code > - Supported protocols (WM_DELETE_WINDOW)</ li >
< li >< code > WM_NAME</ code > - Window title</ li >
< li >< code > WM_CLASS</ code > - Application class</ li >
< li >< code > WM_HINTS</ code > - Input model, icons</ li >
< li >< code > WM_NORMAL_HINTS</ code > - Size constraints</ li >
</ ul >
< h3 > XEmbed (System Tray)</ h3 >
< p > Protocol for embedding application icons in system tray.</ p >
< ul >
< li > Acquire < code > _NET_SYSTEM_TRAY_S0</ code > selection</ li >
< li > Handle < code > SYSTEM_TRAY_REQUEST_DOCK</ code > messages</ li >
< li > Send < code > XEMBED_EMBEDDED_NOTIFY</ code > to docked icons</ li >
</ ul >
< h2 id = "design-patterns" > Design Patterns</ h2 >
< h3 > Opaque Pointers</ h3 >
< p > Hide implementation details. Header exposes typedef, source defines struct.</ p >
< div class = "code-block" >
< pre >< code > // header.h
typedef struct module_t* Module;
Module module_create(void);
void module_destroy(Module m);
// source.c
struct module_t {
int private_field;
};</ code ></ pre >
</ div >
< h3 > Return Code Error Handling</ h3 >
< p > Functions return status codes, pass results via output parameters.</ p >
< div class = "code-block" >
< pre >< code > typedef enum {
STATUS_OK = 0,
STATUS_ERROR_INVALID_ARG,
STATUS_ERROR_NO_MEMORY
} Status;
Status do_work(int input, int *output);</ code ></ pre >
</ div >
< h3 > Goto Cleanup</ h3 >
< p > Centralized resource cleanup for functions with multiple allocations.</ p >
< div class = "code-block" >
< pre >< code > int process(void) {
char *buf = NULL;
int status = -1;
buf = malloc(1024);
if (!buf) goto cleanup;
// ... work ...
status = 0;
cleanup:
free(buf);
return status;
}</ code ></ pre >
</ div >
< h3 > Module Prefix Convention</ h3 >
< p > All public functions prefixed with module name.</ p >
< div class = "code-block" >
< pre >< code > // client.h
void client_focus(Client *c);
void client_move(Client *c, int x, int y);
void client_resize(Client *c, int w, int h);
// workspace.h
void workspace_switch(int index);
void workspace_arrange(int index);</ code ></ pre >
</ div >
< h2 > Key Constants</ h2 >
< div class = "table-container" >
< table >
< thead >
< tr >
< th > Constant</ th >
< th > Value</ th >
< th > Description</ th >
</ tr >
</ thead >
< tbody >
< tr >
< td >< code > MAX_CLIENTS</ code ></ td >
< td > 256</ td >
< td > Maximum managed windows</ td >
</ tr >
< tr >
< td >< code > MAX_WORKSPACES</ code ></ td >
< td > 9</ td >
< td > Virtual desktops</ td >
</ tr >
< tr >
< td >< code > MAX_MONITORS</ code ></ td >
< td > 8</ td >
< td > Multi-monitor support</ td >
</ tr >
< tr >
< td >< code > MAX_NOTIFICATIONS</ code ></ td >
< td > 32</ td >
< td > Visible notifications</ td >
</ tr >
< tr >
< td >< code > MAX_KEYBINDINGS</ code ></ td >
< td > 64</ td >
< td > Keyboard shortcuts</ td >
</ tr >
< tr >
< td >< code > MAX_TRAY_ICONS</ code ></ td >
< td > 32</ td >
< td > System tray icons</ td >
</ tr >
</ tbody >
</ table >
</ div >
< footer >
< p > DWN Window Manager - retoor < retoor@molodetz.nl> </ p >
</ footer >
</ div >
</ main >
</ div >
< script src = "js/main.js" ></ script >
</ body >
</ html >