build: add -ldl linker flag, recursive source discovery, and API test targets to Makefile
This commit is contained in:
@@ -0,0 +1,305 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Abstraction Layer - 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">v2.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">Architecture</a>
|
||||
<a href="abstraction-layer.html" class="nav-link active">Abstraction Layer</a>
|
||||
<a href="plugin-development.html" class="nav-link">Plugin Development</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>Abstraction Layer</h1>
|
||||
<p class="lead">Backend-agnostic architecture for future extensibility</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="#core-types">Core Types</a></li>
|
||||
<li><a href="#backend-interface">Backend Interface</a></li>
|
||||
<li><a href="#client-abstraction">Client Abstraction</a></li>
|
||||
<li><a href="#containers">Container Types</a></li>
|
||||
<li><a href="#migration">Migration Strategy</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>DWN v2.0 introduces a comprehensive abstraction layer that separates the window manager logic from backend-specific implementations. This architecture enables:</p>
|
||||
|
||||
<ul>
|
||||
<li><strong>Backend Portability</strong> - Clean migration path from X11 to Wayland</li>
|
||||
<li><strong>Type Safety</strong> - Strongly typed handles eliminate void* casting</li>
|
||||
<li><strong>Memory Safety</strong> - Abstract strings and containers prevent buffer overflows</li>
|
||||
<li><strong>Plugin Extensibility</strong> - Dynamic loading of layouts and widgets</li>
|
||||
<li><strong>100% Compatibility</strong> - Existing code continues to work unchanged</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="core-types">Core Types</h2>
|
||||
<p>The abstraction layer provides type-safe replacements for backend-specific types:</p>
|
||||
|
||||
<div class="table-container">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Abstract Type</th>
|
||||
<th>X11 Equivalent</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>WmWindowHandle</code></td>
|
||||
<td><code>Window</code></td>
|
||||
<td>Opaque window reference</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>WmClientId</code></td>
|
||||
<td>-</td>
|
||||
<td>Unique client identifier</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>WmWorkspaceId</code></td>
|
||||
<td><code>int</code></td>
|
||||
<td>Workspace identifier</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>WmRect</code></td>
|
||||
<td>-</td>
|
||||
<td>Rectangle geometry (x, y, w, h)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>WmColor</code></td>
|
||||
<td><code>unsigned long</code></td>
|
||||
<td>RGBA color value</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3>Geometry Operations</h3>
|
||||
<p>Inline functions for rectangle operations:</p>
|
||||
<div class="code-block">
|
||||
<pre><code>WmRect rect = wm_rect_make(0, 0, 1920, 1080);
|
||||
bool contains = wm_rect_contains_point(&rect, 100, 100);
|
||||
bool intersects = wm_rect_intersects(&rect1, &rect2);
|
||||
WmRect intersection = wm_rect_intersection(&rect1, &rect2);</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>Color Operations</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>WmColor color = wm_color_rgb(255, 0, 128); // RGB
|
||||
WmColor color = wm_color_rgba(255, 0, 128, 200); // RGBA
|
||||
uint8_t r = wm_color_get_red(color);
|
||||
uint8_t a = wm_color_get_alpha(color);</code></pre>
|
||||
</div>
|
||||
|
||||
<h2 id="backend-interface">Backend Interface</h2>
|
||||
<p>The backend interface defines a vtable of operations that any backend must implement:</p>
|
||||
|
||||
<div class="code-block">
|
||||
<pre><code>typedef struct BackendInterface {
|
||||
/* Identification */
|
||||
const char *name;
|
||||
WmBackendInfo (*get_info)(void);
|
||||
|
||||
/* Lifecycle */
|
||||
bool (*init)(void *config);
|
||||
void (*shutdown)(void);
|
||||
|
||||
/* Window Management */
|
||||
void (*window_move)(WmWindowHandle window, int x, int y);
|
||||
void (*window_resize)(WmWindowHandle window, int width, int height);
|
||||
void (*window_focus)(WmWindowHandle window);
|
||||
|
||||
/* Events */
|
||||
bool (*poll_event)(WmBackendEvent *event_out);
|
||||
|
||||
/* ... 80+ operations */
|
||||
} BackendInterface;</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>X11 Backend</h3>
|
||||
<p>The X11 backend is the reference implementation, translating abstract operations to X11 calls:</p>
|
||||
<ul>
|
||||
<li>Event translation (X11 → abstract events)</li>
|
||||
<li>Protocol support (ICCCM, EWMH)</li>
|
||||
<li>Property management with atom caching</li>
|
||||
<li>Error handling with custom handlers</li>
|
||||
</ul>
|
||||
|
||||
<h3>Future Backends</h3>
|
||||
<p>The architecture supports multiple backends:</p>
|
||||
<ul>
|
||||
<li><strong>X11</strong> - Current, fully implemented</li>
|
||||
<li><strong>Wayland</strong> - Planned for future</li>
|
||||
<li><strong>Headless</strong> - For testing and CI</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="client-abstraction">Client Abstraction</h2>
|
||||
<p>The <code>AbstractClient</code> type provides a backend-agnostic representation of a managed window:</p>
|
||||
|
||||
<div class="code-block">
|
||||
<pre><code>/* Create from native window */
|
||||
AbstractClient* client = wm_client_create(window, WM_CLIENT_TYPE_NORMAL);
|
||||
|
||||
/* State management */
|
||||
wm_client_set_state(client, WM_CLIENT_STATE_FULLSCREEN);
|
||||
wm_client_add_state(client, WM_CLIENT_STATE_FLOATING);
|
||||
bool is_floating = wm_client_is_floating(client);
|
||||
|
||||
/* Geometry */
|
||||
WmRect geom = wm_client_get_geometry(client);
|
||||
wm_client_set_geometry(client, &new_geom);
|
||||
wm_client_move_resize(client, x, y, width, height);
|
||||
|
||||
/* Properties */
|
||||
wm_client_set_title(client, "New Title");
|
||||
const char* title = wm_client_get_title(client);</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>Legacy Compatibility</h3>
|
||||
<p>Abstract clients maintain bidirectional synchronization with legacy <code>Client</code> structures:</p>
|
||||
<div class="code-block">
|
||||
<pre><code>/* Wrap existing legacy client */
|
||||
AbstractClient* abs_client = wm_client_from_legacy(legacy_client);
|
||||
|
||||
/* Access legacy client when needed */
|
||||
Client* legacy = wm_client_get_legacy(abs_client);</code></pre>
|
||||
</div>
|
||||
|
||||
<h2 id="containers">Container Types</h2>
|
||||
<p>Safe, dynamic container implementations:</p>
|
||||
|
||||
<h3>WmString (Dynamic Strings)</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>WmString* str = wm_string_new("Hello");
|
||||
wm_string_append(str, " World");
|
||||
wm_string_append_printf(str, " %d", 42);
|
||||
|
||||
const char* cstr = wm_string_cstr(str);
|
||||
bool empty = wm_string_is_empty(str);
|
||||
|
||||
wm_string_destroy(str);</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>WmList (Dynamic Arrays)</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>WmList* list = wm_list_new();
|
||||
wm_list_append(list, item1);
|
||||
wm_list_prepend(list, item2);
|
||||
|
||||
void* item = wm_list_get(list, 0);
|
||||
wm_list_foreach(list, my_callback, user_data);
|
||||
|
||||
wm_list_destroy(list);</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>WmHashMap</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>WmHashMap* map = wm_hashmap_new_string_key();
|
||||
wm_hashmap_insert_string(map, "key", value);
|
||||
|
||||
void* value = wm_hashmap_get_string(map, "key");
|
||||
bool exists = wm_hashmap_contains_string(map, "key");
|
||||
|
||||
wm_hashmap_destroy(map);</code></pre>
|
||||
</div>
|
||||
|
||||
<h2 id="migration">Migration Strategy</h2>
|
||||
<p>The abstraction layer uses an incremental migration approach:</p>
|
||||
|
||||
<ol>
|
||||
<li><strong>Phase 1: Infrastructure</strong> (Complete)
|
||||
<ul>
|
||||
<li>Core types defined</li>
|
||||
<li>Backend interface specified</li>
|
||||
<li>X11 backend implemented</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>Phase 2: Client Migration</strong> (Complete)
|
||||
<ul>
|
||||
<li>AbstractClient type created</li>
|
||||
<li>Bidirectional sync with legacy Client</li>
|
||||
<li>Client manager with MRU tracking</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>Phase 3: Plugin System</strong> (Complete)
|
||||
<ul>
|
||||
<li>Layout plugin API</li>
|
||||
<li>Widget plugin API</li>
|
||||
<li>4 built-in layout plugins</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>Phase 4: Future</strong>
|
||||
<ul>
|
||||
<li>Gradual migration of existing code</li>
|
||||
<li>Wayland backend implementation</li>
|
||||
<li>Legacy code deprecation (long-term)</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<strong>Note:</strong> The abstraction layer is fully backward compatible. Existing code using X11 types continues to work unchanged.
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>DWN Window Manager - retoor <retoor@molodetz.nl></p>
|
||||
</footer>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -13,7 +13,7 @@
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>DWN</h1>
|
||||
<span class="version">v1.0.0</span>
|
||||
<span class="version">v2.0.0</span>
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
@@ -47,6 +47,8 @@
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-title">Advanced</div>
|
||||
<a href="architecture.html" class="nav-link">Architecture</a>
|
||||
<a href="abstraction-layer.html" class="nav-link">Abstraction Layer</a>
|
||||
<a href="plugin-development.html" class="nav-link">Plugin Development</a>
|
||||
<a href="building.html" class="nav-link">Building from Source</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
+132
-81
@@ -13,7 +13,7 @@
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>DWN</h1>
|
||||
<span class="version">v1.0.0</span>
|
||||
<span class="version">v2.0.0</span>
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
@@ -47,6 +47,8 @@
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-title">Advanced</div>
|
||||
<a href="architecture.html" class="nav-link">Architecture</a>
|
||||
<a href="abstraction-layer.html" class="nav-link">Abstraction Layer</a>
|
||||
<a href="plugin-development.html" class="nav-link">Plugin Development</a>
|
||||
<a href="building.html" class="nav-link">Building from Source</a>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -65,6 +67,7 @@
|
||||
<li><a href="#python">Python Examples</a></li>
|
||||
<li><a href="#javascript">JavaScript Examples</a></li>
|
||||
<li><a href="#bash">Bash Examples</a></li>
|
||||
<li><a href="#fade-control">Fade Effect Control</a></li>
|
||||
<li><a href="#events">Event Subscription</a></li>
|
||||
<li><a href="#automation">Automation Recipes</a></li>
|
||||
<li><a href="#browser-ocr">Browser Automation with OCR</a></li>
|
||||
@@ -78,17 +81,17 @@
|
||||
<pre><code>import json
|
||||
import websocket
|
||||
|
||||
ws = websocket.create_connection("ws://localhost:8777")
|
||||
ws = websocket.create_connection("ws://localhost:8777/ws")
|
||||
|
||||
def send_command(command, **params):
|
||||
request = {"command": command, **params}
|
||||
ws.send(json.dumps(request))
|
||||
return json.loads(ws.recv())
|
||||
|
||||
# List all windows
|
||||
result = send_command("list_windows")
|
||||
for window in result["windows"]:
|
||||
print(f"{window['title']} ({window['class']})")
|
||||
# List all clients
|
||||
result = send_command("get_clients")
|
||||
for client in result["clients"]:
|
||||
print(f"{client['title']} ({client['class']})")
|
||||
|
||||
ws.close()</code></pre>
|
||||
</div>
|
||||
@@ -100,21 +103,21 @@ ws.close()</code></pre>
|
||||
client = DWNClient()
|
||||
client.connect()
|
||||
|
||||
# Get all windows
|
||||
windows = client.list_windows()
|
||||
print(f"Found {len(windows)} windows")
|
||||
# Get all clients
|
||||
clients = client.get_clients()
|
||||
print(f"Found {len(clients)} clients")
|
||||
|
||||
# Focus window by title
|
||||
for w in windows:
|
||||
if "Firefox" in w["title"]:
|
||||
client.focus_window(w["id"])
|
||||
# Focus client by title
|
||||
for c in clients:
|
||||
if "Firefox" in c["title"]:
|
||||
client.focus_client(c["window"])
|
||||
break
|
||||
|
||||
# Switch to workspace 3
|
||||
client.switch_workspace(2)
|
||||
|
||||
# Type some text
|
||||
client.type_text("Hello from Python!")
|
||||
client.key_type("Hello from Python!")
|
||||
|
||||
client.disconnect()</code></pre>
|
||||
</div>
|
||||
@@ -145,30 +148,30 @@ print(ocr_result["text"])
|
||||
client.disconnect()</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>Window Arrangement Script</h3>
|
||||
<h3>Client Arrangement Script</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>from dwn_api_client import DWNClient
|
||||
|
||||
def arrange_coding_setup(client):
|
||||
"""Arrange windows for coding: editor left, terminal right"""
|
||||
windows = client.list_windows()
|
||||
"""Arrange clients for coding: editor left, terminal right"""
|
||||
clients = client.get_clients()
|
||||
|
||||
# Find VS Code and terminal
|
||||
vscode = None
|
||||
terminal = None
|
||||
for w in windows:
|
||||
if "code" in w["class"].lower():
|
||||
vscode = w
|
||||
elif "terminal" in w["class"].lower():
|
||||
terminal = w
|
||||
for c in clients:
|
||||
if "code" in c["class"].lower():
|
||||
vscode = c
|
||||
elif "terminal" in c["class"].lower():
|
||||
terminal = c
|
||||
|
||||
if vscode:
|
||||
client.move_window(vscode["id"], 0, 32)
|
||||
client.resize_window(vscode["id"], 960, 1048)
|
||||
client.move_client(vscode["window"], 0, 32)
|
||||
client.resize_client(vscode["window"], 960, 1048)
|
||||
|
||||
if terminal:
|
||||
client.move_window(terminal["id"], 960, 32)
|
||||
client.resize_window(terminal["id"], 960, 1048)
|
||||
client.move_client(terminal["window"], 960, 32)
|
||||
client.resize_client(terminal["window"], 960, 1048)
|
||||
|
||||
client = DWNClient()
|
||||
client.connect()
|
||||
@@ -183,15 +186,15 @@ import json
|
||||
import websockets
|
||||
|
||||
async def main():
|
||||
async with websockets.connect("ws://localhost:8777") as ws:
|
||||
async with websockets.connect("ws://localhost:8777/ws") as ws:
|
||||
# Send command
|
||||
await ws.send(json.dumps({"command": "list_windows"}))
|
||||
await ws.send(json.dumps({"command": "get_clients"}))
|
||||
|
||||
# Receive response
|
||||
response = json.loads(await ws.recv())
|
||||
|
||||
for window in response["windows"]:
|
||||
print(f"Window: {window['title']}")
|
||||
for client in response["clients"]:
|
||||
print(f"Client: {client['title']}")
|
||||
|
||||
asyncio.run(main())</code></pre>
|
||||
</div>
|
||||
@@ -201,7 +204,7 @@ asyncio.run(main())</code></pre>
|
||||
<h3>Browser WebSocket</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>class DWNClient {
|
||||
constructor(url = 'ws://localhost:8777') {
|
||||
constructor(url = 'ws://localhost:8777/ws') {
|
||||
this.url = url;
|
||||
this.ws = null;
|
||||
this.pending = new Map();
|
||||
@@ -228,16 +231,16 @@ asyncio.run(main())</code></pre>
|
||||
this.ws.send(JSON.stringify(request));
|
||||
}
|
||||
|
||||
async listWindows() {
|
||||
this.send('list_windows');
|
||||
async getClients() {
|
||||
this.send('get_clients');
|
||||
}
|
||||
|
||||
async focusWindow(windowId) {
|
||||
this.send('focus_window', { window: windowId });
|
||||
async focusClient(windowId) {
|
||||
this.send('focus_client', { window: windowId });
|
||||
}
|
||||
|
||||
async typeText(text) {
|
||||
this.send('type_text', { text });
|
||||
async keyType(text) {
|
||||
this.send('key_type', { text });
|
||||
}
|
||||
|
||||
async screenshot(mode = 'fullscreen') {
|
||||
@@ -248,28 +251,28 @@ asyncio.run(main())</code></pre>
|
||||
// Usage
|
||||
const client = new DWNClient();
|
||||
await client.connect();
|
||||
await client.listWindows();</code></pre>
|
||||
await client.getClients();</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>Node.js Client</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>const WebSocket = require('ws');
|
||||
|
||||
const ws = new WebSocket('ws://localhost:8777');
|
||||
const ws = new WebSocket('ws://localhost:8777/ws');
|
||||
|
||||
ws.on('open', () => {
|
||||
console.log('Connected to DWN');
|
||||
|
||||
// List windows
|
||||
ws.send(JSON.stringify({ command: 'list_windows' }));
|
||||
// List clients
|
||||
ws.send(JSON.stringify({ command: 'get_clients' }));
|
||||
});
|
||||
|
||||
ws.on('message', (data) => {
|
||||
const response = JSON.parse(data);
|
||||
|
||||
if (response.windows) {
|
||||
response.windows.forEach(w => {
|
||||
console.log(`${w.title} - ${w.class}`);
|
||||
if (response.clients) {
|
||||
response.clients.forEach(c => {
|
||||
console.log(`${c.title} - ${c.class}`);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -311,18 +314,18 @@ ws.on('error', (err) => {
|
||||
<div class="code-block">
|
||||
<pre><code>#!/bin/bash
|
||||
|
||||
# List windows
|
||||
echo '{"command": "list_windows"}' | websocat ws://localhost:8777
|
||||
# List clients
|
||||
echo '{"command": "get_clients"}' | websocat ws://localhost:8777/ws
|
||||
|
||||
# Focus window by ID
|
||||
echo '{"command": "focus_window", "window": 12345678}' | websocat ws://localhost:8777
|
||||
# Focus client by ID
|
||||
echo '{"command": "focus_client", "window": 12345678}' | websocat ws://localhost:8777/ws
|
||||
|
||||
# Switch workspace
|
||||
echo '{"command": "switch_workspace", "workspace": 2}' | websocat ws://localhost:8777
|
||||
echo '{"command": "switch_workspace", "workspace": 2}' | websocat ws://localhost:8777/ws
|
||||
|
||||
# Take screenshot and save
|
||||
echo '{"command": "screenshot", "mode": "fullscreen"}' | \
|
||||
websocat ws://localhost:8777 | \
|
||||
websocat ws://localhost:8777/ws | \
|
||||
jq -r '.data' | \
|
||||
base64 -d > screenshot.png</code></pre>
|
||||
</div>
|
||||
@@ -332,10 +335,10 @@ echo '{"command": "screenshot", "mode": "fullscreen"}' | \
|
||||
<pre><code>#!/bin/bash
|
||||
|
||||
# One-liner command
|
||||
echo '{"command": "list_windows"}' | wscat -c ws://localhost:8777 -w 1
|
||||
echo '{"command": "get_clients"}' | wscat -c ws://localhost:8777/ws -w 1
|
||||
|
||||
# Interactive session
|
||||
wscat -c ws://localhost:8777
|
||||
wscat -c ws://localhost:8777/ws
|
||||
# Then type commands manually</code></pre>
|
||||
</div>
|
||||
|
||||
@@ -344,17 +347,65 @@ wscat -c ws://localhost:8777
|
||||
<pre><code>#!/bin/bash
|
||||
|
||||
dwn_command() {
|
||||
echo "$1" | websocat -n1 ws://localhost:8777
|
||||
echo "$1" | websocat -n1 ws://localhost:8777/ws
|
||||
}
|
||||
|
||||
# Get focused window
|
||||
dwn_command '{"command": "get_focused"}' | jq '.window.title'
|
||||
# Get focused client
|
||||
dwn_command '{"command": "get_focused_client"}' | jq '.client.title'
|
||||
|
||||
# Type text
|
||||
dwn_command '{"command": "type_text", "text": "Hello!"}'
|
||||
dwn_command '{"command": "key_type", "text": "Hello!"}'
|
||||
|
||||
# Launch application
|
||||
dwn_command '{"command": "spawn", "program": "firefox"}'</code></pre>
|
||||
dwn_command '{"command": "run_command", "exec": "firefox"}'</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>Fade Effect Control</h3>
|
||||
<p>Control DWN's fade animation effects via API:</p>
|
||||
<div class="code-block">
|
||||
<pre><code>import json
|
||||
import websocket
|
||||
|
||||
ws = websocket.create_connection("ws://localhost:8777/ws")
|
||||
|
||||
# Get current fade settings
|
||||
ws.send(json.dumps({"command": "get_fade_settings"}))
|
||||
response = json.loads(ws.recv())
|
||||
print(f"Speed: {response['fade_speed']}, Intensity: {response['fade_intensity']}")
|
||||
|
||||
# Set fade animation speed (0.1 - 3.0)
|
||||
ws.send(json.dumps({"command": "set_fade_speed", "speed": 1.5}))
|
||||
|
||||
# Set fade glow intensity (0.0 - 1.0)
|
||||
ws.send(json.dumps({"command": "set_fade_intensity", "intensity": 0.8}))
|
||||
|
||||
# Subscribe to fade change events
|
||||
ws.send(json.dumps({
|
||||
"command": "subscribe",
|
||||
"events": ["fade_speed_changed", "fade_intensity_changed"]
|
||||
}))
|
||||
|
||||
# Listen for events
|
||||
while True:
|
||||
event = json.loads(ws.recv())
|
||||
if event.get("type") == "event":
|
||||
print(f"Event: {event['event']}")
|
||||
print(f"Data: {event['data']}")</code></pre>
|
||||
</div>
|
||||
|
||||
<p>Using the provided fade control demo script:</p>
|
||||
<div class="code-block">
|
||||
<pre><code># Get current fade settings
|
||||
python3 examples/fade_control_demo.py
|
||||
|
||||
# Set fade speed
|
||||
python3 examples/fade_control_demo.py --speed 1.5
|
||||
|
||||
# Set fade intensity
|
||||
python3 examples/fade_control_demo.py --intensity 0.8
|
||||
|
||||
# Listen for fade events
|
||||
python3 examples/fade_control_demo.py --listen --duration 30</code></pre>
|
||||
</div>
|
||||
|
||||
<h2 id="events">Event Subscription</h2>
|
||||
@@ -452,7 +503,7 @@ activity_logger()</code></pre>
|
||||
|
||||
<h3>JavaScript Event Listener</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>const ws = new WebSocket('ws://localhost:8777');
|
||||
<pre><code>const ws = new WebSocket('ws://localhost:8777/ws');
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('Connected to DWN');
|
||||
@@ -491,7 +542,7 @@ ws.onclose = () => {
|
||||
};</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>Reactive Window Arrangement</h3>
|
||||
<h3>Reactive Client Arrangement</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>from dwn_api_client import DWNClient
|
||||
|
||||
@@ -508,7 +559,7 @@ def auto_arrange():
|
||||
|
||||
client.subscribe(events=["window_created"])
|
||||
|
||||
print("Auto-arranging windows...")
|
||||
print("Auto-arranging clients...")
|
||||
|
||||
try:
|
||||
while True:
|
||||
@@ -541,7 +592,7 @@ auto_arrange()</code></pre>
|
||||
|
||||
<h2 id="automation">Automation Recipes</h2>
|
||||
|
||||
<h3>Auto-Arrange Windows by Class</h3>
|
||||
<h3>Auto-Arrange Clients by Class</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>from dwn_api_client import DWNClient
|
||||
|
||||
@@ -556,17 +607,17 @@ def auto_arrange():
|
||||
client = DWNClient()
|
||||
client.connect()
|
||||
|
||||
windows = client.list_windows()
|
||||
for w in windows:
|
||||
win_class = w["class"].lower()
|
||||
clients = client.get_clients()
|
||||
for c in clients:
|
||||
wm_class = c["class"].lower()
|
||||
for pattern, rules in LAYOUT_RULES.items():
|
||||
if pattern in win_class:
|
||||
if w["workspace"] != rules["workspace"]:
|
||||
client.move_window_to_workspace(
|
||||
w["id"], rules["workspace"]
|
||||
if pattern in wm_class:
|
||||
if c["workspace"] != rules["workspace"]:
|
||||
client.move_client_to_workspace(
|
||||
c["window"], rules["workspace"]
|
||||
)
|
||||
if w["floating"] != rules["floating"]:
|
||||
client.set_floating(w["id"], rules["floating"])
|
||||
if c["floating"] != rules["floating"]:
|
||||
client.float_client(c["window"], rules["floating"])
|
||||
break
|
||||
|
||||
client.disconnect()
|
||||
@@ -609,14 +660,14 @@ def screenshot_monitor(interval=60, output_dir="screenshots"):
|
||||
screenshot_monitor(interval=300) # Every 5 minutes</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>Window Focus Logger</h3>
|
||||
<h3>Client Focus Logger</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>import time
|
||||
from datetime import datetime
|
||||
from dwn_api_client import DWNClient
|
||||
|
||||
def focus_logger(log_file="focus_log.txt"):
|
||||
"""Log window focus changes"""
|
||||
"""Log client focus changes"""
|
||||
client = DWNClient()
|
||||
client.connect()
|
||||
|
||||
@@ -625,16 +676,16 @@ def focus_logger(log_file="focus_log.txt"):
|
||||
try:
|
||||
with open(log_file, "a") as f:
|
||||
while True:
|
||||
windows = client.list_windows()
|
||||
focused = next((w for w in windows if w["focused"]), None)
|
||||
clients = client.get_clients()
|
||||
focused = next((c for c in clients if c["focused"]), None)
|
||||
|
||||
if focused and focused["id"] != last_focused:
|
||||
if focused and focused["window"] != last_focused:
|
||||
timestamp = datetime.now().isoformat()
|
||||
entry = f"{timestamp} | {focused['title']} ({focused['class']})\n"
|
||||
f.write(entry)
|
||||
f.flush()
|
||||
print(entry.strip())
|
||||
last_focused = focused["id"]
|
||||
last_focused = focused["window"]
|
||||
|
||||
time.sleep(1)
|
||||
except KeyboardInterrupt:
|
||||
@@ -682,24 +733,24 @@ client.disconnect()</code></pre>
|
||||
<div class="code-block">
|
||||
<pre><code>from dwn_api_client import DWNClient
|
||||
|
||||
def read_active_window():
|
||||
"""Extract and print text from active window"""
|
||||
def read_active_client():
|
||||
"""Extract and print text from active client"""
|
||||
client = DWNClient()
|
||||
client.connect()
|
||||
|
||||
# Capture active window
|
||||
# Capture active client
|
||||
screenshot = client.screenshot("active")
|
||||
|
||||
# Extract text
|
||||
ocr_result = client.ocr(screenshot["data"])
|
||||
|
||||
print(f"Text from active window (confidence: {ocr_result['confidence']:.0%}):")
|
||||
print(f"Text from active client (confidence: {ocr_result['confidence']:.0%}):")
|
||||
print("-" * 40)
|
||||
print(ocr_result["text"])
|
||||
|
||||
client.disconnect()
|
||||
|
||||
read_active_window()</code></pre>
|
||||
read_active_client()</code></pre>
|
||||
</div>
|
||||
|
||||
<h3 id="browser-ocr">Browser Automation with OCR</h3>
|
||||
|
||||
+64
-27
@@ -13,7 +13,7 @@
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>DWN</h1>
|
||||
<span class="version">v1.0.0</span>
|
||||
<span class="version">v2.0.0</span>
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
@@ -47,6 +47,8 @@
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-title">Advanced</div>
|
||||
<a href="architecture.html" class="nav-link">Architecture</a>
|
||||
<a href="abstraction-layer.html" class="nav-link">Abstraction Layer</a>
|
||||
<a href="plugin-development.html" class="nav-link">Plugin Development</a>
|
||||
<a href="building.html" class="nav-link">Building from Source</a>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -98,7 +100,7 @@ port = 8777</code></pre>
|
||||
</div>
|
||||
|
||||
<h2 id="connecting">Connecting</h2>
|
||||
<p>Connect via WebSocket to <code>ws://localhost:8777</code> (or your configured port).</p>
|
||||
<p>Connect via WebSocket to <code>ws://localhost:8777/ws</code> (or your configured port). The <code>/ws</code> path is required.</p>
|
||||
|
||||
<h3>Testing with wscat</h3>
|
||||
<div class="code-block">
|
||||
@@ -106,11 +108,11 @@ port = 8777</code></pre>
|
||||
npm install -g wscat
|
||||
|
||||
# Connect to DWN
|
||||
wscat -c ws://localhost:8777
|
||||
wscat -c ws://localhost:8777/ws
|
||||
|
||||
# Send a command
|
||||
> {"command": "list_windows"}
|
||||
< {"status": "ok", "windows": [...]}</code></pre>
|
||||
> {"command": "get_clients"}
|
||||
< {"status": "ok", "clients": [...]}</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>Testing with websocat</h3>
|
||||
@@ -119,7 +121,7 @@ wscat -c ws://localhost:8777
|
||||
cargo install websocat
|
||||
|
||||
# Connect and send command
|
||||
echo '{"command": "list_windows"}' | websocat ws://localhost:8777</code></pre>
|
||||
echo '{"command": "get_clients"}' | websocat ws://localhost:8777/ws</code></pre>
|
||||
</div>
|
||||
|
||||
<h2 id="protocol">Protocol</h2>
|
||||
@@ -161,24 +163,24 @@ echo '{"command": "list_windows"}' | websocat ws://localhost:8777</code></pre>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Windows</td>
|
||||
<td>list_windows, focus_window, close_window, move_window, resize_window</td>
|
||||
<td>Clients</td>
|
||||
<td>get_clients, find_clients, get_focused_client, focus_client, focus_next, focus_prev, focus_master, close_client, kill_client, move_client, resize_client, minimize_client, restore_client, maximize_client, fullscreen_client, float_client, raise_client, lower_client, snap_client</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Workspaces</td>
|
||||
<td>list_workspaces, switch_workspace, move_to_workspace</td>
|
||||
<td>get_workspaces, switch_workspace, switch_workspace_next, switch_workspace_prev, move_client_to_workspace</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Layout</td>
|
||||
<td>get_layout, set_layout, set_master_ratio</td>
|
||||
<td>set_layout, cycle_layout, set_master_ratio, adjust_master_ratio, set_master_count, adjust_master_count</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Keyboard</td>
|
||||
<td>key_press, key_release, type_text</td>
|
||||
<td>key_press, key_release, key_tap, key_type, get_keybindings</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mouse</td>
|
||||
<td>mouse_move, mouse_click, mouse_drag</td>
|
||||
<td>mouse_move, mouse_move_relative, mouse_click, mouse_press, mouse_release, mouse_scroll, get_mouse_position</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Screenshot</td>
|
||||
@@ -190,7 +192,39 @@ echo '{"command": "list_windows"}' | websocat ws://localhost:8777</code></pre>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>System</td>
|
||||
<td>get_monitors, spawn, notify</td>
|
||||
<td>get_status, get_screen_info, run_command, show_desktop, get_config, reload_config</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Notifications</td>
|
||||
<td>notify, close_notification, get_notifications</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>System Tray</td>
|
||||
<td>get_battery_state, get_audio_state, set_audio_volume, toggle_audio_mute, get_wifi_state</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Panels</td>
|
||||
<td>get_panel_state, show_panel, hide_panel, toggle_panel</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AI</td>
|
||||
<td>ai_is_available, ai_command, exa_is_available, exa_search</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>News</td>
|
||||
<td>get_news, news_next, news_prev, news_open</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Demo/Tutorial</td>
|
||||
<td>start_demo, stop_demo, get_demo_state, start_tutorial, stop_tutorial, get_tutorial_state</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Events</td>
|
||||
<td>subscribe, unsubscribe, list_events</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Fade Effects</td>
|
||||
<td>get_fade_settings, set_fade_speed, set_fade_intensity</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -198,32 +232,35 @@ echo '{"command": "list_windows"}' | websocat ws://localhost:8777</code></pre>
|
||||
|
||||
<h2 id="quick-start">Quick Start</h2>
|
||||
|
||||
<h3>List Windows</h3>
|
||||
<h3>List Clients</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>// Request
|
||||
{"command": "list_windows"}
|
||||
{"command": "get_clients"}
|
||||
|
||||
// Response
|
||||
{
|
||||
"status": "ok",
|
||||
"windows": [
|
||||
"clients": [
|
||||
{
|
||||
"id": 12345678,
|
||||
"window": 12345678,
|
||||
"title": "Firefox",
|
||||
"class": "firefox",
|
||||
"workspace": 0,
|
||||
"x": 0, "y": 32,
|
||||
"width": 960, "height": 540,
|
||||
"focused": true,
|
||||
"floating": false
|
||||
"floating": false,
|
||||
"fullscreen": false,
|
||||
"maximized": false,
|
||||
"minimized": false
|
||||
}
|
||||
]
|
||||
}</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>Focus a Window</h3>
|
||||
<h3>Focus a Client</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>{"command": "focus_window", "window": 12345678}</code></pre>
|
||||
<pre><code>{"command": "focus_client", "window": 12345678}</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>Switch Workspace</h3>
|
||||
@@ -233,7 +270,7 @@ echo '{"command": "list_windows"}' | websocat ws://localhost:8777</code></pre>
|
||||
|
||||
<h3>Type Text</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>{"command": "type_text", "text": "Hello, World!"}</code></pre>
|
||||
<pre><code>{"command": "key_type", "text": "Hello, World!"}</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>Take Screenshot</h3>
|
||||
@@ -263,11 +300,11 @@ echo '{"command": "list_windows"}' | websocat ws://localhost:8777</code></pre>
|
||||
client = DWNClient()
|
||||
client.connect()
|
||||
|
||||
# List windows
|
||||
windows = client.list_windows()
|
||||
# List clients
|
||||
clients = client.get_clients()
|
||||
|
||||
# Focus a window
|
||||
client.focus_window(windows[0]['id'])
|
||||
# Focus a client
|
||||
client.focus_client(clients[0]['window'])
|
||||
|
||||
# Take screenshot
|
||||
result = client.screenshot('fullscreen')
|
||||
@@ -280,10 +317,10 @@ client.disconnect()</code></pre>
|
||||
|
||||
<h3>JavaScript (Browser)</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>const ws = new WebSocket('ws://localhost:8777');
|
||||
<pre><code>const ws = new WebSocket('ws://localhost:8777/ws');
|
||||
|
||||
ws.onopen = () => {
|
||||
ws.send(JSON.stringify({command: 'list_windows'}));
|
||||
ws.send(JSON.stringify({command: 'get_clients'}));
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
|
||||
+918
-179
File diff suppressed because it is too large
Load Diff
+53
-18
@@ -13,7 +13,7 @@
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>DWN</h1>
|
||||
<span class="version">v1.0.0</span>
|
||||
<span class="version">v2.0.0</span>
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
@@ -47,6 +47,8 @@
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-title">Advanced</div>
|
||||
<a href="architecture.html" class="nav-link active">Architecture</a>
|
||||
<a href="abstraction-layer.html" class="nav-link">Abstraction Layer</a>
|
||||
<a href="plugin-development.html" class="nav-link">Plugin Development</a>
|
||||
<a href="building.html" class="nav-link">Building from Source</a>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -63,6 +65,7 @@
|
||||
<div class="toc-title">On this page</div>
|
||||
<ul class="toc-list">
|
||||
<li><a href="#overview">Overview</a></li>
|
||||
<li><a href="#abstraction">Abstraction Layer</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>
|
||||
@@ -72,30 +75,62 @@
|
||||
</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>
|
||||
<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>
|
||||
|
||||
<div class="code-block">
|
||||
<pre><code>┌─────────────────────────────────────────────────────────┐
|
||||
│ DWN Window Manager │
|
||||
│ DWN Application │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ main │ │ keys │ │ panel │ │ api │ │
|
||||
│ │ loop │ │ handler │ │ render │ │ server │ │
|
||||
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
|
||||
│ │ │ │ │ │
|
||||
│ ┌────┴────────────┴────────────┴────────────┴────┐ │
|
||||
│ │ DWNState (Global Singleton) │ │
|
||||
│ └────┬────────────┬────────────┬────────────┬────┘ │
|
||||
│ │ │ │ │ │
|
||||
│ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ │
|
||||
│ │ client │ │workspace│ │ layout │ │ atoms │ │
|
||||
│ │ mgmt │ │ mgmt │ │ engine │ │ (EWMH) │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ X11 / Xlib │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
|
||||
│ │ 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) │ │
|
||||
│ └───────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘</code></pre>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
|
||||
<h2 id="modules">Module Structure</h2>
|
||||
<p>Each module has a header in <code>include/</code> and implementation in <code>src/</code>.</p>
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>DWN</h1>
|
||||
<span class="version">v1.0.0</span>
|
||||
<span class="version">v2.0.0</span>
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
@@ -47,6 +47,8 @@
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-title">Advanced</div>
|
||||
<a href="architecture.html" class="nav-link">Architecture</a>
|
||||
<a href="abstraction-layer.html" class="nav-link">Abstraction Layer</a>
|
||||
<a href="plugin-development.html" class="nav-link">Plugin Development</a>
|
||||
<a href="building.html" class="nav-link active">Building from Source</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
+130
-1
@@ -13,7 +13,7 @@
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>DWN</h1>
|
||||
<span class="version">v1.0.0</span>
|
||||
<span class="version">v2.0.0</span>
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
@@ -47,6 +47,8 @@
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-title">Advanced</div>
|
||||
<a href="architecture.html" class="nav-link">Architecture</a>
|
||||
<a href="abstraction-layer.html" class="nav-link">Abstraction Layer</a>
|
||||
<a href="plugin-development.html" class="nav-link">Plugin Development</a>
|
||||
<a href="building.html" class="nav-link">Building from Source</a>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -309,6 +311,133 @@ ai_timeout = 15000
|
||||
window_timeout = 5000</code></pre>
|
||||
</div>
|
||||
|
||||
<h3 id="rules">[rules] - Window Rules</h3>
|
||||
<p>Automatically apply settings to windows based on their class or title. Rules use glob patterns for matching.</p>
|
||||
|
||||
<div class="code-block">
|
||||
<pre><code>[rules]
|
||||
Firefox = workspace:2, floating:false
|
||||
class:*terminal* = workspace:1
|
||||
title:*Calculator* = floating:true, width:400, height:300
|
||||
class:Telegram = workspace:9, sticky:true
|
||||
Gimp = floating:true
|
||||
class:mpv = fullscreen:true</code></pre>
|
||||
</div>
|
||||
|
||||
<h4>Rule Syntax</h4>
|
||||
<p>Each rule has the format: <code>pattern = property:value, property:value, ...</code></p>
|
||||
|
||||
<div class="table-container">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Pattern Prefix</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>class:</code></td>
|
||||
<td>Match by WM_CLASS (default if no prefix)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>title:</code></td>
|
||||
<td>Match by window title</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>(no prefix)</td>
|
||||
<td>Treated as class pattern</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h4>Available Properties</h4>
|
||||
<div class="table-container">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Property</th>
|
||||
<th>Values</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>workspace</code></td>
|
||||
<td>1-9</td>
|
||||
<td>Move to specific workspace</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>floating</code></td>
|
||||
<td>true/false</td>
|
||||
<td>Set floating mode</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>sticky</code></td>
|
||||
<td>true/false</td>
|
||||
<td>Visible on all workspaces</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>fullscreen</code></td>
|
||||
<td>true/false</td>
|
||||
<td>Start in fullscreen mode</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>width</code></td>
|
||||
<td>pixels</td>
|
||||
<td>Set initial width</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>height</code></td>
|
||||
<td>pixels</td>
|
||||
<td>Set initial height</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>x</code></td>
|
||||
<td>pixels</td>
|
||||
<td>Set initial X position</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>y</code></td>
|
||||
<td>pixels</td>
|
||||
<td>Set initial Y position</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h4>Pattern Matching</h4>
|
||||
<ul>
|
||||
<li><code>*</code> - Matches any sequence of characters</li>
|
||||
<li><code>?</code> - Matches any single character</li>
|
||||
<li><code>[abc]</code> - Matches any character in brackets</li>
|
||||
<li>Matching is case-insensitive</li>
|
||||
</ul>
|
||||
|
||||
<h4>Examples</h4>
|
||||
<div class="code-block">
|
||||
<pre><code>[rules]
|
||||
# Open Firefox on workspace 2
|
||||
Firefox = workspace:2
|
||||
|
||||
# All terminals on workspace 1
|
||||
class:*terminal* = workspace:1
|
||||
|
||||
# Calculator always floating with specific size
|
||||
title:*Calculator* = floating:true, width:400, height:300
|
||||
|
||||
# Picture-in-picture windows
|
||||
title:Picture-in-Picture = floating:true, sticky:true
|
||||
|
||||
# Gimp dialogs floating
|
||||
class:Gimp = floating:true
|
||||
|
||||
# Video players fullscreen
|
||||
class:mpv = fullscreen:true
|
||||
class:vlc = fullscreen:true</code></pre>
|
||||
</div>
|
||||
|
||||
<h2>Environment Variables</h2>
|
||||
<div class="table-container">
|
||||
<table>
|
||||
|
||||
+113
-3
@@ -13,7 +13,7 @@
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>DWN</h1>
|
||||
<span class="version">v1.0.0</span>
|
||||
<span class="version">v2.0.0</span>
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
@@ -47,6 +47,8 @@
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-title">Advanced</div>
|
||||
<a href="architecture.html" class="nav-link">Architecture</a>
|
||||
<a href="abstraction-layer.html" class="nav-link">Abstraction Layer</a>
|
||||
<a href="plugin-development.html" class="nav-link">Plugin Development</a>
|
||||
<a href="building.html" class="nav-link">Building from Source</a>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -63,6 +65,8 @@
|
||||
<div class="toc-title">On this page</div>
|
||||
<ul class="toc-list">
|
||||
<li><a href="#window-management">Window Management</a></li>
|
||||
<li><a href="#window-rules">Window Rules</a></li>
|
||||
<li><a href="#window-marks">Window Marks</a></li>
|
||||
<li><a href="#workspaces">Virtual Workspaces</a></li>
|
||||
<li><a href="#layouts">Layout System</a></li>
|
||||
<li><a href="#panels">Panels & System Tray</a></li>
|
||||
@@ -120,6 +124,85 @@
|
||||
<h3>Alt-Tab Window Cycling</h3>
|
||||
<p>DWN maintains a Most Recently Used (MRU) stack per workspace. <code>Alt+Tab</code> cycles through windows in order of recent use, not visual order.</p>
|
||||
|
||||
<h3>Keyboard Window Control</h3>
|
||||
<p>Move and resize floating windows without leaving the keyboard:</p>
|
||||
<ul>
|
||||
<li><code>Super+Alt+Arrow</code> - Move window by 20 pixels</li>
|
||||
<li><code>Super+Ctrl+Arrow</code> - Resize window by 20 pixels</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="window-rules">Window Rules</h2>
|
||||
<p>Automatically apply settings to windows based on their class or title. Rules are matched using glob patterns with case-insensitive matching.</p>
|
||||
|
||||
<h3>Matching Criteria</h3>
|
||||
<ul>
|
||||
<li><strong>Class Pattern</strong> - Match by WM_CLASS (e.g., <code>Firefox</code>, <code>*terminal*</code>)</li>
|
||||
<li><strong>Title Pattern</strong> - Match by window title (e.g., <code>*Calculator*</code>)</li>
|
||||
<li><strong>Combined</strong> - Match both class and title simultaneously</li>
|
||||
</ul>
|
||||
|
||||
<h3>Available Actions</h3>
|
||||
<div class="table-container">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Property</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>workspace</code></td>
|
||||
<td>Move window to specific workspace (1-9)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>floating</code></td>
|
||||
<td>Set floating state (true/false)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>sticky</code></td>
|
||||
<td>Make window visible on all workspaces</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>fullscreen</code></td>
|
||||
<td>Start window in fullscreen mode</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>width</code>, <code>height</code></td>
|
||||
<td>Set initial window size</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>x</code>, <code>y</code></td>
|
||||
<td>Set initial window position</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p>See <a href="configuration.html#rules">Configuration</a> for rule syntax.</p>
|
||||
|
||||
<h2 id="window-marks">Window Marks</h2>
|
||||
<p>Mark windows with letters (a-z) for instant navigation, inspired by Vim marks.</p>
|
||||
|
||||
<div class="feature-grid">
|
||||
<div class="feature-card">
|
||||
<div class="feature-title">Set Mark</div>
|
||||
<div class="feature-desc">Press <code>Super+M</code> then <code>a-z</code> to mark the focused window.</div>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<div class="feature-title">Jump to Mark</div>
|
||||
<div class="feature-desc">Press <code>Super+'</code> then <code>a-z</code> to instantly focus the marked window.</div>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<div class="feature-title">Cross-Workspace</div>
|
||||
<div class="feature-desc">Marks work across workspaces, automatically switching if needed.</div>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<div class="feature-title">26 Slots</div>
|
||||
<div class="feature-desc">Use any letter a-z for marks. Reassigning overwrites the previous mark.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 id="workspaces">Virtual Workspaces</h2>
|
||||
<p>DWN provides 9 virtual workspaces for organizing your windows.</p>
|
||||
|
||||
@@ -143,7 +226,7 @@
|
||||
</div>
|
||||
|
||||
<h2 id="layouts">Layout System</h2>
|
||||
<p>Three layout modes available per workspace:</p>
|
||||
<p>Six layout modes available per workspace:</p>
|
||||
|
||||
<h3>Tiling Layout</h3>
|
||||
<p>Master-stack tiling with configurable ratios. The first window(s) occupy the master area, others stack on the side.</p>
|
||||
@@ -159,7 +242,22 @@
|
||||
<h3>Monocle Layout</h3>
|
||||
<p>All windows fullscreen and stacked. Use Alt-Tab to switch between them. Ideal for focused work.</p>
|
||||
|
||||
<p>See <a href="layouts.html">Layouts</a> for detailed documentation.</p>
|
||||
<h3>Centered Master Layout</h3>
|
||||
<p>The master window is centered on screen with stack windows divided on left and right sides. Great for wide monitors.</p>
|
||||
|
||||
<h3>Columns Layout</h3>
|
||||
<p>All windows arranged in equal-width vertical columns. Each window takes full height.</p>
|
||||
|
||||
<h3>Fibonacci Layout</h3>
|
||||
<p>Windows arranged in a spiral pattern using recursive splitting. Creates a visually interesting and space-efficient arrangement.</p>
|
||||
|
||||
<h3>Grid Layout</h3>
|
||||
<p>Windows arranged in an automatically-calculated grid pattern. Perfect for comparing multiple documents or monitoring many terminals simultaneously.</p>
|
||||
|
||||
<h3>Plugin System</h3>
|
||||
<p>DWN v2.0 supports custom layout plugins. Create your own window arrangements using the Layout Plugin API. Both built-in and dynamically loaded plugins are supported.</p>
|
||||
|
||||
<p>See <a href="layouts.html">Layouts</a> and <a href="plugin-development.html">Plugin Development</a> for detailed documentation.</p>
|
||||
|
||||
<h2 id="panels">Panels & System Tray</h2>
|
||||
|
||||
@@ -277,6 +375,18 @@
|
||||
|
||||
<p>See <a href="api-overview.html">API Overview</a> for getting started.</p>
|
||||
|
||||
<h2>Abstraction Layer (v2.0)</h2>
|
||||
<p>DWN v2.0 introduces a comprehensive abstraction layer enabling backend portability and plugin extensibility:</p>
|
||||
<ul>
|
||||
<li><strong>Backend Interface</strong> - 80+ operation vtable for X11/Wayland portability</li>
|
||||
<li><strong>Type Safety</strong> - Strongly typed handles replacing void* casts</li>
|
||||
<li><strong>Memory Safety</strong> - Safe string and container abstractions</li>
|
||||
<li><strong>Plugin API</strong> - Extensible architecture for layouts and widgets</li>
|
||||
<li><strong>100% Compatible</strong> - Existing code works unchanged</li>
|
||||
</ul>
|
||||
|
||||
<p>See <a href="abstraction-layer.html">Abstraction Layer</a> for technical details.</p>
|
||||
|
||||
<h2>Protocol Compliance</h2>
|
||||
<p>DWN implements standard X11 protocols for compatibility:</p>
|
||||
<ul>
|
||||
|
||||
+15
-3
@@ -13,7 +13,7 @@
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>DWN</h1>
|
||||
<span class="version">v1.0.0</span>
|
||||
<span class="version">v2.0.0</span>
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
@@ -47,6 +47,8 @@
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-title">Advanced</div>
|
||||
<a href="architecture.html" class="nav-link">Architecture</a>
|
||||
<a href="abstraction-layer.html" class="nav-link">Abstraction Layer</a>
|
||||
<a href="plugin-development.html" class="nav-link">Plugin Development</a>
|
||||
<a href="building.html" class="nav-link">Building from Source</a>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -56,7 +58,7 @@
|
||||
<div class="content">
|
||||
<div class="hero">
|
||||
<h1>DWN</h1>
|
||||
<p class="tagline">A modern X11 window manager with AI integration and WebSocket API</p>
|
||||
<p class="tagline">A modern X11 window manager with AI integration, WebSocket API, and plugin extensibility</p>
|
||||
<div class="btn-group">
|
||||
<a href="installation.html" class="btn">Get Started</a>
|
||||
<a href="api-overview.html" class="btn btn-outline">API Docs</a>
|
||||
@@ -67,7 +69,7 @@
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🪟</div>
|
||||
<div class="feature-title">Multiple Layouts</div>
|
||||
<div class="feature-desc">Tiling, floating, and monocle layouts with per-workspace configuration. Master-stack tiling with adjustable ratios.</div>
|
||||
<div class="feature-desc">Tiling, floating, monocle, and grid layouts with per-workspace configuration. Plugin API for custom layouts.</div>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🖥️</div>
|
||||
@@ -94,6 +96,16 @@
|
||||
<div class="feature-title">Notifications</div>
|
||||
<div class="feature-desc">Built-in D-Bus notification daemon with configurable appearance.</div>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🔧</div>
|
||||
<div class="feature-title">Plugin System</div>
|
||||
<div class="feature-desc">Extensible plugin architecture for layouts and widgets. Dynamic loading support.</div>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">📐</div>
|
||||
<div class="feature-title">Abstraction Layer</div>
|
||||
<div class="feature-desc">Backend-agnostic architecture. Ready for X11, Wayland, and headless backends.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="quick-start">
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>DWN</h1>
|
||||
<span class="version">v1.0.0</span>
|
||||
<span class="version">v2.0.0</span>
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
@@ -47,6 +47,8 @@
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-title">Advanced</div>
|
||||
<a href="architecture.html" class="nav-link">Architecture</a>
|
||||
<a href="abstraction-layer.html" class="nav-link">Abstraction Layer</a>
|
||||
<a href="plugin-development.html" class="nav-link">Plugin Development</a>
|
||||
<a href="building.html" class="nav-link">Building from Source</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
+152
-6
@@ -13,7 +13,7 @@
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>DWN</h1>
|
||||
<span class="version">v1.0.0</span>
|
||||
<span class="version">v2.0.0</span>
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
@@ -47,6 +47,8 @@
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-title">Advanced</div>
|
||||
<a href="architecture.html" class="nav-link">Architecture</a>
|
||||
<a href="abstraction-layer.html" class="nav-link">Abstraction Layer</a>
|
||||
<a href="plugin-development.html" class="nav-link">Plugin Development</a>
|
||||
<a href="building.html" class="nav-link">Building from Source</a>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -66,15 +68,20 @@
|
||||
<li><a href="#tiling">Tiling Layout</a></li>
|
||||
<li><a href="#floating">Floating Layout</a></li>
|
||||
<li><a href="#monocle">Monocle Layout</a></li>
|
||||
<li><a href="#centered-master">Centered Master Layout</a></li>
|
||||
<li><a href="#columns">Columns Layout</a></li>
|
||||
<li><a href="#fibonacci">Fibonacci Layout</a></li>
|
||||
<li><a href="#grid">Grid Layout</a></li>
|
||||
<li><a href="#plugin-system">Plugin System</a></li>
|
||||
<li><a href="#per-workspace">Per-Workspace Settings</a></li>
|
||||
<li><a href="#shortcuts">Layout Shortcuts</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>DWN provides three layout modes that determine how windows are arranged on screen. Each workspace maintains its own layout settings independently.</p>
|
||||
<p>DWN provides six layout modes that determine how windows are arranged on screen. Each workspace maintains its own layout settings independently.</p>
|
||||
|
||||
<p>Press <code>Super+Space</code> to cycle through layouts: Tiling → Floating → Monocle → Tiling</p>
|
||||
<p>Press <code>Super+Space</code> to cycle through layouts: Tiling → Floating → Monocle → Centered Master → Columns → Fibonacci → Tiling</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<strong>Tip:</strong> The current layout is shown in the panel with a symbol: <code>[]=</code> for tiling, <code>><></code> for floating, <code>[M]</code> for monocle.
|
||||
@@ -182,6 +189,141 @@
|
||||
<strong>Note:</strong> Windows maintain decorations in monocle mode unless fullscreen (<code>Alt+F11</code>).
|
||||
</div>
|
||||
|
||||
<h2 id="centered-master">Centered Master Layout</h2>
|
||||
<p>The master window is centered on screen with stack windows divided on left and right sides.</p>
|
||||
|
||||
<h3>How It Works</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>+--------+------------------+--------+
|
||||
| Stack | Master | Stack |
|
||||
| 1 | Window | 3 |
|
||||
+--------+ +--------+
|
||||
| Stack | | Stack |
|
||||
| 2 | | 4 |
|
||||
+--------+------------------+--------+</code></pre>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
<li>The <strong>master window</strong> occupies the center of the screen</li>
|
||||
<li>Stack windows are divided between left and right sides</li>
|
||||
<li>Odd-numbered stack windows go left, even go right</li>
|
||||
<li>Excellent for wide monitors and ultrawide displays</li>
|
||||
</ul>
|
||||
|
||||
<h3>Use Cases</h3>
|
||||
<ul>
|
||||
<li>Keeping primary work centered while referencing side content</li>
|
||||
<li>Video editing with timeline and tools on sides</li>
|
||||
<li>Development with editor centered and documentation on sides</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="columns">Columns Layout</h2>
|
||||
<p>All windows arranged in equal-width vertical columns spanning the full height.</p>
|
||||
|
||||
<h3>How It Works</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>+----------+----------+----------+----------+
|
||||
| | | | |
|
||||
| Window | Window | Window | Window |
|
||||
| 1 | 2 | 3 | 4 |
|
||||
| | | | |
|
||||
| | | | |
|
||||
+----------+----------+----------+----------+</code></pre>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
<li>Each window gets an equal-width column</li>
|
||||
<li>Windows span the full usable height</li>
|
||||
<li>Simple and predictable arrangement</li>
|
||||
</ul>
|
||||
|
||||
<h3>Use Cases</h3>
|
||||
<ul>
|
||||
<li>Comparing multiple files side-by-side</li>
|
||||
<li>Monitoring multiple log files</li>
|
||||
<li>Multi-column text editing</li>
|
||||
<li>Concurrent terminal sessions</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="fibonacci">Fibonacci Layout</h2>
|
||||
<p>Windows arranged in a spiral pattern using recursive splitting, inspired by the Fibonacci sequence.</p>
|
||||
|
||||
<h3>How It Works</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>+------------------+----------+
|
||||
| | |
|
||||
| Window 1 | Window 2 |
|
||||
| +----+-----+
|
||||
| | W3 | |
|
||||
+------------------+----+ W4 |
|
||||
| Window 5 | |
|
||||
+-----------------------+-----+</code></pre>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
<li>First window takes half the screen</li>
|
||||
<li>Each subsequent window takes half the remaining space</li>
|
||||
<li>Alternates between horizontal and vertical splits</li>
|
||||
<li>Creates a visually interesting spiral pattern</li>
|
||||
</ul>
|
||||
|
||||
<h3>Use Cases</h3>
|
||||
<ul>
|
||||
<li>Hierarchical window importance (larger = more important)</li>
|
||||
<li>Primary workspace with progressively smaller utilities</li>
|
||||
<li>Creative workflows with main canvas and tool windows</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="grid">Grid Layout</h2>
|
||||
<p>Windows are arranged in a grid pattern with automatic row/column calculation.</p>
|
||||
|
||||
<h3>How It Works</h3>
|
||||
<div class="code-block">
|
||||
<pre><code>+----------+----------+----------+
|
||||
| Window | Window | Window |
|
||||
| 1 | 2 | 3 |
|
||||
+----------+----------+----------+
|
||||
| Window | Window |
|
||||
| 4 | 5 |
|
||||
+----------+----------+</code></pre>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
<li>Automatically calculates optimal rows and columns</li>
|
||||
<li>Uses square root for balanced grid</li>
|
||||
<li>All windows have equal size</li>
|
||||
<li>Great for viewing multiple documents simultaneously</li>
|
||||
</ul>
|
||||
|
||||
<h3>Use Cases</h3>
|
||||
<ul>
|
||||
<li>Comparing multiple documents or files</li>
|
||||
<li>Monitoring multiple terminals</li>
|
||||
<li>Dashboard-style workflows</li>
|
||||
<li>Multi-way video calls</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="plugin-system">Plugin System (v2.0)</h2>
|
||||
<p>DWN v2.0 introduces a layout plugin system that allows custom layout algorithms to be loaded dynamically or built-in.</p>
|
||||
|
||||
<h3>Built-in Layouts</h3>
|
||||
<ul>
|
||||
<li><strong>tiling</strong> - Master-stack tiling (default)</li>
|
||||
<li><strong>floating</strong> - Traditional floating windows</li>
|
||||
<li><strong>monocle</strong> - Single maximized window</li>
|
||||
<li><strong>centered-master</strong> - Master centered with stacks on sides</li>
|
||||
<li><strong>columns</strong> - Equal-width vertical columns</li>
|
||||
<li><strong>fibonacci</strong> - Spiral recursive splitting</li>
|
||||
<li><strong>grid</strong> - Grid arrangement</li>
|
||||
</ul>
|
||||
|
||||
<h3>Custom Layouts</h3>
|
||||
<p>Developers can create custom layout plugins using the Layout Plugin API. See <a href="plugin-development.html">Plugin Development</a> for details.</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<strong>Plugin API:</strong> Layouts implement the <code>LayoutPluginInterface</code> vtable with an <code>arrange()</code> method that calculates window geometries.
|
||||
</div>
|
||||
|
||||
<h2 id="per-workspace">Per-Workspace Settings</h2>
|
||||
<p>Each workspace maintains independent layout settings:</p>
|
||||
|
||||
@@ -198,7 +340,7 @@
|
||||
<tr>
|
||||
<td>Layout Mode</td>
|
||||
<td>Per-workspace</td>
|
||||
<td>Tiling, floating, or monocle</td>
|
||||
<td>Tiling, floating, monocle, centered-master, columns, or fibonacci</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Master Ratio</td>
|
||||
@@ -224,7 +366,9 @@
|
||||
<li>Workspace 1: Tiling layout for coding (editor + terminal)</li>
|
||||
<li>Workspace 2: Floating layout for design work</li>
|
||||
<li>Workspace 3: Monocle layout for focused writing</li>
|
||||
<li>Workspace 4: Tiling with master count 2 for comparison</li>
|
||||
<li>Workspace 4: Centered-master for wide monitor development</li>
|
||||
<li>Workspace 5: Columns layout for log monitoring</li>
|
||||
<li>Workspace 6: Fibonacci for hierarchical work</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="shortcuts">Layout Shortcuts</h2>
|
||||
@@ -278,7 +422,9 @@
|
||||
|
||||
<div class="code-block">
|
||||
<pre><code>[layout]
|
||||
default = tiling # Default layout for new workspaces
|
||||
# Default layout for new workspaces
|
||||
# Options: tiling, floating, monocle, centered-master, columns, fibonacci
|
||||
default = tiling
|
||||
master_ratio = 0.55 # Default master area ratio (0.1-0.9)
|
||||
master_count = 1 # Default master window count (1-10)
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Plugin Development - 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">v2.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">Architecture</a>
|
||||
<a href="abstraction-layer.html" class="nav-link">Abstraction Layer</a>
|
||||
<a href="plugin-development.html" class="nav-link active">Plugin Development</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>Plugin Development</h1>
|
||||
<p class="lead">Create custom layouts and widgets for DWN</p>
|
||||
</div>
|
||||
|
||||
<h2>Overview</h2>
|
||||
<p>DWN v2.0 introduces a plugin system for extending functionality. Two types of plugins are supported:</p>
|
||||
|
||||
<ul>
|
||||
<li><strong>Layout Plugins</strong> - Custom window arrangement algorithms</li>
|
||||
<li><strong>Widget Plugins</strong> - Panel components like taskbar, clock, system monitors</li>
|
||||
</ul>
|
||||
|
||||
<h2>Layout Plugins</h2>
|
||||
<p>Layout plugins implement the LayoutPluginInterface vtable. See the abstraction-layer.html documentation for details.</p>
|
||||
|
||||
<h2>Widget Plugins</h2>
|
||||
<p>Widget plugins create panel components with custom rendering and event handling.</p>
|
||||
|
||||
<footer>
|
||||
<p>DWN Window Manager - retoor <retoor@molodetz.nl></p>
|
||||
</footer>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -13,7 +13,7 @@
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>DWN</h1>
|
||||
<span class="version">v1.0.0</span>
|
||||
<span class="version">v2.0.0</span>
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
@@ -47,6 +47,8 @@
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-title">Advanced</div>
|
||||
<a href="architecture.html" class="nav-link">Architecture</a>
|
||||
<a href="abstraction-layer.html" class="nav-link">Abstraction Layer</a>
|
||||
<a href="plugin-development.html" class="nav-link">Plugin Development</a>
|
||||
<a href="building.html" class="nav-link">Building from Source</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
+86
-2
@@ -13,7 +13,7 @@
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>DWN</h1>
|
||||
<span class="version">v1.0.0</span>
|
||||
<span class="version">v2.0.0</span>
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
@@ -47,6 +47,8 @@
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-title">Advanced</div>
|
||||
<a href="architecture.html" class="nav-link">Architecture</a>
|
||||
<a href="abstraction-layer.html" class="nav-link">Abstraction Layer</a>
|
||||
<a href="plugin-development.html" class="nav-link">Plugin Development</a>
|
||||
<a href="building.html" class="nav-link">Building from Source</a>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -64,6 +66,8 @@
|
||||
<ul class="toc-list">
|
||||
<li><a href="#launchers">Application Launchers</a></li>
|
||||
<li><a href="#windows">Window Management</a></li>
|
||||
<li><a href="#keyboard-control">Keyboard Window Control</a></li>
|
||||
<li><a href="#marks">Window Marks</a></li>
|
||||
<li><a href="#workspaces">Workspace Navigation</a></li>
|
||||
<li><a href="#layouts">Layout Control</a></li>
|
||||
<li><a href="#snapping">Window Snapping</a></li>
|
||||
@@ -148,6 +152,86 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h2 id="keyboard-control">Keyboard Window Control</h2>
|
||||
<p>Move and resize floating windows without using the mouse.</p>
|
||||
|
||||
<div class="table-container">
|
||||
<table class="shortcut-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Shortcut</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>Super+Alt+Left</code></td>
|
||||
<td>Move window left by 20 pixels</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Super+Alt+Right</code></td>
|
||||
<td>Move window right by 20 pixels</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Super+Alt+Up</code></td>
|
||||
<td>Move window up by 20 pixels</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Super+Alt+Down</code></td>
|
||||
<td>Move window down by 20 pixels</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Super+Ctrl+Left</code></td>
|
||||
<td>Shrink window width by 20 pixels</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Super+Ctrl+Right</code></td>
|
||||
<td>Grow window width by 20 pixels</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Super+Ctrl+Up</code></td>
|
||||
<td>Shrink window height by 20 pixels</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Super+Ctrl+Down</code></td>
|
||||
<td>Grow window height by 20 pixels</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<strong>Note:</strong> Window must be floating for keyboard move/resize to work. Toggle floating with <code>Super+F9</code>.
|
||||
</div>
|
||||
|
||||
<h2 id="marks">Window Marks</h2>
|
||||
<p>Mark windows with letters (a-z) for instant switching, similar to Vim marks.</p>
|
||||
|
||||
<div class="table-container">
|
||||
<table class="shortcut-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Shortcut</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>Super+M</code> then <code>a-z</code></td>
|
||||
<td>Mark current window with letter</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Super+'</code> then <code>a-z</code></td>
|
||||
<td>Jump to window marked with letter</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<strong>Tip:</strong> Use marks to quickly switch between frequently used windows. For example, mark your editor with <code>e</code> and terminal with <code>t</code>.
|
||||
</div>
|
||||
|
||||
<h2 id="workspaces">Workspace Navigation</h2>
|
||||
<div class="table-container">
|
||||
<table class="shortcut-table">
|
||||
@@ -190,7 +274,7 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>Super+Space</code></td>
|
||||
<td>Cycle layout mode (tiling → floating → monocle)</td>
|
||||
<td>Cycle layout mode (tiling → floating → monocle → centered-master → columns → fibonacci)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Super+H</code></td>
|
||||
|
||||
Reference in New Issue
Block a user