Abstraction Layer
Backend-agnostic architecture for future extensibility
Overview
DWN v2.0 introduces a comprehensive abstraction layer that separates the window manager logic from backend-specific implementations. This architecture enables:
- Backend Portability - Clean migration path from X11 to Wayland
- Type Safety - Strongly typed handles eliminate void* casting
- Memory Safety - Abstract strings and containers prevent buffer overflows
- Plugin Extensibility - Dynamic loading of layouts and widgets
- 100% Compatibility - Existing code continues to work unchanged
Core Types
The abstraction layer provides type-safe replacements for backend-specific types:
| Abstract Type | X11 Equivalent | Description |
|---|---|---|
WmWindowHandle |
Window |
Opaque window reference |
WmClientId |
- | Unique client identifier |
WmWorkspaceId |
int |
Workspace identifier |
WmRect |
- | Rectangle geometry (x, y, w, h) |
WmColor |
unsigned long |
RGBA color value |
Geometry Operations
Inline functions for rectangle operations:
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);
Color Operations
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);
Backend Interface
The backend interface defines a vtable of operations that any backend must implement:
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;
X11 Backend
The X11 backend is the reference implementation, translating abstract operations to X11 calls:
- Event translation (X11 → abstract events)
- Protocol support (ICCCM, EWMH)
- Property management with atom caching
- Error handling with custom handlers
Future Backends
The architecture supports multiple backends:
- X11 - Current, fully implemented
- Wayland - Planned for future
- Headless - For testing and CI
Client Abstraction
The AbstractClient type provides a backend-agnostic representation of a managed window:
/* 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);
Legacy Compatibility
Abstract clients maintain bidirectional synchronization with legacy Client structures:
/* 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);
Container Types
Safe, dynamic container implementations:
WmString (Dynamic Strings)
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);
WmList (Dynamic Arrays)
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);
WmHashMap
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);
Migration Strategy
The abstraction layer uses an incremental migration approach:
- Phase 1: Infrastructure (Complete)
- Core types defined
- Backend interface specified
- X11 backend implemented
- Phase 2: Client Migration (Complete)
- AbstractClient type created
- Bidirectional sync with legacy Client
- Client manager with MRU tracking
- Phase 3: Plugin System (Complete)
- Layout plugin API
- Widget plugin API
- 4 built-in layout plugins
- Phase 4: Future
- Gradual migration of existing code
- Wayland backend implementation
- Legacy code deprecation (long-term)