|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="description" content="DWN Design Patterns - Comprehensive documentation of design patterns, architectural decisions, and research sources used in the DWN window manager.">
|
|
<meta name="keywords" content="design patterns, C programming, opaque pointer, vtable, factory pattern, observer pattern, EWMH, ICCCM, XEmbed">
|
|
<title>Design Patterns - DWN Window Manager</title>
|
|
<link rel="stylesheet" href="css/style.css">
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<nav>
|
|
<a href="index.html" class="logo">
|
|
<span class="logo-icon">D</span>
|
|
<span>DWN</span>
|
|
</a>
|
|
<ul class="nav-links">
|
|
<li><a href="index.html">Home</a></li>
|
|
<li><a href="features.html">Features</a></li>
|
|
<li><a href="installation.html">Install</a></li>
|
|
<li class="dropdown">
|
|
<a href="documentation.html">Docs</a>
|
|
<div class="dropdown-menu">
|
|
<a href="documentation.html">Getting Started</a>
|
|
<a href="shortcuts.html">Keyboard Shortcuts</a>
|
|
<a href="configuration.html">Configuration</a>
|
|
<a href="ai-features.html">AI Features</a>
|
|
<a href="architecture.html">Architecture</a>
|
|
<a href="design-patterns.html" class="active">Design Patterns</a>
|
|
</div>
|
|
</li>
|
|
<li><a href="https://retoor.molodetz.nl/retoor/dwn">Git</a></li>
|
|
</ul>
|
|
<div class="nav-toggle" onclick="toggleNav()">
|
|
<span></span>
|
|
<span></span>
|
|
<span></span>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
<main>
|
|
<section class="hero hero-small">
|
|
<div class="container">
|
|
<h1>Design Patterns & Architecture</h1>
|
|
<p class="subtitle">
|
|
Comprehensive documentation of the design patterns, architectural decisions,
|
|
and research that shaped DWN's implementation.
|
|
</p>
|
|
</div>
|
|
</section>
|
|
<section class="section">
|
|
<div class="container docs-container">
|
|
<aside class="docs-sidebar">
|
|
<h3>Contents</h3>
|
|
<ul>
|
|
<li><a href="#overview">Overview</a></li>
|
|
<li><a href="#c-patterns">C Design Patterns</a></li>
|
|
<li><a href="#opaque-pointer">Opaque Pointer</a></li>
|
|
<li><a href="#goto-cleanup">Goto Cleanup</a></li>
|
|
<li><a href="#vtable">Vtable Polymorphism</a></li>
|
|
<li><a href="#factory">Factory Pattern</a></li>
|
|
<li><a href="#observer">Observer Pattern</a></li>
|
|
<li><a href="#singleton">Singleton Pattern</a></li>
|
|
<li><a href="#double-fork">Double Fork Daemon</a></li>
|
|
<li><a href="#x11-protocols">X11 Protocols</a></li>
|
|
<li><a href="#ewmh">EWMH Specification</a></li>
|
|
<li><a href="#icccm">ICCCM Standard</a></li>
|
|
<li><a href="#xembed">XEmbed Protocol</a></li>
|
|
<li><a href="#systray">System Tray Protocol</a></li>
|
|
<li><a href="#xdg">XDG Specifications</a></li>
|
|
<li><a href="#async">Async Patterns</a></li>
|
|
<li><a href="#modular">Modular Architecture</a></li>
|
|
<li><a href="#defensive">Defensive Programming</a></li>
|
|
<li><a href="#sources">Research Sources</a></li>
|
|
</ul>
|
|
</aside>
|
|
<div class="docs-content">
|
|
<h2 id="overview">Overview</h2>
|
|
<p>
|
|
DWN is built using professional C design patterns that provide encapsulation,
|
|
modularity, and maintainability without the overhead of C++. This document
|
|
details the patterns used, the rationale behind architectural decisions,
|
|
and links to authoritative sources.
|
|
</p>
|
|
<div class="alert alert-info">
|
|
<strong class="alert-title">Design Philosophy</strong>
|
|
<p style="margin: 0;">
|
|
DWN prioritizes simplicity, readability, and defensive programming.
|
|
Each module has a single responsibility with well-defined interfaces.
|
|
The codebase follows the principle: "Simple is better than complex."
|
|
</p>
|
|
</div>
|
|
|
|
<h2 id="c-patterns" style="margin-top: 3rem;">C Design Patterns</h2>
|
|
<p style="color: var(--text-muted); margin-bottom: 2rem;">
|
|
While C lacks native object-oriented features, these patterns provide
|
|
equivalent functionality with minimal overhead.
|
|
</p>
|
|
|
|
<h3 id="opaque-pointer">Opaque Pointer Pattern</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Hide implementation details from API consumers, enabling changes without recompilation.</p>
|
|
<h4>How It Works</h4>
|
|
<p>The header declares a pointer to an incomplete type. The struct definition
|
|
exists only in the implementation file, preventing direct member access.</p>
|
|
<div class="code-header">
|
|
<span>Header (public)</span>
|
|
</div>
|
|
<pre><code>typedef struct config_t *Config;
|
|
Config config_create(void);
|
|
void config_destroy(Config cfg);</code></pre>
|
|
<div class="code-header">
|
|
<span>Implementation (private)</span>
|
|
</div>
|
|
<pre><code>struct config_t {
|
|
int border_width;
|
|
char terminal[128];
|
|
};</code></pre>
|
|
<h4>Benefits</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li>API consumers cannot access internal fields directly</li>
|
|
<li>Implementation can change without breaking client code</li>
|
|
<li>Enforces encapsulation at compile time</li>
|
|
</ul>
|
|
<h4>Used In</h4>
|
|
<p style="color: var(--text-muted);">
|
|
<code>config.c</code> - Configuration management
|
|
</p>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://interrupt.memfault.com/blog/opaque-pointers" target="_blank">Practical Design Patterns: Opaque Pointers and Objects in C</a> - Memfault</li>
|
|
<li><a href="https://en.wikipedia.org/wiki/Opaque_pointer" target="_blank">Opaque Pointer</a> - Wikipedia</li>
|
|
<li><a href="https://wiki.sei.cmu.edu/confluence/display/c/DCL12-C.+Implement+abstract+data+types+using+opaque+types" target="_blank">DCL12-C: Implement abstract data types using opaque types</a> - SEI CERT C Coding Standard</li>
|
|
<li><a href="https://blog.mbedded.ninja/programming/design-patterns/opaque-pointers/" target="_blank">Opaque Pointers</a> - mbedded.ninja</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h3 id="goto-cleanup">Goto Cleanup Pattern</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Centralize resource cleanup in functions that acquire multiple resources,
|
|
preventing memory leaks and ensuring proper deallocation on all code paths.</p>
|
|
<h4>How It Works</h4>
|
|
<p>Resources are initialized to safe values (NULL). On error, execution jumps
|
|
to a cleanup label. The cleanup section safely releases all resources.</p>
|
|
<div class="code-header">
|
|
<span>Example</span>
|
|
</div>
|
|
<pre><code>int process_file(const char *path) {
|
|
char *buf = NULL;
|
|
FILE *f = NULL;
|
|
int status = -1;
|
|
|
|
buf = malloc(1024);
|
|
if (!buf) goto cleanup;
|
|
|
|
f = fopen(path, "r");
|
|
if (!f) goto cleanup;
|
|
|
|
// ... processing ...
|
|
status = 0;
|
|
|
|
cleanup:
|
|
free(buf); // safe: free(NULL) is no-op
|
|
if (f) fclose(f);
|
|
return status;
|
|
}</code></pre>
|
|
<h4>Benefits</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li>Single cleanup point prevents code duplication</li>
|
|
<li>All error paths properly release resources</li>
|
|
<li>Used extensively in Linux kernel and SQLite</li>
|
|
</ul>
|
|
<h4>Used In</h4>
|
|
<p style="color: var(--text-muted);">
|
|
<code>config.c</code>, <code>news.c</code>, <code>ai.c</code> - File and network operations
|
|
</p>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://wiki.sei.cmu.edu/confluence/display/c/MEM12-C.+Consider+using+a+goto+chain+when+leaving+a+function+on+error+when+using+and+releasing+resources" target="_blank">MEM12-C: Using goto chain for error handling</a> - SEI CERT C Coding Standard</li>
|
|
<li><a href="https://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c" target="_blank">Using goto for error handling in C</a> - Eli Bendersky</li>
|
|
<li><a href="https://www.geeksforgeeks.org/c/using-goto-for-exception-handling-in-c/" target="_blank">Using goto for Exception Handling in C</a> - GeeksforGeeks</li>
|
|
<li><a href="https://ayende.com/blog/183521-C/error-handling-via-goto-in-c" target="_blank">Error handling via GOTO in C</a> - Ayende Rahien</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h3 id="vtable">Vtable Polymorphism</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Enable runtime polymorphism in C using function pointer tables,
|
|
allowing different implementations to share a common interface.</p>
|
|
<h4>How It Works</h4>
|
|
<p>A struct of function pointers (vtable) defines the interface. Objects contain
|
|
a pointer to their vtable. Calling through the vtable invokes the correct implementation.</p>
|
|
<div class="code-header">
|
|
<span>Example</span>
|
|
</div>
|
|
<pre><code>typedef struct Widget Widget;
|
|
typedef struct {
|
|
void (*draw)(Widget *self);
|
|
void (*destroy)(Widget *self);
|
|
} WidgetVtable;
|
|
|
|
struct Widget {
|
|
const WidgetVtable *vtable;
|
|
int x, y, width, height;
|
|
};
|
|
|
|
// Usage: widget->vtable->draw(widget);</code></pre>
|
|
<h4>Benefits</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li>Runtime dispatch without language support</li>
|
|
<li>New implementations added without modifying existing code</li>
|
|
<li>Same pattern used by C++ compilers internally</li>
|
|
</ul>
|
|
<h4>Used In</h4>
|
|
<p style="color: var(--text-muted);">
|
|
<code>panel.c</code> - Widget rendering system
|
|
</p>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://en.wikipedia.org/wiki/Virtual_method_table" target="_blank">Virtual Method Table</a> - Wikipedia</li>
|
|
<li><a href="https://embeddedartistry.com/fieldatlas/technique-inheritance-and-polymorphism-in-c/" target="_blank">Inheritance and Polymorphism in C</a> - Embedded Artistry</li>
|
|
<li><a href="https://www.state-machine.com/doc/AN_Simple_OOP_in_C.pdf" target="_blank">Object-Oriented Programming in C</a> - Quantum Leaps (PDF)</li>
|
|
<li><a href="https://www.embedded.com/programming-embedded-systems-polymorphism-in-c-2/" target="_blank">Programming embedded systems: polymorphism in C</a> - Embedded.com</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h3 id="factory">Factory Pattern</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Encapsulate object creation logic, allowing the system to create objects
|
|
without specifying their exact types.</p>
|
|
<h4>How It Works</h4>
|
|
<p>A factory function takes parameters describing what to create and returns
|
|
a pointer to the appropriate object type.</p>
|
|
<div class="code-header">
|
|
<span>Example</span>
|
|
</div>
|
|
<pre><code>typedef enum { WIDGET_BUTTON, WIDGET_LABEL } WidgetType;
|
|
|
|
Widget *widget_create(WidgetType type) {
|
|
switch (type) {
|
|
case WIDGET_BUTTON: return button_create();
|
|
case WIDGET_LABEL: return label_create();
|
|
default: return NULL;
|
|
}
|
|
}</code></pre>
|
|
<h4>Benefits</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li>Centralizes object creation logic</li>
|
|
<li>New types added without changing client code</li>
|
|
<li>Supports Open/Closed Principle</li>
|
|
</ul>
|
|
<h4>Used In</h4>
|
|
<p style="color: var(--text-muted);">
|
|
<code>config.c</code>, <code>client.c</code>, <code>workspace.c</code> - Object lifecycle management
|
|
</p>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://refactoring.guru/design-patterns/factory-method" target="_blank">Factory Method Pattern</a> - Refactoring Guru</li>
|
|
<li><a href="https://en.wikipedia.org/wiki/Factory_method_pattern" target="_blank">Factory Method Pattern</a> - Wikipedia</li>
|
|
<li><a href="https://sourcemaking.com/design_patterns" target="_blank">Design Patterns</a> - SourceMaking</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h3 id="observer">Observer Pattern</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Implement event-driven communication where subjects notify observers
|
|
of state changes without tight coupling.</p>
|
|
<h4>How It Works</h4>
|
|
<p>Observers register callback functions with subjects. When events occur,
|
|
the subject iterates through registered callbacks and invokes them.</p>
|
|
<div class="code-header">
|
|
<span>Example</span>
|
|
</div>
|
|
<pre><code>typedef void (*EventCallback)(void *data);
|
|
|
|
void events_register(EventType type, EventCallback cb, void *data);
|
|
void events_emit(EventType type);
|
|
|
|
// Notification triggers all registered callbacks</code></pre>
|
|
<h4>Benefits</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li>Loose coupling between event sources and handlers</li>
|
|
<li>Observers added/removed without modifying subjects</li>
|
|
<li>Foundation of event-driven programming</li>
|
|
</ul>
|
|
<h4>Used In</h4>
|
|
<p style="color: var(--text-muted);">
|
|
<code>keys.c</code> - Keyboard event handling, <code>notifications.c</code> - D-Bus signals
|
|
</p>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://refactoring.guru/design-patterns/observer" target="_blank">Observer Pattern</a> - Refactoring Guru</li>
|
|
<li><a href="https://en.wikipedia.org/wiki/Observer_pattern" target="_blank">Observer Pattern</a> - Wikipedia</li>
|
|
<li><a href="https://learn.microsoft.com/en-us/dotnet/standard/events/observer-design-pattern" target="_blank">Observer Design Pattern</a> - Microsoft Learn</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h3 id="singleton">Singleton / Global State</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Provide a single, globally accessible instance of the window manager state,
|
|
simplifying module communication.</p>
|
|
<h4>Implementation in DWN</h4>
|
|
<p>DWN uses a single <code>DWNState</code> structure accessible via the global
|
|
<code>dwn</code> pointer. This is appropriate for a window manager where
|
|
exactly one instance exists per X11 session.</p>
|
|
<div class="code-header">
|
|
<span>Example</span>
|
|
</div>
|
|
<pre><code>// Global state pointer
|
|
extern DWNState *dwn;
|
|
|
|
// Access from any module
|
|
if (dwn != NULL && dwn->config != NULL) {
|
|
return dwn->config->terminal;
|
|
}</code></pre>
|
|
<h4>Rationale</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li>Window manager is inherently a singleton per X session</li>
|
|
<li>Simplifies inter-module communication</li>
|
|
<li>All state centralized for easier debugging</li>
|
|
</ul>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://refactoring.guru/design-patterns/singleton" target="_blank">Singleton Pattern</a> - Refactoring Guru</li>
|
|
<li><a href="https://gameprogrammingpatterns.com/singleton.html" target="_blank">Singleton</a> - Game Programming Patterns</li>
|
|
<li><a href="https://en.wikipedia.org/wiki/Singleton_pattern" target="_blank">Singleton Pattern</a> - Wikipedia</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h3 id="double-fork">Double Fork Daemon Pattern</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Launch background processes that are fully detached from the parent,
|
|
preventing zombie processes and terminal reattachment.</p>
|
|
<h4>How It Works</h4>
|
|
<p>The pattern uses two fork() calls: the first creates a child that calls
|
|
setsid() to become a session leader, then forks again. The grandchild
|
|
cannot reacquire a controlling terminal.</p>
|
|
<div class="code-header">
|
|
<span>Implementation in DWN</span>
|
|
</div>
|
|
<pre><code>int spawn_async(const char *cmd) {
|
|
pid_t pid = fork();
|
|
if (pid == 0) {
|
|
setsid(); // New session
|
|
pid_t pid2 = fork(); // Second fork
|
|
if (pid2 == 0) {
|
|
execl("/bin/sh", "sh", "-c", cmd, NULL);
|
|
_exit(EXIT_FAILURE);
|
|
}
|
|
_exit(EXIT_SUCCESS); // Intermediate exits
|
|
}
|
|
waitpid(pid, &status, 0); // Only wait for intermediate
|
|
return 0;
|
|
}</code></pre>
|
|
<h4>Benefits</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li>Process fully detached from parent</li>
|
|
<li>No zombie processes (intermediate is reaped immediately)</li>
|
|
<li>Cannot reacquire controlling terminal</li>
|
|
<li>Non-blocking for the caller</li>
|
|
</ul>
|
|
<h4>Used In</h4>
|
|
<p style="color: var(--text-muted);">
|
|
<code>util.c</code> - spawn_async(), <code>autostart.c</code>, <code>applauncher.c</code>
|
|
</p>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://0xjet.github.io/3OHA/2022/04/11/post.html" target="_blank">UNIX daemonization and the double fork</a> - Juan Tapiador</li>
|
|
<li><a href="https://www.digitalbunker.dev/understanding-daemons-unix/" target="_blank">Understanding Daemons</a> - Digital Bunker</li>
|
|
<li><a href="https://lloydrochester.com/post/c/unix-daemon-example/" target="_blank">Daemon Example in C</a> - Lloyd Rochester</li>
|
|
<li><a href="https://goral.net.pl/post/double-fork/" target="_blank">Double Fork</a> - Michal Goral</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h2 id="x11-protocols" style="margin-top: 3rem;">X11 Window Manager Protocols</h2>
|
|
<p style="color: var(--text-muted); margin-bottom: 2rem;">
|
|
DWN implements several freedesktop.org specifications for cross-desktop compatibility.
|
|
</p>
|
|
|
|
<h3 id="ewmh">Extended Window Manager Hints (EWMH)</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Define interactions between window managers, compositing managers, applications,
|
|
and desktop utilities in a standardized way.</p>
|
|
<h4>Key Features Implemented</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><code>_NET_SUPPORTED</code> - List of supported hints</li>
|
|
<li><code>_NET_CLIENT_LIST</code> - List of managed windows</li>
|
|
<li><code>_NET_CURRENT_DESKTOP</code> - Active workspace</li>
|
|
<li><code>_NET_WM_STATE</code> - Window states (fullscreen, maximized)</li>
|
|
<li><code>_NET_ACTIVE_WINDOW</code> - Currently focused window</li>
|
|
<li><code>_NET_WM_WINDOW_TYPE</code> - Window type classification</li>
|
|
</ul>
|
|
<h4>Implementation</h4>
|
|
<p style="color: var(--text-muted);">
|
|
<code>atoms.c</code> manages X11 atom creation and EWMH property updates.
|
|
Properties are updated on window focus changes, workspace switches, and state changes.
|
|
</p>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://specifications.freedesktop.org/wm/latest/" target="_blank">Extended Window Manager Hints Specification</a> - freedesktop.org</li>
|
|
<li><a href="https://en.wikipedia.org/wiki/Extended_Window_Manager_Hints" target="_blank">Extended Window Manager Hints</a> - Wikipedia</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h3 id="icccm">Inter-Client Communication Conventions Manual (ICCCM)</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Define low-level conventions for X11 client communication, including
|
|
selections, window management, and session management.</p>
|
|
<h4>Key Features Implemented</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><code>WM_PROTOCOLS</code> - Window close handling</li>
|
|
<li><code>WM_DELETE_WINDOW</code> - Graceful window closing</li>
|
|
<li><code>WM_NAME</code> / <code>_NET_WM_NAME</code> - Window titles</li>
|
|
<li><code>WM_CLASS</code> - Application classification</li>
|
|
<li><code>WM_HINTS</code> - Window hints (urgency, input model)</li>
|
|
</ul>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html" target="_blank">Inter-Client Communication Conventions Manual</a> - X.Org</li>
|
|
<li><a href="https://tronche.com/gui/x/icccm/" target="_blank">ICCCM Reference</a> - Christophe Tronche</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h3 id="xembed">XEmbed Protocol</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Enable embedding of controls from one application into another,
|
|
forming the basis of the system tray implementation.</p>
|
|
<h4>How It Works</h4>
|
|
<p>The embedder (DWN panel) acts as a window manager for embedded clients.
|
|
Client windows are reparented into the embedder, and events are coordinated
|
|
through XEMBED messages.</p>
|
|
<h4>Key Messages</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><code>XEMBED_EMBEDDED_NOTIFY</code> - Sent when embedding completes</li>
|
|
<li><code>XEMBED_FOCUS_IN/OUT</code> - Focus coordination</li>
|
|
<li><code>XEMBED_WINDOW_ACTIVATE</code> - Window activation</li>
|
|
</ul>
|
|
<h4>Implementation</h4>
|
|
<p style="color: var(--text-muted);">
|
|
<code>systray.c</code> implements the embedder side, reparenting tray icons
|
|
and forwarding click events.
|
|
</p>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://specifications.freedesktop.org/xembed-spec/latest/" target="_blank">XEmbed Protocol Specification</a> - freedesktop.org</li>
|
|
<li><a href="https://www.freedesktop.org/wiki/Specifications/xembed-spec/" target="_blank">XEmbed Spec Wiki</a> - freedesktop.org</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h3 id="systray">System Tray Protocol</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Enable applications to display status icons in a desktop panel,
|
|
providing a standardized notification area.</p>
|
|
<h4>How It Works</h4>
|
|
<p>DWN acquires the <code>_NET_SYSTEM_TRAY_S0</code> selection to become the
|
|
tray manager. Applications send <code>SYSTEM_TRAY_REQUEST_DOCK</code> messages
|
|
to dock their icons.</p>
|
|
<h4>Docking Process</h4>
|
|
<ol style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li>DWN acquires <code>_NET_SYSTEM_TRAY_S0</code> selection</li>
|
|
<li>Application sends <code>SYSTEM_TRAY_REQUEST_DOCK</code> client message</li>
|
|
<li>DWN creates embedding window and reparents icon</li>
|
|
<li>DWN sends <code>XEMBED_EMBEDDED_NOTIFY</code> to icon</li>
|
|
<li>Click events forwarded to icon window</li>
|
|
</ol>
|
|
<h4>Supported Applications</h4>
|
|
<p style="color: var(--text-muted);">
|
|
nm-applet, blueman-applet, Telegram, pasystray, udiskie, and any XEmbed-compatible tray icon.
|
|
</p>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://specifications.freedesktop.org/systemtray-spec/systemtray-spec-0.3.html" target="_blank">System Tray Protocol Specification</a> - freedesktop.org</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h2 id="xdg" style="margin-top: 3rem;">XDG Specifications</h2>
|
|
|
|
<h3>Desktop Entry Specification</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Standard format for application metadata files (.desktop files) used
|
|
by application launchers and autostart systems.</p>
|
|
<h4>Key Fields Parsed</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><code>Exec</code> - Command to execute</li>
|
|
<li><code>TryExec</code> - Check if binary exists</li>
|
|
<li><code>Hidden</code> - Entry is disabled</li>
|
|
<li><code>OnlyShowIn</code> / <code>NotShowIn</code> - Desktop environment filters</li>
|
|
<li><code>Terminal</code> - Run in terminal</li>
|
|
</ul>
|
|
<h4>Implementation</h4>
|
|
<p style="color: var(--text-muted);">
|
|
<code>applauncher.c</code> parses .desktop files for the application menu.
|
|
<code>autostart.c</code> parses autostart entries.
|
|
</p>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://specifications.freedesktop.org/desktop-entry-spec/latest/" target="_blank">Desktop Entry Specification</a> - freedesktop.org</li>
|
|
<li><a href="https://wiki.archlinux.org/title/Desktop_entries" target="_blank">Desktop Entries</a> - ArchWiki</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h3>Desktop Application Autostart Specification</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Define standard locations and format for applications that should
|
|
start automatically when the user logs in.</p>
|
|
<h4>Directories Scanned</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><code>/etc/xdg/autostart/</code> - System-wide autostart</li>
|
|
<li><code>~/.config/autostart/</code> - User autostart</li>
|
|
<li><code>~/.config/dwn/autostart.d/</code> - DWN-specific (symlinks)</li>
|
|
</ul>
|
|
<h4>Key Behavior</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li>User entries override system entries with same filename</li>
|
|
<li><code>Hidden=true</code> disables an entry</li>
|
|
<li><code>TryExec</code> prevents running if binary missing</li>
|
|
</ul>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://specifications.freedesktop.org/autostart-spec/autostart-spec-latest.html" target="_blank">Desktop Application Autostart Specification</a> - freedesktop.org</li>
|
|
<li><a href="https://wiki.archlinux.org/title/XDG_Autostart" target="_blank">XDG Autostart</a> - ArchWiki</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h3>Desktop Notifications Specification</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Standard D-Bus interface for applications to display passive notifications
|
|
to users without blocking.</p>
|
|
<h4>D-Bus Interface</h4>
|
|
<p style="color: var(--text-muted);">
|
|
DWN implements <code>org.freedesktop.Notifications</code> on the session bus
|
|
at path <code>/org/freedesktop/Notifications</code>.
|
|
</p>
|
|
<h4>Key Methods</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><code>Notify</code> - Display a notification</li>
|
|
<li><code>CloseNotification</code> - Dismiss a notification</li>
|
|
<li><code>GetCapabilities</code> - Query supported features</li>
|
|
<li><code>GetServerInformation</code> - Server metadata</li>
|
|
</ul>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://specifications.freedesktop.org/notification-spec/latest/" target="_blank">Desktop Notifications Specification</a> - freedesktop.org</li>
|
|
<li><a href="https://wiki.archlinux.org/title/Desktop_notifications" target="_blank">Desktop Notifications</a> - ArchWiki</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h2 id="async" style="margin-top: 3rem;">Async Programming Patterns</h2>
|
|
|
|
<h3>libcurl Multi Interface</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Perform HTTP requests asynchronously without blocking the main event loop,
|
|
essential for AI features and news fetching.</p>
|
|
<h4>How It Works</h4>
|
|
<p>Instead of blocking on network I/O, the multi interface allows the main
|
|
loop to poll for completion. <code>curl_multi_perform()</code> advances
|
|
transfers incrementally.</p>
|
|
<div class="code-header">
|
|
<span>Integration Pattern</span>
|
|
</div>
|
|
<pre><code>// In event loop (16ms intervals)
|
|
curl_multi_perform(multi_handle, &running);
|
|
CURLMsg *msg = curl_multi_info_read(multi_handle, &msgs_left);
|
|
if (msg && msg->msg == CURLMSG_DONE) {
|
|
// Request completed, process response
|
|
}</code></pre>
|
|
<h4>Implementation</h4>
|
|
<p style="color: var(--text-muted);">
|
|
<code>ai.c</code> uses curl_multi for OpenRouter API calls.
|
|
Responses processed in <code>ai_process_pending()</code> called from main loop.
|
|
</p>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://curl.se/libcurl/c/libcurl-multi.html" target="_blank">libcurl multi interface overview</a> - curl.se</li>
|
|
<li><a href="https://curl.se/libcurl/c/libcurl-tutorial.html" target="_blank">libcurl programming tutorial</a> - curl.se</li>
|
|
<li><a href="https://curl.se/libcurl/c/multi-app.html" target="_blank">multi-app.c example</a> - curl.se</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h3>pthread for Background I/O</h3>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Purpose</h4>
|
|
<p>Offload blocking operations to separate threads when async APIs
|
|
are unavailable or impractical.</p>
|
|
<h4>Implementation</h4>
|
|
<p style="color: var(--text-muted);">
|
|
<code>news.c</code> spawns a detached thread for RSS fetching.
|
|
Mutex guards shared state, atomic flags prevent concurrent fetches.
|
|
</p>
|
|
<div class="code-header">
|
|
<span>Pattern</span>
|
|
</div>
|
|
<pre><code>static pthread_mutex_t news_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
static atomic_int fetch_running = 0;
|
|
|
|
void news_fetch_async(void) {
|
|
if (atomic_load(&fetch_running)) return;
|
|
atomic_store(&fetch_running, 1);
|
|
pthread_create(&fetch_thread, NULL, fetch_thread_func, NULL);
|
|
}</code></pre>
|
|
</div>
|
|
|
|
<h2 id="modular" style="margin-top: 3rem;">Modular Architecture</h2>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Design Principle</h4>
|
|
<p>Each module has a single responsibility with well-defined interfaces.
|
|
Modules communicate through the global <code>dwn</code> state and
|
|
function calls, never through shared mutable state.</p>
|
|
<h4>Module Structure</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><code>include/module.h</code> - Public API declarations</li>
|
|
<li><code>src/module.c</code> - Private implementation</li>
|
|
<li>Static functions for internal logic</li>
|
|
<li>module_init() / module_cleanup() lifecycle</li>
|
|
</ul>
|
|
<h4>Module Responsibilities</h4>
|
|
<div class="table-wrapper">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Module</th>
|
|
<th>Responsibility</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr><td>main.c</td><td>Event loop, initialization orchestration</td></tr>
|
|
<tr><td>client.c</td><td>Window management, focus handling</td></tr>
|
|
<tr><td>workspace.c</td><td>Virtual desktop management</td></tr>
|
|
<tr><td>layout.c</td><td>Tiling algorithms</td></tr>
|
|
<tr><td>panel.c</td><td>UI panels and widgets</td></tr>
|
|
<tr><td>systray.c</td><td>System tray protocol</td></tr>
|
|
<tr><td>notifications.c</td><td>D-Bus notification daemon</td></tr>
|
|
<tr><td>autostart.c</td><td>XDG autostart support</td></tr>
|
|
<tr><td>config.c</td><td>Configuration parsing</td></tr>
|
|
<tr><td>ai.c</td><td>AI integration</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://en.wikipedia.org/wiki/Modular_programming" target="_blank">Modular Programming</a> - Wikipedia</li>
|
|
<li><a href="https://en.wikipedia.org/wiki/Separation_of_concerns" target="_blank">Separation of Concerns</a> - Wikipedia</li>
|
|
<li><a href="https://thecloudstrap.com/chapter-14-modular-programming-in-c/" target="_blank">Modular Programming in C</a> - TheCloudStrap</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h2 id="defensive" style="margin-top: 3rem;">Defensive Programming</h2>
|
|
<div class="card" style="margin-bottom: 2rem;">
|
|
<h4>Core Principles</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><strong>Null Checks</strong> - All pointer parameters validated before use</li>
|
|
<li><strong>Bounds Checking</strong> - Array indices and string lengths verified</li>
|
|
<li><strong>Return Value Checking</strong> - malloc(), fopen(), etc. checked for failure</li>
|
|
<li><strong>String Safety</strong> - strncpy() with size-1, explicit null termination</li>
|
|
<li><strong>Assertions</strong> - assert() for programmer errors in debug builds</li>
|
|
</ul>
|
|
<h4>Examples in DWN</h4>
|
|
<div class="code-header">
|
|
<span>Null Check Pattern</span>
|
|
</div>
|
|
<pre><code>const char *config_get_terminal(void) {
|
|
if (dwn != NULL && dwn->config != NULL) {
|
|
return dwn->config->terminal;
|
|
}
|
|
return "xterm"; // Safe fallback
|
|
}</code></pre>
|
|
<div class="code-header">
|
|
<span>String Safety Pattern</span>
|
|
</div>
|
|
<pre><code>strncpy(cfg->terminal, value, sizeof(cfg->terminal) - 1);
|
|
cfg->terminal[sizeof(cfg->terminal) - 1] = '\0'; // Guarantee null termination</code></pre>
|
|
<h4>Research Sources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://wiki.sei.cmu.edu/confluence/display/c/API00-C.+Functions+should+validate+their+parameters" target="_blank">API00-C: Functions should validate their parameters</a> - SEI CERT</li>
|
|
<li><a href="https://enterprisecraftsmanship.com/posts/defensive-programming/" target="_blank">Defensive programming: the good, the bad and the ugly</a> - Enterprise Craftsmanship</li>
|
|
<li><a href="https://www.cse.psu.edu/~gxt29/teaching/cs447s19/slides/05defensiveProg.pdf" target="_blank">Defensive Programming</a> - Penn State (PDF)</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<h2 id="sources" style="margin-top: 3rem;">Complete Research Sources</h2>
|
|
<div class="card">
|
|
<h4>C Design Patterns</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://interrupt.memfault.com/blog/opaque-pointers" target="_blank">Practical Design Patterns: Opaque Pointers and Objects in C</a> - Memfault</li>
|
|
<li><a href="https://wiki.sei.cmu.edu/confluence/display/c/" target="_blank">SEI CERT C Coding Standard</a> - Carnegie Mellon University</li>
|
|
<li><a href="https://refactoring.guru/design-patterns" target="_blank">Design Patterns Catalog</a> - Refactoring Guru</li>
|
|
<li><a href="https://sourcemaking.com/design_patterns" target="_blank">Design Patterns</a> - SourceMaking</li>
|
|
<li><a href="https://embeddedartistry.com/fieldatlas/" target="_blank">Embedded Artistry Field Atlas</a> - Embedded Artistry</li>
|
|
<li><a href="https://www.state-machine.com/doc/AN_Simple_OOP_in_C.pdf" target="_blank">Object-Oriented Programming in C</a> - Quantum Leaps</li>
|
|
</ul>
|
|
<h4>X11 and freedesktop.org</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://specifications.freedesktop.org/wm/latest/" target="_blank">Extended Window Manager Hints (EWMH)</a> - freedesktop.org</li>
|
|
<li><a href="https://specifications.freedesktop.org/xembed-spec/latest/" target="_blank">XEmbed Protocol</a> - freedesktop.org</li>
|
|
<li><a href="https://specifications.freedesktop.org/systemtray-spec/systemtray-spec-0.3.html" target="_blank">System Tray Protocol</a> - freedesktop.org</li>
|
|
<li><a href="https://specifications.freedesktop.org/notification-spec/latest/" target="_blank">Desktop Notifications</a> - freedesktop.org</li>
|
|
<li><a href="https://specifications.freedesktop.org/autostart-spec/autostart-spec-latest.html" target="_blank">Desktop Application Autostart</a> - freedesktop.org</li>
|
|
<li><a href="https://specifications.freedesktop.org/desktop-entry-spec/latest/" target="_blank">Desktop Entry Specification</a> - freedesktop.org</li>
|
|
</ul>
|
|
<h4>Libraries and APIs</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://curl.se/libcurl/c/libcurl-multi.html" target="_blank">libcurl multi interface</a> - curl.se</li>
|
|
<li><a href="https://dbus.freedesktop.org/doc/dbus-specification.html" target="_blank">D-Bus Specification</a> - freedesktop.org</li>
|
|
<li><a href="https://www.x.org/releases/current/doc/" target="_blank">X Window System Documentation</a> - X.Org</li>
|
|
</ul>
|
|
<h4>Unix Programming</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://0xjet.github.io/3OHA/2022/04/11/post.html" target="_blank">UNIX daemonization and the double fork</a> - Juan Tapiador</li>
|
|
<li><a href="https://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c" target="_blank">Using goto for error handling in C</a> - Eli Bendersky</li>
|
|
<li><a href="https://gameprogrammingpatterns.com/" target="_blank">Game Programming Patterns</a> - Robert Nystrom</li>
|
|
</ul>
|
|
<h4>Community Resources</h4>
|
|
<ul style="padding-left: 1.25rem; color: var(--text-muted);">
|
|
<li><a href="https://wiki.archlinux.org/" target="_blank">ArchWiki</a> - Comprehensive Linux documentation</li>
|
|
<li><a href="https://en.wikipedia.org/" target="_blank">Wikipedia</a> - Design pattern overviews</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
<footer>
|
|
<div class="container">
|
|
<div class="footer-grid">
|
|
<div class="footer-section">
|
|
<h4>DWN Window Manager</h4>
|
|
<p style="color: var(--text-muted);">
|
|
A modern, production-ready X11 window manager with XFCE-like
|
|
functionality and optional AI integration.
|
|
</p>
|
|
</div>
|
|
<div class="footer-section">
|
|
<h4>Documentation</h4>
|
|
<ul>
|
|
<li><a href="documentation.html">Getting Started</a></li>
|
|
<li><a href="shortcuts.html">Keyboard Shortcuts</a></li>
|
|
<li><a href="configuration.html">Configuration</a></li>
|
|
<li><a href="architecture.html">Architecture</a></li>
|
|
<li><a href="design-patterns.html">Design Patterns</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="footer-section">
|
|
<h4>Resources</h4>
|
|
<ul>
|
|
<li><a href="https://retoor.molodetz.nl/retoor/dwn">Source Code</a></li>
|
|
<li><a href="https://retoor.molodetz.nl/retoor/dwn/issues">Issue Tracker</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="footer-section">
|
|
<h4>Author</h4>
|
|
<p style="color: var(--text-muted);">
|
|
retoor <retoor@molodetz.nl>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="footer-bottom">
|
|
<p>DWN Window Manager - MIT License</p>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
<script src="js/main.js"></script>
|
|
</body>
|
|
</html>
|