511 lines
22 KiB
HTML
Raw Normal View History

<!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>
<span class="version">v1.0.0</span>
</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>
<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>
<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>
<p>DWN is written in ANSI C for X11/Xorg. It uses a modular architecture with a global state singleton and event-driven design.</p>
<div class="code-block">
<pre><code>┌─────────────────────────────────────────────────────────┐
│ DWN Window Manager │
├─────────────────────────────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ main │ │ keys │ │ panel │ │ api │ │
│ │ loop │ │ handler │ │ render │ │ server │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │ │
│ ┌────┴────────────┴────────────┴────────────┴────┐ │
│ │ DWNState (Global Singleton) │ │
│ └────┬────────────┬────────────┬────────────┬────┘ │
│ │ │ │ │ │
│ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ │
│ │ client │ │workspace│ │ layout │ │ atoms │ │
│ │ mgmt │ │ mgmt │ │ engine │ │ (EWMH) │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
├─────────────────────────────────────────────────────────┤
│ X11 / Xlib │
└─────────────────────────────────────────────────────────┘</code></pre>
</div>
<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 &lt;retoor@molodetz.nl&gt;</p>
</footer>
</div>
</main>
</div>
<script src="js/main.js"></script>
</body>
</html>