diff --git a/Makefile b/Makefile index 4247f5e..6c69e97 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CC = gcc CFLAGS = -Wall -Wextra -Wpedantic -Wshadow -O2 -I./include CFLAGS += -fstack-protector-strong -D_FORTIFY_SOURCE=2 -LDFLAGS = -lX11 -lXext -lXinerama -lXrandr -lXft -lfontconfig -ldbus-1 -lcurl -lm -lpthread -lXtst -lXi +LDFLAGS = -lX11 -lXext -lXinerama -lXrandr -lXft -lfontconfig -ldbus-1 -lcurl -lm -lpthread -lXtst -lXi -ldl # Directories SRC_DIR = src @@ -13,9 +13,9 @@ INC_DIR = include BUILD_DIR = build BIN_DIR = bin -# Find all source files automatically -SRCS = $(wildcard $(SRC_DIR)/*.c) -OBJS = $(SRCS:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) +# Find all source files automatically (including subdirectories) +SRCS = $(shell find $(SRC_DIR) -name '*.c' -type f) +OBJS = $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(SRCS)) DEPS = $(OBJS:.o=.d) # Output binary @@ -78,6 +78,11 @@ help: @echo " make deps - Install dependencies (needs sudo)" @echo " make help - Show this help" @echo "" + @echo "API TESTING:" + @echo " make test - Run API integration tests" + @echo " make test-quick - Run quick tests (skip OCR)" + @echo " make test-coverage- Run tests with coverage report" + @echo "" @echo "AFTER INSTALL:" @echo " 1. Log out of your current session" @echo " 2. At login screen, select 'DWN' as your session" @@ -108,6 +113,7 @@ $(TARGET): $(OBJS) | $(BIN_DIR) # Compile each source file $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR) @echo "Compiling $<..." + @mkdir -p $(dir $@) @$(CC) $(CFLAGS) -MMD -MP -c $< -o $@ # Create build directory @@ -271,6 +277,60 @@ deps: exit 1; \ fi +# ============================================================================= +# API INTEGRATION TESTS +# ============================================================================= + +TEST_PORT ?= 18777 +TEST_DISPLAY ?= :99 + +.PHONY: test test-quick test-coverage test-isolated + +test: + @echo "Running API integration tests..." + @echo "Note: DWN must be running with API enabled (port 8777)" + @cd tests && python -m pytest -v + +test-quick: + @echo "Running quick API tests (skipping OCR)..." + @cd tests && python -m pytest -v -x --ignore=test_ocr_commands.py + +test-coverage: + @echo "Running API tests with coverage..." + @cd tests && python -m pytest --cov=. --cov-report=term-missing + +test-isolated: $(TARGET) + @echo "Starting isolated DWN test instance on port $(TEST_PORT)..." + @-kill $$(cat /tmp/dwn_test_dwn.pid 2>/dev/null) 2>/dev/null; true + @-kill $$(cat /tmp/dwn_test_xephyr.pid 2>/dev/null) 2>/dev/null; true + @rm -f /tmp/dwn_test_xephyr.pid /tmp/dwn_test_dwn.pid /tmp/dwn_test.log + @sleep 1 + @Xephyr $(TEST_DISPLAY) -screen 1280x720 2>/dev/null & echo $$! > /tmp/dwn_test_xephyr.pid + @sleep 2 + @DISPLAY=$(TEST_DISPLAY) $(TARGET) -p $(TEST_PORT) > /tmp/dwn_test.log 2>&1 & echo $$! > /tmp/dwn_test_dwn.pid + @sleep 3 + @for i in 1 2 3 4 5; do \ + if curl -s http://localhost:$(TEST_PORT)/api/status >/dev/null 2>&1; then \ + echo "DWN API ready on port $(TEST_PORT)"; \ + break; \ + fi; \ + echo "Waiting for DWN API... ($$i/5)"; \ + sleep 1; \ + done + @if ! curl -s http://localhost:$(TEST_PORT)/api/status >/dev/null 2>&1; then \ + echo "ERROR: DWN API not responding. Check /tmp/dwn_test.log"; \ + cat /tmp/dwn_test.log 2>/dev/null | tail -50; \ + kill $$(cat /tmp/dwn_test_dwn.pid 2>/dev/null) 2>/dev/null || true; \ + kill $$(cat /tmp/dwn_test_xephyr.pid 2>/dev/null) 2>/dev/null || true; \ + exit 1; \ + fi + @DWN_TEST_PORT=$(TEST_PORT) python -m pytest tests/ -v; \ + EXIT_CODE=$$?; \ + kill $$(cat /tmp/dwn_test_dwn.pid 2>/dev/null) 2>/dev/null || true; \ + kill $$(cat /tmp/dwn_test_xephyr.pid 2>/dev/null) 2>/dev/null || true; \ + rm -f /tmp/dwn_test_xephyr.pid /tmp/dwn_test_dwn.pid; \ + exit $$EXIT_CODE + # ============================================================================= # CODE QUALITY (for developers) # ============================================================================= diff --git a/README.md b/README.md index 7ae4fda..1665e94 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ DWN prioritizes a seamless, distraction-free desktop experience: **Built-in Widgets** - Battery: Percentage display, charging indicator, multi-battery support - Volume: Click for slider, scroll to adjust, right-click to mute +- Fade effects: Click "S:X.X" or "I:XX%" to adjust animation speed and glow intensity - Process monitors: Rotating display of top CPU/memory consumers ### Ambient Glow Effects @@ -167,6 +168,37 @@ Programmatic control on port 8777: | `run_command` | Execute shell command | | `screenshot` | Capture screen | | `ocr` | Extract text from image | +| `get_fade_settings` | Get fade effect settings | +| `set_fade_speed` | Set animation speed (0.1-3.0) | +| `set_fade_intensity` | Set glow intensity (0.0-1.0) | + +**Event Subscription** + +Subscribe to real-time events including fade changes: + +```bash +# Subscribe to fade events +python3 examples/dwn_api_client.py subscribe fade_speed_changed fade_intensity_changed + +# Listen for all events +python3 examples/dwn_api_client.py listen +``` + +**Fade Control Example** + +```bash +# Get current fade settings +python3 examples/dwn_api_client.py fade-settings + +# Set fade speed (faster animation) +python3 examples/dwn_api_client.py fade-speed 1.5 + +# Set fade intensity (dimmer glow) +python3 examples/dwn_api_client.py fade-intensity 0.5 + +# Run interactive demo +python3 examples/fade_control_demo.py +``` ### Automation @@ -436,6 +468,61 @@ window_timeout = 5000 # 1000-30000ms | api.c | WebSocket server | | util.c | Logging, memory, string utilities, glow effects | +### New Abstraction Layer (v2.0) + +DWN now includes a modern abstraction layer for future extensibility: + +**Core Abstractions** (`include/core/`) +- `wm_types.h` - Abstract handles, geometry, colors, events +- `wm_string.h/c` - Safe dynamic strings with automatic memory management +- `wm_list.h/c` - Dynamic array container with sorting and iteration +- `wm_hashmap.h/c` - Hash table with automatic resizing +- `wm_client.h/c` - Abstract client type with bidirectional legacy sync + +**Backend Interface** (`include/backends/`) +- `backend_interface.h` - Backend-agnostic vtable (80+ operations) +- `x11/x11_backend.h/c` - X11 implementation with event translation +- Designed for future Wayland and headless backends + +**Plugin System** (`include/plugins/`) +- `layout_plugin.h` - Layout plugin API with state management +- `widget_plugin.h` - Widget plugin API for panel components +- Built-in layouts: tiling, floating, monocle, grid +- Support for dynamic plugin loading + +The abstraction layer maintains **100% API compatibility** with existing code while enabling: +- Backend portability (X11 → Wayland migration path) +- Dynamic plugin loading for layouts and widgets +- Type-safe handles replacing void* casts +- Memory-safe string and container operations + +### Design Patterns + +**Encapsulation** +- Opaque pointer types hide internal structures +- Header exposes only public API +- Implementation details remain private + +**Error Handling** +- Status code return values +- Output parameters for results +- Enum-based error codes + +**Resource Management** +- Goto cleanup pattern for multi-resource functions +- Every allocation has corresponding free +- XGrabServer/XUngrabServer for atomic X11 operations + +**Event Architecture** +- Select-based multiplexed I/O +- 60fps animation loop with 16ms timeout +- Async request queues for AI/screenshot/OCR + +**Naming Conventions** +- Module prefix for functions: `client_focus()`, `workspace_switch()` +- Snake_case for functions and variables +- CamelCase for types and structs + ### Design Patterns **Encapsulation** @@ -518,13 +605,20 @@ ws.close() ``` dwn/ -├── src/ # Implementation files -├── include/ # Header files -├── config/ # Configuration templates -├── scripts/ # Utility scripts -├── examples/ # API usage examples -├── site/ # Documentation website -└── build/ # Build artifacts +├── src/ # Implementation files +│ ├── core/ # Abstract core types (string, list, hashmap, client) +│ ├── backends/x11/ # X11 backend implementation +│ └── plugins/ # Plugin system (layout, widget managers) +│ └── layouts/ # Built-in layout plugins +├── include/ # Header files +│ ├── core/ # Core abstraction headers +│ ├── backends/ # Backend interface headers +│ └── plugins/ # Plugin API headers +├── manual/ # Documentation website (HTML) +├── config/ # Configuration templates +├── scripts/ # Utility scripts +├── examples/ # API usage examples +└── build/ # Build artifacts ``` ## License diff --git a/bin/dwn b/bin/dwn index 7f3c6b1..378bfdf 100755 Binary files a/bin/dwn and b/bin/dwn differ diff --git a/build/ai.o b/build/ai.o index b3a7f04..f148591 100644 Binary files a/build/ai.o and b/build/ai.o differ diff --git a/build/applauncher.o b/build/applauncher.o index a8ebd86..4ec792a 100644 Binary files a/build/applauncher.o and b/build/applauncher.o differ diff --git a/build/atoms.o b/build/atoms.o index 6686d7d..fb32c32 100644 Binary files a/build/atoms.o and b/build/atoms.o differ diff --git a/build/autostart.o b/build/autostart.o index 46880e1..ff49f41 100644 Binary files a/build/autostart.o and b/build/autostart.o differ diff --git a/build/cJSON.o b/build/cJSON.o index 9c189f7..267611e 100644 Binary files a/build/cJSON.o and b/build/cJSON.o differ diff --git a/build/client.d b/build/client.d index c83ca48..67a15b4 100644 --- a/build/client.d +++ b/build/client.d @@ -19,7 +19,7 @@ build/client.o: src/client.c include/client.h include/dwn.h \ /usr/include/dbus-1.0/dbus/dbus-signature.h \ /usr/include/dbus-1.0/dbus/dbus-syntax.h \ /usr/include/dbus-1.0/dbus/dbus-threads.h include/layout.h \ - include/panel.h include/api.h + include/panel.h include/api.h include/rules.h include/marks.h include/client.h: include/dwn.h: include/atoms.h: @@ -49,3 +49,5 @@ include/notifications.h: include/layout.h: include/panel.h: include/api.h: +include/rules.h: +include/marks.h: diff --git a/build/client.o b/build/client.o index c7f0a79..cb40d94 100644 Binary files a/build/client.o and b/build/client.o differ diff --git a/build/config.o b/build/config.o index 83397e7..69be0b0 100644 Binary files a/build/config.o and b/build/config.o differ diff --git a/build/decorations.o b/build/decorations.o index 64427d8..963fcd0 100644 Binary files a/build/decorations.o and b/build/decorations.o differ diff --git a/build/demo.o b/build/demo.o index 81e0dce..8ddffa5 100644 Binary files a/build/demo.o and b/build/demo.o differ diff --git a/build/keys.d b/build/keys.d index 1fb211a..235a29a 100644 --- a/build/keys.d +++ b/build/keys.d @@ -19,7 +19,7 @@ build/keys.o: src/keys.c include/keys.h include/dwn.h include/client.h \ /usr/include/dbus-1.0/dbus/dbus-syntax.h \ /usr/include/dbus-1.0/dbus/dbus-threads.h include/news.h \ include/applauncher.h include/decorations.h include/demo.h \ - include/layout.h include/api.h + include/layout.h include/api.h include/marks.h include/keys.h: include/dwn.h: include/client.h: @@ -52,3 +52,4 @@ include/decorations.h: include/demo.h: include/layout.h: include/api.h: +include/marks.h: diff --git a/build/keys.o b/build/keys.o index 3048b88..8e1227f 100644 Binary files a/build/keys.o and b/build/keys.o differ diff --git a/build/layout.o b/build/layout.o index 7165d75..c3727fd 100644 Binary files a/build/layout.o and b/build/layout.o differ diff --git a/build/main.d b/build/main.d index aa82306..26e254a 100644 --- a/build/main.d +++ b/build/main.d @@ -19,9 +19,12 @@ build/main.o: src/main.c include/dwn.h include/config.h include/dwn.h \ /usr/include/dbus-1.0/dbus/dbus-signature.h \ /usr/include/dbus-1.0/dbus/dbus-syntax.h \ /usr/include/dbus-1.0/dbus/dbus-threads.h include/systray.h \ - include/news.h include/applauncher.h include/ai.h include/autostart.h \ - include/services.h include/api.h include/demo.h include/screenshot.h \ - include/ocr.h include/util.h + include/slider.h include/news.h include/applauncher.h include/ai.h \ + include/autostart.h include/services.h include/api.h include/demo.h \ + include/screenshot.h include/ocr.h include/util.h include/slider.h \ + include/rules.h include/marks.h include/core/wm_client.h \ + include/core/wm_types.h include/core/wm_string.h include/core/wm_types.h \ + include/plugins/layout_plugin.h include/plugins/builtin_layouts.h include/dwn.h: include/config.h: include/dwn.h: @@ -52,6 +55,7 @@ include/notifications.h: /usr/include/dbus-1.0/dbus/dbus-syntax.h: /usr/include/dbus-1.0/dbus/dbus-threads.h: include/systray.h: +include/slider.h: include/news.h: include/applauncher.h: include/ai.h: @@ -62,3 +66,12 @@ include/demo.h: include/screenshot.h: include/ocr.h: include/util.h: +include/slider.h: +include/rules.h: +include/marks.h: +include/core/wm_client.h: +include/core/wm_types.h: +include/core/wm_string.h: +include/core/wm_types.h: +include/plugins/layout_plugin.h: +include/plugins/builtin_layouts.h: diff --git a/build/main.o b/build/main.o index 62466d3..f63fdd6 100644 Binary files a/build/main.o and b/build/main.o differ diff --git a/build/news.o b/build/news.o index 67cf19d..0f59896 100644 Binary files a/build/news.o and b/build/news.o differ diff --git a/build/notifications.o b/build/notifications.o index 4e64915..a66a775 100644 Binary files a/build/notifications.o and b/build/notifications.o differ diff --git a/build/panel.d b/build/panel.d index e028e4b..b65f484 100644 --- a/build/panel.d +++ b/build/panel.d @@ -1,6 +1,7 @@ build/panel.o: src/panel.c include/panel.h include/dwn.h \ include/workspace.h include/layout.h include/client.h include/config.h \ - include/util.h include/atoms.h include/systray.h include/news.h + include/util.h include/atoms.h include/systray.h include/slider.h \ + include/news.h include/panel.h: include/dwn.h: include/workspace.h: @@ -10,4 +11,5 @@ include/config.h: include/util.h: include/atoms.h: include/systray.h: +include/slider.h: include/news.h: diff --git a/build/panel.o b/build/panel.o index 27edac7..f34c901 100644 Binary files a/build/panel.o and b/build/panel.o differ diff --git a/build/systray.d b/build/systray.d index 00de802..1ebbf3a 100644 --- a/build/systray.d +++ b/build/systray.d @@ -1,6 +1,6 @@ build/systray.o: src/systray.c include/systray.h include/dwn.h \ - include/panel.h include/config.h include/util.h include/notifications.h \ - /usr/include/dbus-1.0/dbus/dbus.h \ + include/slider.h include/panel.h include/config.h include/util.h \ + include/notifications.h /usr/include/dbus-1.0/dbus/dbus.h \ /usr/lib/x86_64-linux-gnu/dbus-1.0/include/dbus/dbus-arch-deps.h \ /usr/include/dbus-1.0/dbus/dbus-macros.h \ /usr/include/dbus-1.0/dbus/dbus-address.h \ @@ -17,9 +17,10 @@ build/systray.o: src/systray.c include/systray.h include/dwn.h \ /usr/include/dbus-1.0/dbus/dbus-server.h \ /usr/include/dbus-1.0/dbus/dbus-signature.h \ /usr/include/dbus-1.0/dbus/dbus-syntax.h \ - /usr/include/dbus-1.0/dbus/dbus-threads.h include/atoms.h + /usr/include/dbus-1.0/dbus/dbus-threads.h include/atoms.h include/api.h include/systray.h: include/dwn.h: +include/slider.h: include/panel.h: include/config.h: include/util.h: @@ -43,3 +44,4 @@ include/notifications.h: /usr/include/dbus-1.0/dbus/dbus-syntax.h: /usr/include/dbus-1.0/dbus/dbus-threads.h: include/atoms.h: +include/api.h: diff --git a/build/systray.o b/build/systray.o index 9e1e645..823d325 100644 Binary files a/build/systray.o and b/build/systray.o differ diff --git a/build/util.o b/build/util.o index 040b5ea..24b4a8c 100644 Binary files a/build/util.o and b/build/util.o differ diff --git a/build/workspace.o b/build/workspace.o index ca33404..262d8e3 100644 Binary files a/build/workspace.o and b/build/workspace.o differ diff --git a/include/ai.h b/include/ai.h index fe9ff7e..999bed6 100644 --- a/include/ai.h +++ b/include/ai.h @@ -10,6 +10,11 @@ #include "dwn.h" #include +/* Forward declarations for libcurl types */ +struct curl_slist; +struct Curl_easy; +typedef struct Curl_easy DWN_CURL; + typedef enum { AI_STATE_IDLE, AI_STATE_PENDING, @@ -24,6 +29,8 @@ typedef struct AIRequest { void (*callback)(struct AIRequest *req); void *user_data; struct AIRequest *next; + struct curl_slist *headers; /* Stored for proper cleanup */ + struct Curl_easy *curl_handle; /* Stored for cancellation */ } AIRequest; typedef struct { @@ -74,6 +81,8 @@ typedef struct ExaRequest { void (*callback)(struct ExaRequest *req); void *user_data; struct ExaRequest *next; + struct curl_slist *headers; /* Stored for proper cleanup */ + struct Curl_easy *curl_handle; /* Stored for cancellation */ } ExaRequest; bool exa_is_available(void); diff --git a/include/api.h b/include/api.h index 408ccd1..863fb60 100644 --- a/include/api.h +++ b/include/api.h @@ -55,6 +55,23 @@ typedef enum { EVENT_NOTIFICATION_SHOWN, EVENT_NOTIFICATION_CLOSED, + EVENT_FADE_SPEED_CHANGED, + EVENT_FADE_INTENSITY_CHANGED, + + EVENT_WINDOW_SNAPPED, + EVENT_AUDIO_VOLUME_CHANGED, + EVENT_AUDIO_MUTE_TOGGLED, + EVENT_PANEL_VISIBILITY_CHANGED, + EVENT_CONFIG_RELOADED, + EVENT_AI_RESPONSE_RECEIVED, + EVENT_EXA_SEARCH_COMPLETED, + EVENT_NEWS_ARTICLE_CHANGED, + EVENT_DEMO_STARTED, + EVENT_DEMO_STOPPED, + EVENT_DEMO_PHASE_CHANGED, + EVENT_TUTORIAL_STARTED, + EVENT_TUTORIAL_STOPPED, + EVENT_COUNT } ApiEventType; @@ -104,4 +121,21 @@ void api_emit_show_desktop_toggled(bool shown); void api_emit_notification_shown(unsigned int id, const char *summary, const char *body); void api_emit_notification_closed(unsigned int id); +void api_emit_fade_speed_changed(float old_speed, float new_speed); +void api_emit_fade_intensity_changed(float old_intensity, float new_intensity); + +void api_emit_window_snapped(Window window, int horizontal, int vertical); +void api_emit_audio_volume_changed(int old_volume, int new_volume); +void api_emit_audio_mute_toggled(bool muted); +void api_emit_panel_visibility_changed(const char *panel, bool visible); +void api_emit_config_reloaded(void); +void api_emit_ai_response_received(const char *prompt, const char *response, bool success); +void api_emit_exa_search_completed(const char *query, int result_count, bool success); +void api_emit_news_article_changed(int old_index, int new_index, const char *title); +void api_emit_demo_started(void); +void api_emit_demo_stopped(void); +void api_emit_demo_phase_changed(int phase, const char *phase_name); +void api_emit_tutorial_started(void); +void api_emit_tutorial_stopped(void); + #endif diff --git a/include/backends/backend_interface.h b/include/backends/backend_interface.h new file mode 100644 index 0000000..9beb951 --- /dev/null +++ b/include/backends/backend_interface.h @@ -0,0 +1,311 @@ +/* + * DWN - Desktop Window Manager + * Backend Abstraction Interface + */ + +#ifndef BACKEND_INTERFACE_H +#define BACKEND_INTERFACE_H + +#include "core/wm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Backend Capabilities + *============================================================================*/ + +typedef enum { + WM_BACKEND_CAP_WINDOWS = (1 << 0), + WM_BACKEND_CAP_COMPOSITING = (1 << 1), + WM_BACKEND_CAP_TRANSPARENCY = (1 << 2), + WM_BACKEND_CAP_ANIMATIONS = (1 << 3), + WM_BACKEND_CAP_MULTI_MONITOR = (1 << 4), + WM_BACKEND_CAP_INPUT_EVENTS = (1 << 5), + WM_BACKEND_CAP_CLIPBOARD = (1 << 6), + WM_BACKEND_CAP_DRAG_DROP = (1 << 7), + WM_BACKEND_CAP_TOUCH = (1 << 8), + WM_BACKEND_CAP_GESTURES = (1 << 9) +} WmBackendCapabilities; + +/*============================================================================== + * Backend Information + *============================================================================*/ + +typedef struct { + const char *name; + const char *version; + const char *description; + uint32_t capabilities; + bool supports_multiple_instances; + bool requires_compositor; +} WmBackendInfo; + +/*============================================================================== + * Backend Event Types + *============================================================================*/ + +typedef enum { + WM_BACKEND_EVENT_NONE, + WM_BACKEND_EVENT_EXPOSE, + WM_BACKEND_EVENT_CONFIGURE, + WM_BACKEND_EVENT_MAP, + WM_BACKEND_EVENT_UNMAP, + WM_BACKEND_EVENT_DESTROY, + WM_BACKEND_EVENT_FOCUS_IN, + WM_BACKEND_EVENT_FOCUS_OUT, + WM_BACKEND_EVENT_KEY_PRESS, + WM_BACKEND_EVENT_KEY_RELEASE, + WM_BACKEND_EVENT_BUTTON_PRESS, + WM_BACKEND_EVENT_BUTTON_RELEASE, + WM_BACKEND_EVENT_MOTION, + WM_BACKEND_EVENT_ENTER, + WM_BACKEND_EVENT_LEAVE, + WM_BACKEND_EVENT_PROPERTY, + WM_BACKEND_EVENT_CLIENT_MESSAGE, + WM_BACKEND_EVENT_SELECTION, +} WmBackendEventType; + +typedef struct { + WmBackendEventType type; + WmWindowHandle window; + WmTime timestamp; + union { + struct { int x, y, width, height; } configure; + struct { int x, y; } point; + struct { unsigned int keycode; unsigned int state; } key; + struct { unsigned int button; int x, y; unsigned int state; } button; + struct { const char *name; const void *data; size_t size; } property; + } data; +} WmBackendEvent; + +/*============================================================================== + * Backend Interface Definition + *============================================================================*/ + +typedef struct BackendInterface { + /* Identification */ + const char *name; + WmBackendInfo (*get_info)(void); + + /* Lifecycle */ + bool (*init)(void *config); + void (*shutdown)(void); + bool (*is_initialized)(void); + + /* Connection */ + bool (*connect)(void); + void (*disconnect)(void); + bool (*is_connected)(void); + int (*get_file_descriptor)(void); + void (*flush)(void); + void (*sync)(void); + + /* Screen/Display */ + void (*get_screen_dimensions)(int *width, int *height); + int (*get_screen_count)(void); + void (*get_screen_geometry)(int screen, WmRect *geometry); + + /* Monitor Management */ + int (*get_monitor_count)(void); + void (*get_monitor_geometry)(int monitor, WmRect *geometry); + bool (*get_monitor_primary)(int monitor); + const char* (*get_monitor_name)(int monitor); + + /* Work Area */ + void (*get_work_area)(int monitor, WmRect *area); + void (*set_work_area)(int monitor, const WmRect *area); + + /* Window Management - Lifecycle */ + WmWindowHandle (*window_create)(const WmRect *geometry, uint32_t flags); + void (*window_destroy)(WmWindowHandle window); + WmWindowHandle (*window_create_frame)(WmWindowHandle parent, const WmRect *geometry); + + /* Window Management - Geometry */ + void (*window_get_geometry)(WmWindowHandle window, WmRect *geometry); + void (*window_set_geometry)(WmWindowHandle window, const WmRect *geometry); + void (*window_move)(WmWindowHandle window, int x, int y); + void (*window_resize)(WmWindowHandle window, int width, int height); + void (*window_move_resize)(WmWindowHandle window, const WmRect *geometry); + + /* Window Management - Visibility */ + void (*window_show)(WmWindowHandle window); + void (*window_hide)(WmWindowHandle window); + bool (*window_is_visible)(WmWindowHandle window); + void (*window_map)(WmWindowHandle window); + void (*window_unmap)(WmWindowHandle window); + bool (*window_is_mapped)(WmWindowHandle window); + + /* Window Management - Stacking */ + void (*window_raise)(WmWindowHandle window); + void (*window_lower)(WmWindowHandle window); + void (*window_raise_above)(WmWindowHandle window, WmWindowHandle above); + void (*window_lower_below)(WmWindowHandle window, WmWindowHandle below); + void (*window_set_stack_position)(WmWindowHandle window, int position); + int (*window_get_stack_position)(WmWindowHandle window); + + /* Window Management - Reparenting */ + void (*window_reparent)(WmWindowHandle window, WmWindowHandle parent, int x, int y); + WmWindowHandle (*window_get_parent)(WmWindowHandle window); + + /* Window Management - Focus */ + void (*window_focus)(WmWindowHandle window); + void (*window_unfocus)(WmWindowHandle window); + bool (*window_is_focused)(WmWindowHandle window); + WmWindowHandle (*window_get_focused)(void); + + /* Window Management - Decoration */ + void (*window_set_decorated)(WmWindowHandle window, bool decorated); + bool (*window_is_decorated)(WmWindowHandle window); + void (*window_set_border_width)(WmWindowHandle window, int width); + int (*window_get_border_width)(WmWindowHandle window); + void (*window_set_border_color)(WmWindowHandle window, WmColor color); + + /* Window Management - Properties */ + void (*window_set_title)(WmWindowHandle window, const char *title); + char* (*window_get_title)(WmWindowHandle window); + void (*window_set_class)(WmWindowHandle window, const char *class, const char *instance); + void (*window_get_class)(WmWindowHandle window, char **class, char **instance); + void (*window_set_icon_name)(WmWindowHandle window, const char *name); + + /* Window Management - Protocols */ + bool (*window_supports_protocol)(WmWindowHandle window, const char *protocol); + void (*window_send_protocol)(WmWindowHandle window, const char *protocol, WmTime timestamp); + void (*window_close)(WmWindowHandle window); + void (*window_kill)(WmWindowHandle window); + + /* Window Management - State */ + void (*window_set_fullscreen)(WmWindowHandle window, bool fullscreen); + bool (*window_is_fullscreen)(WmWindowHandle window); + void (*window_set_maximized)(WmWindowHandle window, bool maximized); + bool (*window_is_maximized)(WmWindowHandle window); + void (*window_set_minimized)(WmWindowHandle window, bool minimized); + bool (*window_is_minimized)(WmWindowHandle window); + void (*window_set_modal)(WmWindowHandle window, bool modal); + void (*window_set_sticky)(WmWindowHandle window, bool sticky); + void (*window_set_shaded)(WmWindowHandle window, bool shaded); + void (*window_set_skip_taskbar)(WmWindowHandle window, bool skip); + void (*window_set_skip_pager)(WmWindowHandle window, bool skip); + void (*window_set_urgent)(WmWindowHandle window, bool urgent); + bool (*window_is_urgent)(WmWindowHandle window); + + /* Window Management - Type */ + void (*window_set_type)(WmWindowHandle window, WmWindowType type); + WmWindowType (*window_get_type)(WmWindowHandle window); + + /* Window Management - Selection */ + void (*window_set_selection_owner)(WmWindowHandle window, const char *selection, WmTime time); + WmWindowHandle (*window_get_selection_owner)(const char *selection); + void (*window_convert_selection)(WmWindowHandle requestor, const char *selection, + const char *target, WmTime time); + + /* Window Management - Client List */ + WmContainer* (*window_get_stacking_list)(void); + WmContainer* (*window_get_client_list)(void); + + /* Input - Events */ + bool (*poll_event)(WmBackendEvent *event); + void (*wait_event)(WmBackendEvent *event); + bool (*check_mask_event)(uint32_t mask, WmBackendEvent *event); + void (*put_back_event)(const WmBackendEvent *event); + + /* Input - Key Grabbing */ + void (*grab_key)(int keycode, uint32_t modifiers, WmWindowHandle window, + bool owner_events, uint32_t pointer_mode, uint32_t keyboard_mode); + void (*ungrab_key)(int keycode, uint32_t modifiers, WmWindowHandle window); + void (*grab_keyboard)(WmWindowHandle window, bool owner_events, + uint32_t pointer_mode, uint32_t keyboard_mode, WmTime time); + void (*ungrab_keyboard)(WmTime time); + + /* Input - Button Grabbing */ + void (*grab_button)(int button, uint32_t modifiers, WmWindowHandle window, + bool owner_events, uint32_t event_mask, + uint32_t pointer_mode, uint32_t keyboard_mode, + WmWindowHandle confine_to, uint32_t cursor); + void (*ungrab_button)(int button, uint32_t modifiers, WmWindowHandle window); + void (*grab_pointer)(WmWindowHandle window, bool owner_events, uint32_t event_mask, + uint32_t pointer_mode, uint32_t keyboard_mode, + WmWindowHandle confine_to, uint32_t cursor, WmTime time); + void (*ungrab_pointer)(WmTime time); + + /* Input - Pointer */ + void (*query_pointer)(WmWindowHandle window, int *root_x, int *root_y, + int *win_x, int *win_y, uint32_t *mask); + void (*warp_pointer)(WmWindowHandle dest_w, int dest_x, int dest_y); + void (*set_cursor)(WmWindowHandle window, uint32_t cursor); + + /* Rendering - Basic */ + void (*fill_rectangle)(WmWindowHandle window, const WmRect *rect, WmColor color); + void (*draw_rectangle)(WmWindowHandle window, const WmRect *rect, WmColor color, int line_width); + void (*draw_line)(WmWindowHandle window, int x1, int y1, int x2, int y2, + WmColor color, int line_width); + void (*clear_window)(WmWindowHandle window); + void (*copy_area)(WmWindowHandle src, WmWindowHandle dst, + int src_x, int src_y, int width, int height, + int dst_x, int dst_y); + + /* Rendering - Text (if supported) */ + void* (*font_load)(const char *name, int size); + void (*font_destroy)(void *font); + int (*font_text_width)(void *font, const char *text, int len); + void (*draw_text)(WmWindowHandle window, void *font, int x, int y, + const char *text, int len, WmColor color); + + /* Rendering - Images (if supported) */ + void* (*image_load)(const uint8_t *data, size_t size); + void (*image_destroy)(void *image); + void (*image_get_size)(void *image, int *width, int *height); + void (*draw_image)(WmWindowHandle window, void *image, int x, int y, + int width, int height); + + /* Rendering - Sync */ + void (*begin_paint)(WmWindowHandle window); + void (*end_paint)(WmWindowHandle window); + + /* Atoms/Properties */ + uint32_t (*atom_get)(const char *name); + const char* (*atom_get_name)(uint32_t atom); + void (*property_set)(WmWindowHandle window, uint32_t property, uint32_t type, + int format, const void *data, int num_items); + int (*property_get)(WmWindowHandle window, uint32_t property, uint32_t type, + void **data, int *num_items); + void (*property_delete)(WmWindowHandle window, uint32_t property); + + /* Session Management */ + void (*set_selection_owner)(WmWindowHandle owner, const char *selection); + void (*send_client_message)(WmWindowHandle window, const char *message_type, + const void *data, int format); + + /* Error Handling */ + int (*get_last_error)(void); + void (*set_error_handler)(int (*handler)(void *display, void *event)); + void (*set_io_error_handler)(int (*handler)(void *display)); + +} BackendInterface; + +/*============================================================================== + * Backend Registration + *============================================================================*/ + +typedef const BackendInterface* (*BackendEntryFunc)(void); + +void wm_backend_register(const char *name, BackendEntryFunc entry); +const BackendInterface* wm_backend_get(const char *name); +WmContainer* wm_backend_get_available(void); + +/*============================================================================== + * Backend Helpers + *============================================================================*/ + +static inline bool wm_backend_has_capability(const BackendInterface *backend, + WmBackendCapabilities cap) { + WmBackendInfo info = backend->get_info(); + return (info.capabilities & cap) != 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* BACKEND_INTERFACE_H */ diff --git a/include/backends/x11/x11_backend.h b/include/backends/x11/x11_backend.h new file mode 100644 index 0000000..c47c6a9 --- /dev/null +++ b/include/backends/x11/x11_backend.h @@ -0,0 +1,35 @@ +/* + * DWN - Desktop Window Manager + * X11 Backend Header + */ + +#ifndef X11_BACKEND_H +#define X11_BACKEND_H + +#include "backends/backend_interface.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * X11 Backend Access + *============================================================================*/ + +const BackendInterface* x11_backend_get_interface(void); +Display* x11_backend_get_display(void); +Window x11_backend_get_root(void); +int x11_backend_get_screen(void); + +static inline bool x11_backend_is_available(void) { + const BackendInterface *iface = x11_backend_get_interface(); + return iface && iface->init(NULL); +} + +#ifdef __cplusplus +} +#endif + +#endif /* X11_BACKEND_H */ diff --git a/include/config.h b/include/config.h index 17a6f91..94e8f68 100644 --- a/include/config.h +++ b/include/config.h @@ -68,6 +68,10 @@ struct Config { int demo_ai_timeout_ms; int demo_window_timeout_ms; + /* Fade effects */ + float fade_speed; /* Animation speed multiplier (0.1 - 3.0) */ + float fade_intensity; /* Glow intensity (0.0 - 1.0) */ + char color_panel_bg[16]; char color_panel_fg[16]; char color_workspace_active[16]; @@ -88,6 +92,7 @@ void config_destroy(Config *cfg); bool config_load(Config *cfg, const char *path); bool config_reload(Config *cfg); void config_set_defaults(Config *cfg); +void config_validate(Config *cfg); const char *config_get_terminal(void); const char *config_get_launcher(void); @@ -96,6 +101,10 @@ int config_get_title_height(void); int config_get_panel_height(void); int config_get_gap(void); const ColorScheme *config_get_colors(void); +float config_get_fade_speed(void); +float config_get_fade_intensity(void); +void config_set_fade_speed(float speed); +void config_set_fade_intensity(float intensity); typedef void (*ConfigCallback)(const char *section, const char *key, const char *value, void *user_data); diff --git a/include/core/wm_client.h b/include/core/wm_client.h new file mode 100644 index 0000000..989c7ac --- /dev/null +++ b/include/core/wm_client.h @@ -0,0 +1,523 @@ +/* + * DWN - Desktop Window Manager + * Abstract Client Interface + */ + +#ifndef WM_CLIENT_H +#define WM_CLIENT_H + +#include "core/wm_types.h" +#include "core/wm_string.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +typedef struct Client Client; /* Legacy client structure */ + +/*============================================================================== + * Abstract Client Type + *============================================================================*/ + +typedef struct AbstractClient AbstractClient; + +/*============================================================================== + * Client State Flags + *============================================================================*/ + +typedef enum { + WM_CLIENT_STATE_NORMAL = 0, + WM_CLIENT_STATE_FLOATING = (1 << 0), + WM_CLIENT_STATE_FULLSCREEN = (1 << 1), + WM_CLIENT_STATE_MAXIMIZED = (1 << 2), + WM_CLIENT_STATE_MINIMIZED = (1 << 3), + WM_CLIENT_STATE_URGENT = (1 << 4), + WM_CLIENT_STATE_STICKY = (1 << 5), + WM_CLIENT_STATE_HIDDEN = (1 << 6), + WM_CLIENT_STATE_FOCUS = (1 << 7), + WM_CLIENT_STATE_MAPPED = (1 << 8), + WM_CLIENT_STATE_MANAGED = (1 << 9), + WM_CLIENT_STATE_DESTROYING = (1 << 10) +} WmClientState; + +/*============================================================================== + * Client Window Type + *============================================================================*/ + +typedef enum { + WM_CLIENT_TYPE_UNKNOWN = 0, + WM_CLIENT_TYPE_NORMAL, + WM_CLIENT_TYPE_DIALOG, + WM_CLIENT_TYPE_DOCK, + WM_CLIENT_TYPE_DESKTOP, + WM_CLIENT_TYPE_TOOLBAR, + WM_CLIENT_TYPE_MENU, + WM_CLIENT_TYPE_UTILITY, + WM_CLIENT_TYPE_SPLASH, + WM_CLIENT_TYPE_NOTIFICATION +} WmClientType; + +/*============================================================================== + * Client Lifecycle + *============================================================================*/ + +/** + * Create an abstract client from a native window handle. + * This takes ownership of the native window. + */ +AbstractClient* wm_client_create(WmWindowHandle window, WmClientType type); + +/** + * Destroy a client and release all associated resources. + */ +void wm_client_destroy(AbstractClient *client); + +/** + * Check if a client is valid (not NULL and not being destroyed). + */ +bool wm_client_is_valid(const AbstractClient *client); + +/*============================================================================== + * Native Access (for compatibility during migration) + *============================================================================*/ + +/** + * Get the native window handle. + * Note: This should be avoided in backend-agnostic code. + */ +WmWindowHandle wm_client_get_window(const AbstractClient *client); + +/** + * Get the native frame window handle (if reparented). + */ +WmWindowHandle wm_client_get_frame(const AbstractClient *client); + +/** + * Get the legacy Client structure. + * Note: This is for gradual migration only. + */ +Client* wm_client_get_legacy(const AbstractClient *client); + +/** + * Create an abstract client wrapper around an existing legacy Client. + * Note: The abstract client does NOT own the legacy client. + */ +AbstractClient* wm_client_from_legacy(Client *client); + +/*============================================================================== + * Client Identification + *============================================================================*/ + +/** + * Get the unique client ID. + */ +WmClientId wm_client_get_id(const AbstractClient *client); + +/** + * Get the client window type. + */ +WmClientType wm_client_get_type(const AbstractClient *client); + +/** + * Set the client window type. + */ +void wm_client_set_type(AbstractClient *client, WmClientType type); + +/*============================================================================== + * Client State + *============================================================================*/ + +/** + * Get the current state flags. + */ +WmClientState wm_client_get_state(const AbstractClient *client); + +/** + * Set state flags. + */ +void wm_client_set_state(AbstractClient *client, WmClientState state); + +/** + * Add state flags. + */ +void wm_client_add_state(AbstractClient *client, WmClientState state); + +/** + * Remove state flags. + */ +void wm_client_remove_state(AbstractClient *client, WmClientState state); + +/** + * Toggle state flags. + */ +void wm_client_toggle_state(AbstractClient *client, WmClientState state); + +/** + * Check if a specific state is set. + */ +bool wm_client_has_state(const AbstractClient *client, WmClientState state); + +/* Convenience state checks */ +static inline bool wm_client_is_floating(const AbstractClient *c) { + return c && wm_client_has_state(c, WM_CLIENT_STATE_FLOATING); +} +static inline bool wm_client_is_fullscreen(const AbstractClient *c) { + return c && wm_client_has_state(c, WM_CLIENT_STATE_FULLSCREEN); +} +static inline bool wm_client_is_maximized(const AbstractClient *c) { + return c && wm_client_has_state(c, WM_CLIENT_STATE_MAXIMIZED); +} +static inline bool wm_client_is_minimized(const AbstractClient *c) { + return c && wm_client_has_state(c, WM_CLIENT_STATE_MINIMIZED); +} +static inline bool wm_client_is_urgent(const AbstractClient *c) { + return c && wm_client_has_state(c, WM_CLIENT_STATE_URGENT); +} +static inline bool wm_client_is_sticky(const AbstractClient *c) { + return c && wm_client_has_state(c, WM_CLIENT_STATE_STICKY); +} +static inline bool wm_client_is_focused(const AbstractClient *c) { + return c && wm_client_has_state(c, WM_CLIENT_STATE_FOCUS); +} +static inline bool wm_client_is_mapped(const AbstractClient *c) { + return c && wm_client_has_state(c, WM_CLIENT_STATE_MAPPED); +} + +/*============================================================================== + * Client Geometry + *============================================================================*/ + +/** + * Get the client geometry (position and size). + */ +WmRect wm_client_get_geometry(const AbstractClient *client); + +/** + * Set the client geometry. + */ +void wm_client_set_geometry(AbstractClient *client, const WmRect *geometry); + +/** + * Get the client position. + */ +WmPoint wm_client_get_position(const AbstractClient *client); + +/** + * Set the client position. + */ +void wm_client_set_position(AbstractClient *client, int x, int y); + +/** + * Get the client size. + */ +WmSize wm_client_get_size(const AbstractClient *client); + +/** + * Set the client size. + */ +void wm_client_set_size(AbstractClient *client, int width, int height); + +/** + * Get the border width. + */ +int wm_client_get_border_width(const AbstractClient *client); + +/** + * Set the border width. + */ +void wm_client_set_border_width(AbstractClient *client, int width); + +/** + * Store previous geometry (for restore after maximize/fullscreen). + */ +void wm_client_save_geometry(AbstractClient *client); + +/** + * Restore previous geometry. + */ +void wm_client_restore_geometry(AbstractClient *client); + +/*============================================================================== + * Client Workspace + *============================================================================*/ + +/** + * Get the client's workspace ID. + */ +WmWorkspaceId wm_client_get_workspace(const AbstractClient *client); + +/** + * Set the client's workspace ID. + */ +void wm_client_set_workspace(AbstractClient *client, WmWorkspaceId workspace); + +/** + * Check if the client is on a specific workspace. + */ +bool wm_client_is_on_workspace(const AbstractClient *client, WmWorkspaceId workspace); + +/** + * Check if the client is visible on the current workspace. + */ +bool wm_client_is_visible_on_current(const AbstractClient *client); + +/*============================================================================== + * Client Properties + *============================================================================*/ + +/** + * Get the client title. + * Returns a reference to the internal string (do not free). + */ +const char* wm_client_get_title(const AbstractClient *client); + +/** + * Set the client title. + */ +void wm_client_set_title(AbstractClient *client, const char *title); + +/** + * Get the client class (application class). + */ +const char* wm_client_get_class(const AbstractClient *client); + +/** + * Set the client class. + */ +void wm_client_set_class(AbstractClient *client, const char *class_name); + +/** + * Get the client instance name. + */ +const char* wm_client_get_instance(const AbstractClient *client); + +/** + * Set the client instance name. + */ +void wm_client_set_instance(AbstractClient *client, const char *instance); + +/** + * Get the client's taskbar color. + */ +WmColor wm_client_get_color(const AbstractClient *client); + +/** + * Set the client's taskbar color. + */ +void wm_client_set_color(AbstractClient *client, WmColor color); + +/*============================================================================== + * Client Actions + *============================================================================*/ + +/** + * Focus the client. + */ +void wm_client_focus(AbstractClient *client); + +/** + * Unfocus the client. + */ +void wm_client_unfocus(AbstractClient *client); + +/** + * Raise the client to the top of the stack. + */ +void wm_client_raise(AbstractClient *client); + +/** + * Lower the client to the bottom of the stack. + */ +void wm_client_lower(AbstractClient *client); + +/** + * Show/map the client window. + */ +void wm_client_show(AbstractClient *client); + +/** + * Hide/unmap the client window. + */ +void wm_client_hide(AbstractClient *client); + +/** + * Minimize the client. + */ +void wm_client_minimize(AbstractClient *client); + +/** + * Restore the client from minimized state. + */ +void wm_client_restore(AbstractClient *client); + +/** + * Close the client (politely request close). + */ +void wm_client_close(AbstractClient *client); + +/** + * Kill the client (forcefully terminate). + */ +void wm_client_kill(AbstractClient *client); + +/*============================================================================== + * Client Management + *============================================================================*/ + +/** + * Reparent the client into a frame window. + */ +void wm_client_reparent(AbstractClient *client, WmWindowHandle frame); + +/** + * Unreparent the client from its frame. + */ +void wm_client_unreparent(AbstractClient *client); + +/** + * Configure the client (apply size hints, constraints). + */ +void wm_client_configure(AbstractClient *client); + +/** + * Apply size hints to constrain width/height. + */ +void wm_client_apply_size_hints(AbstractClient *client, int *width, int *height); + +/** + * Move and resize a client. + */ +void wm_client_move_resize(AbstractClient *client, int x, int y, int width, int height); + +/*============================================================================== + * Client List Management + *============================================================================*/ + +/** + * Get the next client in the global list. + */ +AbstractClient* wm_client_get_next(const AbstractClient *client); + +/** + * Get the previous client in the global list. + */ +AbstractClient* wm_client_get_prev(const AbstractClient *client); + +/** + * Get the first client in the global list. + */ +AbstractClient* wm_client_get_first(void); + +/** + * Get the last client in the global list. + */ +AbstractClient* wm_client_get_last(void); + +/** + * Get the next client in MRU (Most Recently Used) order. + */ +AbstractClient* wm_client_get_next_mru(const AbstractClient *client); + +/** + * Get the previous client in MRU order. + */ +AbstractClient* wm_client_get_prev_mru(const AbstractClient *client); + +/*============================================================================== + * Client Lookup + *============================================================================*/ + +/** + * Find a client by its window handle. + */ +AbstractClient* wm_client_find_by_window(WmWindowHandle window); + +/** + * Find a client by its frame handle. + */ +AbstractClient* wm_client_find_by_frame(WmWindowHandle frame); + +/** + * Find a client by its ID. + */ +AbstractClient* wm_client_find_by_id(WmClientId id); + +/*============================================================================== + * Client Iteration + *============================================================================*/ + +typedef bool (*WmClientForeachFunc)(AbstractClient *client, void *user_data); + +/** + * Iterate over all clients. + */ +void wm_client_foreach(WmClientForeachFunc func, void *user_data); + +/** + * Iterate over clients on a specific workspace. + */ +void wm_client_foreach_on_workspace(WmWorkspaceId workspace, + WmClientForeachFunc func, void *user_data); + +/** + * Count total clients. + */ +int wm_client_count(void); + +/** + * Count clients on a specific workspace. + */ +int wm_client_count_on_workspace(WmWorkspaceId workspace); + +/*============================================================================== + * Client Manager + *============================================================================*/ + +typedef struct WmClientManager WmClientManager; + +/** + * Get the global client manager. + */ +WmClientManager* wm_client_manager_get(void); + +/** + * Initialize the client manager. + */ +bool wm_client_manager_init(void); + +/** + * Shutdown the client manager. + */ +void wm_client_manager_shutdown(void); + +/** + * Register a client with the manager. + */ +void wm_client_manager_add(WmClientManager *mgr, AbstractClient *client); + +/** + * Unregister a client from the manager. + */ +void wm_client_manager_remove(WmClientManager *mgr, AbstractClient *client); + +/** + * Move a client to the front of the MRU list. + */ +void wm_client_manager_touch(WmClientManager *mgr, AbstractClient *client); + +/** + * Get the focused client. + */ +AbstractClient* wm_client_manager_get_focused(const WmClientManager *mgr); + +/** + * Set the focused client. + */ +void wm_client_manager_set_focused(WmClientManager *mgr, AbstractClient *client); + +#ifdef __cplusplus +} +#endif + +#endif /* WM_CLIENT_H */ diff --git a/include/core/wm_container.h b/include/core/wm_container.h new file mode 100644 index 0000000..0d238e4 --- /dev/null +++ b/include/core/wm_container.h @@ -0,0 +1,220 @@ +/* + * DWN - Desktop Window Manager + * Generic Container Interface + */ + +#ifndef WM_CONTAINER_H +#define WM_CONTAINER_H + +#include "wm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Container Lifecycle + *============================================================================*/ + +WmContainer* wm_container_create(WmContainerType type, WmDestroyFunc destroy_fn); +void wm_container_destroy(WmContainer *container); +void wm_container_clear(WmContainer *container); + +WmContainer* wm_container_clone(const WmContainer *container, WmCloneFunc clone_fn); + +/*============================================================================== + * Container Properties + *============================================================================*/ + +WmContainerType wm_container_get_type(const WmContainer *container); +size_t wm_container_size(const WmContainer *container); +bool wm_container_is_empty(const WmContainer *container); + +/*============================================================================== + * List Operations + *============================================================================*/ + +/* These work for LIST and QUEUE */ +void wm_list_append(WmContainer *list, void *data); +void wm_list_prepend(WmContainer *list, void *data); +void wm_list_insert(WmContainer *list, size_t index, void *data); + +bool wm_list_remove(WmContainer *list, void *data); +void* wm_list_remove_at(WmContainer *list, size_t index); + +void* wm_list_get(const WmContainer *list, size_t index); +void* wm_list_get_first(const WmContainer *list); +void* wm_list_get_last(const WmContainer *list); + +size_t wm_list_index_of(const WmContainer *list, void *data); +bool wm_list_contains(const WmContainer *list, void *data); + +void* wm_list_find(const WmContainer *list, WmCompareFunc cmp, const void *key); +void* wm_list_find_custom(const WmContainer *list, + bool (*predicate)(const void *item, const void *user_data), + const void *user_data); + +void wm_list_sort(WmContainer *list, WmCompareFunc cmp); +void wm_list_reverse(WmContainer *list); + +/*============================================================================== + * Array Operations + *============================================================================*/ + +void wm_array_append(WmContainer *array, void *data); +void wm_array_insert(WmContainer *array, size_t index, void *data); +void wm_array_set(WmContainer *array, size_t index, void *data); + +void* wm_array_get(const WmContainer *array, size_t index); +void* wm_array_remove_at(WmContainer *array, size_t index); + +void wm_array_resize(WmContainer *array, size_t new_size); +void wm_array_reserve(WmContainer *array, size_t capacity); +size_t wm_array_capacity(const WmContainer *array); + +void wm_array_compact(WmContainer *array); +void wm_array_sort(WmContainer *array, WmCompareFunc cmp); + +/*============================================================================== + * HashMap Operations + *============================================================================*/ + +/* Key types supported */ +typedef enum { + WM_HASH_KEY_STRING, + WM_HASH_KEY_INT, + WM_HASH_KEY_POINTER +} WmHashKeyType; + +WmContainer* wm_hashmap_create(WmHashKeyType key_type, WmDestroyFunc destroy_fn); + +void wm_hashmap_insert(WmContainer *map, const void *key, void *value); +void* wm_hashmap_get(const WmContainer *map, const void *key); +bool wm_hashmap_contains(const WmContainer *map, const void *key); +bool wm_hashmap_remove(WmContainer *map, const void *key); + +void* wm_hashmap_lookup(const WmContainer *map, WmCompareFunc cmp, const void *key); + +WmContainer* wm_hashmap_get_keys(const WmContainer *map); +WmContainer* wm_hashmap_get_values(const WmContainer *map); + +void wm_hashmap_rehash(WmContainer *map, size_t new_capacity); +float wm_hashmap_load_factor(const WmContainer *map); + +/* Convenience functions for string keys */ +void wm_hashmap_insert_string(WmContainer *map, const char *key, void *value); +void* wm_hashmap_get_string(const WmContainer *map, const char *key); +bool wm_hashmap_contains_string(const WmContainer *map, const char *key); +bool wm_hashmap_remove_string(WmContainer *map, const char *key); + +/* Convenience functions for int keys */ +void wm_hashmap_insert_int(WmContainer *map, int key, void *value); +void* wm_hashmap_get_int(const WmContainer *map, int key); +bool wm_hashmap_contains_int(const WmContainer *map, int key); +bool wm_hashmap_remove_int(WmContainer *map, int key); + +/*============================================================================== + * Stack Operations + *============================================================================*/ + +void wm_stack_push(WmContainer *stack, void *data); +void* wm_stack_pop(WmContainer *stack); +void* wm_stack_peek(const WmContainer *stack); + +/*============================================================================== + * Queue Operations + *============================================================================*/ + +void wm_queue_enqueue(WmContainer *queue, void *data); +void* wm_queue_dequeue(WmContainer *queue); +void* wm_queue_peek(const WmContainer *queue); +void* wm_queue_peek_tail(const WmContainer *queue); + +/*============================================================================== + * Tree Operations (if type is TREE) + *============================================================================*/ + +typedef struct WmTreeNode WmTreeNode; + +WmTreeNode* wm_tree_get_root(const WmContainer *tree); +WmTreeNode* wm_tree_node_get_left(const WmTreeNode *node); +WmTreeNode* wm_tree_node_get_right(const WmTreeNode *node); +WmTreeNode* wm_tree_node_get_parent(const WmTreeNode *node); +void* wm_tree_node_get_data(const WmTreeNode *node); + +/*============================================================================== + * Iteration + *============================================================================*/ + +WmIterator* wm_container_iterator(const WmContainer *container); +WmIterator* wm_container_iterator_reverse(const WmContainer *container); + +void wm_iterator_destroy(WmIterator *it); +bool wm_iterator_has_next(const WmIterator *it); +void* wm_iterator_next(WmIterator *it); +const void* wm_iterator_peek(const WmIterator *it); + +/* HashMap iteration - returns key-value pairs */ +typedef struct { + const void *key; + void *value; +} WmHashEntry; + +WmIterator* wm_hashmap_iterator(const WmContainer *map); +WmHashEntry* wm_hashmap_iterator_next(WmIterator *it); + +/*============================================================================== + * Functional Operations + *============================================================================*/ + +typedef void (*WmForeachFunc)(void *item, void *user_data); +typedef void* (*WmMapFunc)(const void *item, void *user_data); +typedef bool (*WmFilterFunc)(const void *item, void *user_data); +typedef void* (*WmReduceFunc)(void *accumulator, const void *item, void *user_data); + +void wm_container_foreach(const WmContainer *container, WmForeachFunc func, void *user_data); + +WmContainer* wm_container_map(const WmContainer *container, WmContainerType new_type, + WmMapFunc func, WmDestroyFunc destroy_fn, void *user_data); + +WmContainer* wm_container_filter(const WmContainer *container, + WmFilterFunc predicate, void *user_data); + +void* wm_container_reduce(const WmContainer *container, + WmReduceFunc func, void *initial, void *user_data); + +bool wm_container_all_match(const WmContainer *container, + WmFilterFunc predicate, void *user_data); + +bool wm_container_any_match(const WmContainer *container, + WmFilterFunc predicate, void *user_data); + +/*============================================================================== + * Convenience Constructors + *============================================================================*/ + +static inline WmContainer* wm_list_create(WmDestroyFunc destroy_fn) { + return wm_container_create(WM_CONTAINER_LIST, destroy_fn); +} + +static inline WmContainer* wm_array_create(WmDestroyFunc destroy_fn) { + return wm_container_create(WM_CONTAINER_ARRAY, destroy_fn); +} + +static inline WmContainer* wm_hashmap_create_string(WmDestroyFunc destroy_fn) { + return wm_hashmap_create(WM_HASH_KEY_STRING, destroy_fn); +} + +static inline WmContainer* wm_queue_create(WmDestroyFunc destroy_fn) { + return wm_container_create(WM_CONTAINER_QUEUE, destroy_fn); +} + +static inline WmContainer* wm_stack_create(WmDestroyFunc destroy_fn) { + return wm_container_create(WM_CONTAINER_STACK, destroy_fn); +} + +#ifdef __cplusplus +} +#endif + +#endif /* WM_CONTAINER_H */ diff --git a/include/core/wm_event.h b/include/core/wm_event.h new file mode 100644 index 0000000..04c2e4b --- /dev/null +++ b/include/core/wm_event.h @@ -0,0 +1,265 @@ +/* + * DWN - Desktop Window Manager + * Event Bus System + */ + +#ifndef WM_EVENT_H +#define WM_EVENT_H + +#include "wm_types.h" +#include "wm_client.h" +#include "wm_string.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Event Data Structures + *============================================================================*/ + +typedef struct { + WmEventType type; + WmTime timestamp; + WmId source_id; +} WmEventHeader; + +/* Window Events */ +typedef struct { + WmEventHeader header; + AbstractClient *client; +} WmEventWindowBase; + +typedef struct { + WmEventHeader header; + AbstractClient *client; +} WmEventWindowCreated; + +typedef struct { + WmEventHeader header; + AbstractClient *client; + WmString *old_title; + WmString *new_title; +} WmEventWindowTitleChanged; + +typedef struct { + WmEventHeader header; + AbstractClient *client; + WmRect old_geometry; + WmRect new_geometry; +} WmEventWindowMoved; + +typedef struct { + WmEventHeader header; + AbstractClient *client; + WmRect old_geometry; + WmRect new_geometry; +} WmEventWindowResized; + +typedef struct { + WmEventHeader header; + AbstractClient *client; + WmClientFlags old_flags; + WmClientFlags new_flags; +} WmEventWindowStateChanged; + +/* Workspace Events */ +typedef struct { + WmEventHeader header; + WmWorkspaceId workspace; +} WmEventWorkspaceBase; + +typedef struct { + WmEventHeader header; + WmWorkspaceId old_workspace; + WmWorkspaceId new_workspace; +} WmEventWorkspaceSwitched; + +typedef struct { + WmEventHeader header; + WmWorkspaceId workspace; + WmLayoutType old_layout; + WmLayoutType new_layout; +} WmEventWorkspaceLayoutChanged; + +typedef struct { + WmEventHeader header; + WmWorkspaceId workspace; + AbstractClient *client; +} WmEventClientWorkspaceChanged; + +/* Input Events */ +typedef struct { + WmEventHeader header; + unsigned int keycode; + unsigned int keysym; + unsigned int modifiers; + const char *key_name; +} WmEventKey; + +typedef struct { + WmEventHeader header; + unsigned int button; + int x; + int y; + unsigned int modifiers; +} WmEventButton; + +typedef struct { + WmEventHeader header; + int x; + int y; + int delta_x; + int delta_y; + unsigned int modifiers; +} WmEventMotion; + +typedef struct { + WmEventHeader header; + int delta; + int x; + int y; +} WmEventScroll; + +/* Monitor Events */ +typedef struct { + WmEventHeader header; + int monitor_index; + WmRect geometry; + bool primary; +} WmEventMonitorAdded; + +typedef struct { + WmEventHeader header; + int monitor_index; +} WmEventMonitorRemoved; + +/* Configuration Events */ +typedef struct { + WmEventHeader header; + WmString *config_path; + bool success; + WmString *error_message; +} WmEventConfigReloaded; + +/* Command Events */ +typedef struct { + WmEventHeader header; + WmCommandType command; + bool success; + WmString *error_message; +} WmEventCommandExecuted; + +/* Custom Event */ +typedef struct { + WmEventHeader header; + WmString *event_name; + void *custom_data; + WmDestroyFunc destroy_func; +} WmEventCustom; + +/*============================================================================== + * Event Bus Lifecycle + *============================================================================*/ + +WmEventBus* wm_event_bus_create(void); +void wm_event_bus_destroy(WmEventBus *bus); + +WmEventBus* wm_event_bus_get_default(void); +void wm_event_bus_set_default(WmEventBus *bus); + +/*============================================================================== + * Event Subscription + *============================================================================*/ + +WmEventSubscription* wm_event_subscribe(WmEventBus *bus, + WmEventType type, + WmEventHandler handler, + void *user_data); + +WmEventSubscription* wm_event_subscribe_pattern(WmEventBus *bus, + WmEventType type_min, + WmEventType type_max, + WmEventHandler handler, + void *user_data); + +WmEventSubscription* wm_event_subscribe_all(WmEventBus *bus, + WmEventHandler handler, + void *user_data); + +void wm_event_unsubscribe(WmEventBus *bus, WmEventSubscription *subscription); +void wm_event_unsubscribe_all(WmEventBus *bus, void *user_data); + +/*============================================================================== + * Event Emission + *============================================================================*/ + +void wm_event_emit(WmEventBus *bus, WmEventType type, const void *event_data); +void wm_event_emit_async(WmEventBus *bus, WmEventType type, const void *event_data); + +/* Convenience emitters */ +void wm_event_emit_window_created(WmEventBus *bus, AbstractClient *client); +void wm_event_emit_window_destroyed(WmEventBus *bus, AbstractClient *client); +void wm_event_emit_window_focused(WmEventBus *bus, AbstractClient *client, AbstractClient *prev_focus); +void wm_event_emit_window_moved(WmEventBus *bus, AbstractClient *client, const WmRect *old_geom); +void wm_event_emit_window_resized(WmEventBus *bus, AbstractClient *client, const WmRect *old_geom); +void wm_event_emit_window_state_changed(WmEventBus *bus, AbstractClient *client, + WmClientFlags old_flags, WmClientFlags new_flags); + +void wm_event_emit_workspace_switched(WmEventBus *bus, WmWorkspaceId old_ws, WmWorkspaceId new_ws); +void wm_event_emit_workspace_layout_changed(WmEventBus *bus, WmWorkspaceId ws, + WmLayoutType old_layout, WmLayoutType new_layout); + +/*============================================================================== + * Event Processing + *============================================================================*/ + +void wm_event_process(WmEventBus *bus); +void wm_event_process_all(WmEventBus *bus); +bool wm_event_process_one(WmEventBus *bus); + +void wm_event_dispatch_pending(WmEventBus *bus); +int wm_event_get_pending_count(const WmEventBus *bus); + +/*============================================================================== + * Event Data Helpers + *============================================================================*/ + +WmEventHeader* wm_event_get_header(void *event_data); +WmTime wm_event_get_timestamp(const void *event_data); +const char* wm_event_type_to_string(WmEventType type); +WmEventType wm_event_type_from_string(const char *str); + +/*============================================================================== + * Event Blocking/Filtering + *============================================================================*/ + +void wm_event_begin_block(WmEventBus *bus, WmEventType type); +void wm_event_end_block(WmEventBus *bus, WmEventType type); +bool wm_event_is_blocked(const WmEventBus *bus, WmEventType type); + +void wm_event_suppress(WmEventBus *bus, WmEventType type); +void wm_event_unsuppress(WmEventBus *bus, WmEventType type); +bool wm_event_is_suppressed(const WmEventBus *bus, WmEventType type); + +/*============================================================================== + * Custom Events + *============================================================================*/ + +void wm_event_emit_custom(WmEventBus *bus, const char *event_name, void *data, WmDestroyFunc destroy_fn); +WmEventSubscription* wm_event_subscribe_custom(WmEventBus *bus, const char *event_name, + WmEventHandler handler, void *user_data); + +/*============================================================================== + * Event Statistics + *============================================================================*/ + +uint64_t wm_event_get_emit_count(const WmEventBus *bus, WmEventType type); +uint64_t wm_event_get_total_emit_count(const WmEventBus *bus); +void wm_event_reset_statistics(WmEventBus *bus); + +#ifdef __cplusplus +} +#endif + +#endif /* WM_EVENT_H */ diff --git a/include/core/wm_hashmap.h b/include/core/wm_hashmap.h new file mode 100644 index 0000000..3d6ca68 --- /dev/null +++ b/include/core/wm_hashmap.h @@ -0,0 +1,107 @@ +/* + * DWN - Desktop Window Manager + * Abstract Hash Map Container + */ + +#ifndef WM_HASHMAP_H +#define WM_HASHMAP_H + +#include "core/wm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Opaque Types + *============================================================================*/ + +typedef struct WmHashMap WmHashMap; + +/*============================================================================== + * Function Types + *============================================================================*/ + +typedef uint32_t (*WmHashFunc)(const void *key); +typedef bool (*WmKeyEqualFunc)(const void *a, const void *b); +typedef void (*WmHashForeachFunc)(void *key, void *value, void *user_data); + +/*============================================================================== + * Hash Functions + *============================================================================*/ + +static inline uint32_t wm_hash_ptr(const void *ptr) { + uintptr_t p = (uintptr_t)ptr; + return (uint32_t)(p ^ (p >> 32)); +} + +static inline uint32_t wm_hash_int(int key) { + return (uint32_t)key; +} + +/*============================================================================== + * Lifecycle + *============================================================================*/ + +WmHashMap* wm_hashmap_new(void); +WmHashMap* wm_hashmap_new_full(WmHashFunc hash_func, WmKeyEqualFunc key_equal, + WmFreeFunc key_free, WmFreeFunc value_free); +WmHashMap* wm_hashmap_new_string_key(void); +void wm_hashmap_destroy(WmHashMap *map); +WmHashMap* wm_hashmap_clone(const WmHashMap *map); + +/*============================================================================== + * Capacity + *============================================================================*/ + +size_t wm_hashmap_size(const WmHashMap *map); +bool wm_hashmap_is_empty(const WmHashMap *map); +void wm_hashmap_clear(WmHashMap *map); + +/*============================================================================== + * Element Access + *============================================================================*/ + +void* wm_hashmap_get(const WmHashMap *map, const void *key); +void* wm_hashmap_get_or_default(const WmHashMap *map, const void *key, void *default_val); +bool wm_hashmap_contains(const WmHashMap *map, const void *key); + +/*============================================================================== + * Modifiers + *============================================================================*/ + +bool wm_hashmap_insert(WmHashMap *map, void *key, void *value); +bool wm_hashmap_insert_no_replace(WmHashMap *map, void *key, void *value); +void* wm_hashmap_set(WmHashMap *map, void *key, void *value); +void* wm_hashmap_remove(WmHashMap *map, const void *key); +bool wm_hashmap_steal(WmHashMap *map, const void *key); + +/*============================================================================== + * Iteration + *============================================================================*/ + +typedef struct { + void *map; /* Opaque pointer to hashmap */ + size_t bucket; + void *entry; /* Opaque pointer to current entry */ + void *next_entry; /* Opaque pointer to next entry */ +} WmHashMapIter; + +void wm_hashmap_iter_init(WmHashMapIter *iter, WmHashMap *map); +bool wm_hashmap_iter_next(WmHashMapIter *iter, void **key, void **value); +void wm_hashmap_foreach(const WmHashMap *map, WmHashForeachFunc func, void *user_data); + +/*============================================================================== + * String Helpers + *============================================================================*/ + +bool wm_hashmap_insert_string(WmHashMap *map, const char *key, void *value); +void* wm_hashmap_get_string(const WmHashMap *map, const char *key); +bool wm_hashmap_contains_string(const WmHashMap *map, const char *key); +void* wm_hashmap_remove_string(WmHashMap *map, const char *key); + +#ifdef __cplusplus +} +#endif + +#endif /* WM_HASHMAP_H */ diff --git a/include/core/wm_list.h b/include/core/wm_list.h new file mode 100644 index 0000000..4cc650d --- /dev/null +++ b/include/core/wm_list.h @@ -0,0 +1,123 @@ +/* + * DWN - Desktop Window Manager + * Abstract List Container + */ + +#ifndef WM_LIST_H +#define WM_LIST_H + +#include "core/wm_types.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Opaque Types + *============================================================================*/ + +typedef struct WmList WmList; + +/*============================================================================== + * Function Types + *============================================================================*/ + +typedef void (*WmFreeFunc)(void *item); +typedef int (*WmCompareFunc)(const void *a, const void *b); +typedef bool (*WmForeachFunc)(void *item, size_t index, void *user_data); +typedef void* (*WmCloneFunc)(const void *item); + +/*============================================================================== + * Lifecycle + *============================================================================*/ + +WmList* wm_list_new(void); +WmList* wm_list_new_sized(size_t initial_capacity); +void wm_list_destroy(WmList *list); +void wm_list_destroy_no_free(WmList *list); +WmList* wm_list_clone(const WmList *list); +void wm_list_set_free_func(WmList *list, WmFreeFunc func); + +/*============================================================================== + * Capacity + *============================================================================*/ + +size_t wm_list_size(const WmList *list); +size_t wm_list_capacity(const WmList *list); +bool wm_list_is_empty(const WmList *list); +void wm_list_reserve(WmList *list, size_t capacity); +void wm_list_compact(WmList *list); +void wm_list_clear(WmList *list); + +/*============================================================================== + * Modifiers + *============================================================================*/ + +void wm_list_append(WmList *list, void *item); +void wm_list_prepend(WmList *list, void *item); +void wm_list_insert(WmList *list, size_t index, void *item); +void wm_list_insert_sorted(WmList *list, void *item, WmCompareFunc compare); +void wm_list_remove(WmList *list, void *item); +void wm_list_remove_at(WmList *list, size_t index); +void* wm_list_take_at(WmList *list, size_t index); +bool wm_list_remove_one(WmList *list, void *item); +bool wm_list_remove_all(WmList *list, void *item); +void* wm_list_pop_back(WmList *list); +void* wm_list_pop_front(WmList *list); + +/*============================================================================== + * Accessors + *============================================================================*/ + +void* wm_list_get(const WmList *list, size_t index); +void* wm_list_first(const WmList *list); +void* wm_list_last(const WmList *list); +void* wm_list_front(const WmList *list); +void* wm_list_back(const WmList *list); +void wm_list_set(WmList *list, size_t index, void *item); + +/*============================================================================== + * Iteration + *============================================================================*/ + +void wm_list_foreach(const WmList *list, WmForeachFunc func, void *user_data); +void wm_list_foreach_reverse(const WmList *list, WmForeachFunc func, void *user_data); + +/*============================================================================== + * Search + *============================================================================*/ + +ssize_t wm_list_index_of(const WmList *list, void *item); +bool wm_list_contains(const WmList *list, void *item); +void* wm_list_find(const WmList *list, WmCompareFunc compare, const void *key); +ssize_t wm_list_find_index(const WmList *list, WmCompareFunc compare, const void *key); + +/*============================================================================== + * Sorting + *============================================================================*/ + +void wm_list_sort(WmList *list, WmCompareFunc compare); + +/*============================================================================== + * Data Operations + *============================================================================*/ + +void** wm_list_data(WmList *list); +void* wm_list_steal(WmList *list, size_t index); +WmList* wm_list_slice(const WmList *list, size_t start, size_t end); +void wm_list_move(WmList *list, size_t from, size_t to); +void wm_list_swap(WmList *list, size_t i, size_t j); + +/*============================================================================== + * Comparison + *============================================================================*/ + +bool wm_list_equals(const WmList *list1, const WmList *list2); + +#ifdef __cplusplus +} +#endif + +#endif /* WM_LIST_H */ diff --git a/include/core/wm_string.h b/include/core/wm_string.h new file mode 100644 index 0000000..151e313 --- /dev/null +++ b/include/core/wm_string.h @@ -0,0 +1,222 @@ +/* + * DWN - Desktop Window Manager + * Abstract String Type + */ + +#ifndef WM_STRING_H +#define WM_STRING_H + +#include "wm_types.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * String Lifecycle + *============================================================================*/ + +WmString* wm_string_new(const char *str); +WmString* wm_string_new_empty(void); +WmString* wm_string_new_sized(size_t capacity); +WmString* wm_string_new_printf(const char *fmt, ...); +WmString* wm_string_new_vprintf(const char *fmt, va_list args); +WmString* wm_string_new_n(const char *str, size_t n); + +void wm_string_destroy(WmString *str); +WmString* wm_string_clone(const WmString *str); + +/*============================================================================== + * String Operations + *============================================================================*/ + +void wm_string_append(WmString *str, const char *suffix); +void wm_string_append_char(WmString *str, char c); +void wm_string_append_n(WmString *str, const char *suffix, size_t n); +void wm_string_append_printf(WmString *str, const char *fmt, ...); +void wm_string_append_vprintf(WmString *str, const char *fmt, va_list args); +void wm_string_append_string(WmString *str, const WmString *suffix); + +void wm_string_prepend(WmString *str, const char *prefix); +void wm_string_prepend_char(WmString *str, char c); + +void wm_string_insert(WmString *str, size_t pos, const char *insert); +void wm_string_insert_char(WmString *str, size_t pos, char c); +void wm_string_insert_string(WmString *str, size_t pos, const WmString *insert); + +void wm_string_erase(WmString *str, size_t pos, size_t len); +void wm_string_clear(WmString *str); + +/*============================================================================== + * String Queries + *============================================================================*/ + +const char* wm_string_cstr(const WmString *str); +char* wm_string_detach(WmString *str); + +size_t wm_string_length(const WmString *str); +size_t wm_string_capacity(const WmString *str); +size_t wm_string_bytes(const WmString *str); + +bool wm_string_is_empty(const WmString *str); +bool wm_string_is_null(const WmString *str); + +char wm_string_char_at(const WmString *str, size_t pos); + +/*============================================================================== + * String Comparison + *============================================================================*/ + +bool wm_string_equals(const WmString *str1, const WmString *str2); +bool wm_string_equals_cstr(const WmString *str, const char *cstr); + +int wm_string_compare(const WmString *str1, const WmString *str2); +int wm_string_compare_cstr(const WmString *str, const char *cstr); +int wm_string_case_compare(const WmString *str1, const WmString *str2); +int wm_string_case_compare_cstr(const WmString *str, const char *cstr); + +/*============================================================================== + * String Searching + *============================================================================*/ + +bool wm_string_contains(const WmString *str, const char *needle); +bool wm_string_contains_char(const WmString *str, char c); + +size_t wm_string_find(const WmString *str, const char *needle, size_t start); +size_t wm_string_find_char(const WmString *str, char c, size_t start); +size_t wm_string_find_last(const WmString *str, const char *needle); +size_t wm_string_find_last_char(const WmString *str, char c); + +bool wm_string_starts_with(const WmString *str, const char *prefix); +bool wm_string_starts_with_char(const WmString *str, char c); +bool wm_string_ends_with(const WmString *str, const char *suffix); +bool wm_string_ends_with_char(const WmString *str, char c); + +/*============================================================================== + * String Modification + *============================================================================*/ + +void wm_string_trim(WmString *str); +void wm_string_trim_left(WmString *str); +void wm_string_trim_right(WmString *str); + +void wm_string_replace(WmString *str, const char *search, const char *replace); +void wm_string_replace_char(WmString *str, char search, char replace); +size_t wm_string_replace_all(WmString *str, const char *search, const char *replace); + +void wm_string_to_lower(WmString *str); +void wm_string_to_upper(WmString *str); + +void wm_string_reverse(WmString *str); + +/*============================================================================== + * String Substrings + *============================================================================*/ + +WmString* wm_string_substring(const WmString *str, size_t start, size_t len); +WmString* wm_string_left(const WmString *str, size_t n); +WmString* wm_string_right(const WmString *str, size_t n); + +/*============================================================================== + * String Splitting and Joining + *============================================================================*/ + +WmContainer* wm_string_split(const WmString *str, const char *delimiter); +WmContainer* wm_string_split_chars(const WmString *str, const char *delimiters); +WmContainer* wm_string_split_lines(const WmString *str); + +WmString* wm_string_join(const WmContainer *strings, const char *separator); +WmString* wm_string_join_cstr(const char **strings, size_t count, const char *separator); + +/*============================================================================== + * String Formatting + *============================================================================*/ + +void wm_string_printf(WmString *str, const char *fmt, ...); +void wm_string_vprintf(WmString *str, const char *fmt, va_list args); + +/*============================================================================== + * String Validation + *============================================================================*/ + +bool wm_string_is_valid_utf8(const WmString *str); +bool wm_string_is_ascii(const WmString *str); +bool wm_string_is_numeric(const WmString *str); +bool wm_string_is_integer(const WmString *str); +bool wm_string_is_float(const WmString *str); + +/*============================================================================== + * String Conversion + *============================================================================*/ + +int wm_string_to_int(const WmString *str, int default_val); +long wm_string_to_long(const WmString *str, long default_val); +float wm_string_to_float(const WmString *str, float default_val); +double wm_string_to_double(const WmString *str, double default_val); +bool wm_string_to_bool(const WmString *str, bool default_val); + +WmString* wm_string_from_int(int val); +WmString* wm_string_from_long(long val); +WmString* wm_string_from_float(float val, int precision); +WmString* wm_string_from_double(double val, int precision); +WmString* wm_string_from_bool(bool val); + +/*============================================================================== + * String Hash + *============================================================================*/ + +uint32_t wm_string_hash(const WmString *str); +uint32_t wm_string_hash_cstr(const char *str); + +/*============================================================================== + * String Escaping + *============================================================================*/ + +WmString* wm_string_escape_json(const WmString *str); +WmString* wm_string_escape_xml(const WmString *str); +WmString* wm_string_escape_html(const WmString *str); +WmString* wm_string_escape_shell(const WmString *str); +WmString* wm_string_escape_regex(const WmString *str); + +WmString* wm_string_unescape_json(const WmString *str); +WmString* wm_string_unescape_xml(const WmString *str); +WmString* wm_string_unescape_html(const WmString *str); + +/*============================================================================== + * Static String Helpers + *============================================================================*/ + +static inline bool wm_cstr_is_empty(const char *str) { + return str == NULL || str[0] == '\0'; +} + +static inline size_t wm_cstr_length(const char *str) { + return str == NULL ? 0 : strlen(str); +} + +static inline bool wm_cstr_equals(const char *a, const char *b) { + if (a == b) return true; + if (a == NULL || b == NULL) return false; + return strcmp(a, b) == 0; +} + +static inline bool wm_cstr_case_equals(const char *a, const char *b) { + if (a == b) return true; + if (a == NULL || b == NULL) return false; + return strcasecmp(a, b) == 0; +} + +static inline void wm_cstr_copy(char *dest, const char *src, size_t size) { + if (size == 0) return; + strncpy(dest, src, size - 1); + dest[size - 1] = '\0'; +} + +#ifdef __cplusplus +} +#endif + +#endif /* WM_STRING_H */ diff --git a/include/core/wm_types.h b/include/core/wm_types.h new file mode 100644 index 0000000..f92ce1a --- /dev/null +++ b/include/core/wm_types.h @@ -0,0 +1,490 @@ +/* + * DWN - Desktop Window Manager + * Core Abstract Types + * Extreme Abstraction Architecture + */ + +#ifndef WM_TYPES_H +#define WM_TYPES_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Version and API Information + *============================================================================*/ + +#define WM_CORE_VERSION_MAJOR 2 +#define WM_CORE_VERSION_MINOR 0 +#define WM_CORE_VERSION_PATCH 0 + +#define WM_PLUGIN_API_VERSION 1 + +/*============================================================================== + * Opaque Type Declarations + *============================================================================*/ + +typedef struct WmCore WmCore; +typedef struct WmBackend WmBackend; +typedef struct WmPlugin WmPlugin; +typedef struct WmPluginManager WmPluginManager; +typedef struct WmEventBus WmEventBus; +typedef struct WmEventSubscription WmEventSubscription; +typedef struct WmContainer WmContainer; +typedef struct WmIterator WmIterator; +typedef struct WmString WmString; +typedef struct WmRenderer WmRenderer; +typedef struct WmSurface WmSurface; +typedef struct WmFont WmFont; +typedef struct WmImage WmImage; +typedef struct WmCommand WmCommand; +typedef struct WmCommandBuilder WmCommandBuilder; +typedef struct WmConfigSchema WmConfigSchema; +typedef struct WmConfigInstance WmConfigInstance; +typedef struct WmLayoutEngine WmLayoutEngine; +typedef struct WmPanelSystem WmPanelSystem; +typedef struct WmAnimation WmAnimation; +typedef struct WmTimer WmTimer; +typedef struct WmMutex WmMutex; +typedef struct WmCondition WmCondition; +typedef struct WmThread WmThread; + +/*============================================================================== + * Basic Type Definitions + *============================================================================*/ + +typedef uint32_t WmColor; +typedef uint64_t WmTime; +typedef uint32_t WmHandle; +typedef uint32_t WmId; +typedef WmId WmClientId; +typedef int WmWorkspaceId; +typedef void* WmWindowHandle; +typedef void* WmNativeHandle; + +/*============================================================================== + * Window Types + *============================================================================*/ + +typedef enum { + WM_WINDOW_TYPE_UNKNOWN = 0, + WM_WINDOW_TYPE_NORMAL, + WM_WINDOW_TYPE_DIALOG, + WM_WINDOW_TYPE_DOCK, + WM_WINDOW_TYPE_DESKTOP, + WM_WINDOW_TYPE_TOOLBAR, + WM_WINDOW_TYPE_MENU, + WM_WINDOW_TYPE_UTILITY, + WM_WINDOW_TYPE_SPLASH, + WM_WINDOW_TYPE_NOTIFICATION, + WM_WINDOW_TYPE_COMBO, + WM_WINDOW_TYPE_DND, + WM_WINDOW_TYPE_POPUP_MENU, + WM_WINDOW_TYPE_TOOLTIP +} WmWindowType; + +/*============================================================================== + * Geometry Types + *============================================================================*/ + +typedef struct { + int x; + int y; +} WmPoint; + +typedef struct { + int width; + int height; +} WmSize; + +typedef struct { + int x; + int y; + int width; + int height; +} WmRect; + +typedef struct { + WmPoint location; + WmSize size; +} WmGeometry; + +typedef struct { + int top; + int bottom; + int left; + int right; +} WmInsets; + +typedef struct { + float x; + float y; +} WmPointF; + +typedef struct { + float width; + float height; +} WmSizeF; + +typedef struct { + WmPointF location; + WmSizeF size; +} WmGeometryF; + +/*============================================================================== + * Rectangle Operations (Inline) + *============================================================================*/ + +static inline WmRect wm_rect_make(int x, int y, int width, int height) { + WmRect r = { x, y, width, height }; + return r; +} + +static inline bool wm_rect_is_empty(const WmRect *r) { + return r == NULL || r->width <= 0 || r->height <= 0; +} + +static inline bool wm_rect_contains_point(const WmRect *r, int x, int y) { + return r != NULL && + x >= r->x && x < r->x + r->width && + y >= r->y && y < r->y + r->height; +} + +static inline bool wm_rect_intersects(const WmRect *a, const WmRect *b) { + if (a == NULL || b == NULL) return false; + return !(a->x + a->width <= b->x || + b->x + b->width <= a->x || + a->y + a->height <= b->y || + b->y + b->height <= a->y); +} + +static inline WmRect wm_rect_intersection(const WmRect *a, const WmRect *b) { + WmRect r = { 0, 0, 0, 0 }; + if (a == NULL || b == NULL) return r; + + int x1 = a->x > b->x ? a->x : b->x; + int y1 = a->y > b->y ? a->y : b->y; + int x2 = (a->x + a->width) < (b->x + b->width) ? (a->x + a->width) : (b->x + b->width); + int y2 = (a->y + a->height) < (b->y + b->height) ? (a->y + a->height) : (b->y + b->height); + + if (x2 > x1 && y2 > y1) { + r.x = x1; + r.y = y1; + r.width = x2 - x1; + r.height = y2 - y1; + } + return r; +} + +static inline WmRect wm_rect_union(const WmRect *a, const WmRect *b) { + WmRect r = { 0, 0, 0, 0 }; + if (a == NULL && b == NULL) return r; + if (a == NULL) return *b; + if (b == NULL) return *a; + + int x1 = a->x < b->x ? a->x : b->x; + int y1 = a->y < b->y ? a->y : b->y; + int x2 = (a->x + a->width) > (b->x + b->width) ? (a->x + a->width) : (b->x + b->width); + int y2 = (a->y + a->height) > (b->y + b->height) ? (a->y + a->height) : (b->y + b->height); + + r.x = x1; + r.y = y1; + r.width = x2 - x1; + r.height = y2 - y1; + return r; +} + +/*============================================================================== + * Color Operations (Inline) + *============================================================================*/ + +static inline WmColor wm_color_rgb(uint8_t r, uint8_t g, uint8_t b) { + return (0xFF << 24) | (r << 16) | (g << 8) | b; +} + +static inline WmColor wm_color_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + return (a << 24) | (r << 16) | (g << 8) | b; +} + +static inline uint8_t wm_color_get_red(WmColor c) { + return (c >> 16) & 0xFF; +} + +static inline uint8_t wm_color_get_green(WmColor c) { + return (c >> 8) & 0xFF; +} + +static inline uint8_t wm_color_get_blue(WmColor c) { + return c & 0xFF; +} + +static inline uint8_t wm_color_get_alpha(WmColor c) { + return (c >> 24) & 0xFF; +} + +/*============================================================================== + * Client State Flags + *============================================================================*/ + +typedef enum { + WM_CLIENT_FLAG_NONE = 0, + WM_CLIENT_FLAG_FLOATING = (1 << 0), + WM_CLIENT_FLAG_FULLSCREEN = (1 << 1), + WM_CLIENT_FLAG_URGENT = (1 << 2), + WM_CLIENT_FLAG_MINIMIZED = (1 << 3), + WM_CLIENT_FLAG_STICKY = (1 << 4), + WM_CLIENT_FLAG_MAXIMIZED = (1 << 5), + WM_CLIENT_FLAG_UNMANAGING = (1 << 6), + WM_CLIENT_FLAG_FOCUSED = (1 << 7), + WM_CLIENT_FLAG_MAPPED = (1 << 8), + WM_CLIENT_FLAG_DECORATED = (1 << 9), + WM_CLIENT_FLAG_DIALOG = (1 << 10), + WM_CLIENT_FLAG_DOCK = (1 << 11), + WM_CLIENT_FLAG_UTILITY = (1 << 12), + WM_CLIENT_FLAG_SPLASH = (1 << 13), + WM_CLIENT_FLAG_MENU = (1 << 14), + WM_CLIENT_FLAG_TOOLBAR = (1 << 15) +} WmClientFlags; + +/*============================================================================== + * Layout Types + *============================================================================*/ + +typedef enum { + WM_LAYOUT_TYPE_TILING, + WM_LAYOUT_TYPE_FLOATING, + WM_LAYOUT_TYPE_MONOCLE, + WM_LAYOUT_TYPE_GRID, + WM_LAYOUT_TYPE_SPIRAL, + WM_LAYOUT_TYPE_DWINDLE, + WM_LAYOUT_TYPE_MAX +} WmLayoutType; + +/*============================================================================== + * Panel Positions + *============================================================================*/ + +typedef enum { + WM_PANEL_POSITION_TOP, + WM_PANEL_POSITION_BOTTOM, + WM_PANEL_POSITION_LEFT, + WM_PANEL_POSITION_RIGHT +} WmPanelPosition; + +/*============================================================================== + * Event Types + *============================================================================*/ + +typedef enum { + /* Window events */ + WM_EVENT_NONE = 0, + WM_EVENT_WINDOW_CREATED, + WM_EVENT_WINDOW_DESTROYED, + WM_EVENT_WINDOW_MAPPED, + WM_EVENT_WINDOW_UNMAPPED, + WM_EVENT_WINDOW_CONFIGURED, + WM_EVENT_WINDOW_FOCUSED, + WM_EVENT_WINDOW_UNFOCUSED, + WM_EVENT_WINDOW_RAISED, + WM_EVENT_WINDOW_LOWERED, + WM_EVENT_WINDOW_MINIMIZED, + WM_EVENT_WINDOW_RESTORED, + WM_EVENT_WINDOW_MAXIMIZED, + WM_EVENT_WINDOW_UNMAXIMIZED, + WM_EVENT_WINDOW_FULLSCREENED, + WM_EVENT_WINDOW_UNFULLSCREENED, + WM_EVENT_WINDOW_FLOATING_CHANGED, + WM_EVENT_WINDOW_PROPERTY_CHANGED, + WM_EVENT_WINDOW_STATE_CHANGED, + WM_EVENT_WINDOW_TITLE_CHANGED, + WM_EVENT_WINDOW_CLASS_CHANGED, + WM_EVENT_WINDOW_ROLE_CHANGED, + WM_EVENT_WINDOW_URGENCY_CHANGED, + WM_EVENT_WINDOW_MOVED, + WM_EVENT_WINDOW_RESIZED, + + /* Workspace events */ + WM_EVENT_WORKSPACE_CREATED, + WM_EVENT_WORKSPACE_DESTROYED, + WM_EVENT_WORKSPACE_SWITCHED, + WM_EVENT_WORKSPACE_RENAMED, + WM_EVENT_WORKSPACE_LAYOUT_CHANGED, + WM_EVENT_WORKSPACE_MASTER_RATIO_CHANGED, + WM_EVENT_WORKSPACE_MASTER_COUNT_CHANGED, + + /* Client/workspace relationship */ + WM_EVENT_CLIENT_ADDED_TO_WORKSPACE, + WM_EVENT_CLIENT_REMOVED_FROM_WORKSPACE, + + /* Input events */ + WM_EVENT_KEY_PRESSED, + WM_EVENT_KEY_RELEASED, + WM_EVENT_BUTTON_PRESSED, + WM_EVENT_BUTTON_RELEASED, + WM_EVENT_MOTION, + WM_EVENT_ENTER, + WM_EVENT_LEAVE, + WM_EVENT_SCROLL, + + /* System events */ + WM_EVENT_MONITOR_ADDED, + WM_EVENT_MONITOR_REMOVED, + WM_EVENT_MONITOR_CONFIGURED, + WM_EVENT_SCREEN_RESIZED, + + /* Configuration events */ + WM_EVENT_CONFIG_RELOADED, + WM_EVENT_CONFIG_CHANGED, + + /* Lifecycle events */ + WM_EVENT_WM_STARTED, + WM_EVENT_WM_SHUTDOWN, + WM_EVENT_WM_READY, + + /* Plugin events */ + WM_EVENT_PLUGIN_LOADED, + WM_EVENT_PLUGIN_UNLOADED, + WM_EVENT_PLUGIN_ERROR, + + /* Custom events for plugins */ + WM_EVENT_CUSTOM = 1000 +} WmEventType; + +/*============================================================================== + * Container Types + *============================================================================*/ + +typedef enum { + WM_CONTAINER_LIST, + WM_CONTAINER_ARRAY, + WM_CONTAINER_HASHMAP, + WM_CONTAINER_QUEUE, + WM_CONTAINER_STACK, + WM_CONTAINER_TREE +} WmContainerType; + +/*============================================================================== + * Command Types + *============================================================================*/ + +typedef enum { + WM_COMMAND_NONE = 0, + + /* Window commands */ + WM_COMMAND_WINDOW_FOCUS, + WM_COMMAND_WINDOW_MOVE, + WM_COMMAND_WINDOW_RESIZE, + WM_COMMAND_WINDOW_MOVE_RESIZE, + WM_COMMAND_WINDOW_CLOSE, + WM_COMMAND_WINDOW_KILL, + WM_COMMAND_WINDOW_MINIMIZE, + WM_COMMAND_WINDOW_RESTORE, + WM_COMMAND_WINDOW_MAXIMIZE, + WM_COMMAND_WINDOW_UNMAXIMIZE, + WM_COMMAND_WINDOW_FULLSCREEN, + WM_COMMAND_WINDOW_UNFULLSCREEN, + WM_COMMAND_WINDOW_FLOAT, + WM_COMMAND_WINDOW_UNFLOAT, + WM_COMMAND_WINDOW_RAISE, + WM_COMMAND_WINDOW_LOWER, + WM_COMMAND_WINDOW_SET_WORKSPACE, + + /* Workspace commands */ + WM_COMMAND_WORKSPACE_SWITCH, + WM_COMMAND_WORKSPACE_CREATE, + WM_COMMAND_WORKSPACE_DESTROY, + WM_COMMAND_WORKSPACE_RENAME, + WM_COMMAND_WORKSPACE_SET_LAYOUT, + WM_COMMAND_WORKSPACE_ADJUST_MASTER_RATIO, + WM_COMMAND_WORKSPACE_ADJUST_MASTER_COUNT, + WM_COMMAND_WORKSPACE_SWAP, + + /* Client manipulation */ + WM_COMMAND_CLIENT_SWAP, + WM_COMMAND_CLIENT_SWAP_MASTER, + WM_COMMAND_CLIENT_CYCLE, + WM_COMMAND_CLIENT_CYCLE_REVERSE, + + /* System commands */ + WM_COMMAND_RELOAD_CONFIG, + WM_COMMAND_QUIT, + WM_COMMAND_RESTART, + + /* Plugin commands */ + WM_COMMAND_PLUGIN_LOAD, + WM_COMMAND_PLUGIN_UNLOAD, + WM_COMMAND_PLUGIN_ENABLE, + WM_COMMAND_PLUGIN_DISABLE +} WmCommandType; + +/*============================================================================== + * Result/Error Types + *============================================================================*/ + +typedef enum { + WM_RESULT_OK = 0, + WM_RESULT_ERROR_GENERIC = -1, + WM_RESULT_ERROR_INVALID_ARG = -2, + WM_RESULT_ERROR_NO_MEMORY = -3, + WM_RESULT_ERROR_NOT_FOUND = -4, + WM_RESULT_ERROR_EXISTS = -5, + WM_RESULT_ERROR_PERMISSION = -6, + WM_RESULT_ERROR_NOT_SUPPORTED = -7, + WM_RESULT_ERROR_NOT_IMPLEMENTED = -8, + WM_RESULT_ERROR_BACKEND = -9, + WM_RESULT_ERROR_PLUGIN = -10, + WM_RESULT_ERROR_TIMEOUT = -11, + WM_RESULT_ERROR_CANCELED = -12 +} WmResult; + +/*============================================================================== + * Callback Types + *============================================================================*/ + +typedef void (*WmDestroyFunc)(void *data); +typedef int (*WmCompareFunc)(const void *a, const void *b); +typedef uint32_t (*WmHashFunc)(const void *key); +typedef void* (*WmCloneFunc)(const void *data); +typedef void (*WmEventHandler)(WmEventType type, const void *event_data, void *user_data); +typedef void (*WmTimerCallback)(WmTimer *timer, void *user_data); +typedef void* (*WmThreadFunc)(void *arg); + +/*============================================================================== + * Memory Management Types + *============================================================================*/ + +typedef void* (*WmAllocFunc)(size_t size); +typedef void* (*WmReallocFunc)(void *ptr, size_t old_size, size_t new_size); +typedef void (*WmFreeFunc)(void *ptr); + +typedef struct { + WmAllocFunc alloc; + WmReallocFunc realloc; + WmFreeFunc free; +} WmAllocator; + +/*============================================================================== + * Logging Types + *============================================================================*/ + +typedef enum { + WM_LOG_LEVEL_DEBUG, + WM_LOG_LEVEL_INFO, + WM_LOG_LEVEL_WARN, + WM_LOG_LEVEL_ERROR, + WM_LOG_LEVEL_FATAL +} WmLogLevel; + +typedef void (*WmLogHandler)(WmLogLevel level, const char *file, int line, + const char *func, const char *message); + +#ifdef __cplusplus +} +#endif + +#endif /* WM_TYPES_H */ diff --git a/include/core/wm_workspace.h b/include/core/wm_workspace.h new file mode 100644 index 0000000..7deb499 --- /dev/null +++ b/include/core/wm_workspace.h @@ -0,0 +1,161 @@ +/* + * DWN - Desktop Window Manager + * Abstract Workspace Interface + */ + +#ifndef WM_WORKSPACE_H +#define WM_WORKSPACE_H + +#include "wm_types.h" +#include "wm_client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Workspace Configuration + *============================================================================*/ + +#define WM_MAX_WORKSPACES 32 + +typedef struct { + WmLayoutType layout_type; + float master_ratio; + int master_count; + char name[64]; + bool persistent; + WmString *custom_data; +} WmWorkspaceConfig; + +/*============================================================================== + * Workspace Lifecycle + *============================================================================*/ + +bool wm_workspace_exists(WmCore *core, WmWorkspaceId id); +WmWorkspaceId wm_workspace_create(WmCore *core, const char *name); +void wm_workspace_destroy(WmCore *core, WmWorkspaceId id); + +void wm_workspace_init_all(WmCore *core); +void wm_workspace_cleanup_all(WmCore *core); + +/*============================================================================== + * Workspace Properties + *============================================================================*/ + +const char* wm_workspace_get_name(WmCore *core, WmWorkspaceId id); +void wm_workspace_set_name(WmCore *core, WmWorkspaceId id, const char *name); + +bool wm_workspace_is_empty(WmCore *core, WmWorkspaceId id); +size_t wm_workspace_get_client_count(WmCore *core, WmWorkspaceId id); + +/*============================================================================== + * Current Workspace + *============================================================================*/ + +WmWorkspaceId wm_workspace_get_current(WmCore *core); +void wm_workspace_set_current(WmCore *core, WmWorkspaceId id); +void wm_workspace_switch(WmCore *core, WmWorkspaceId id); + +void wm_workspace_switch_next(WmCore *core); +void wm_workspace_switch_prev(WmCore *core); + +/*============================================================================== + * Client Management + *============================================================================*/ + +void wm_workspace_add_client(WmCore *core, WmWorkspaceId id, AbstractClient *client); +void wm_workspace_remove_client(WmCore *core, WmWorkspaceId id, AbstractClient *client); +void wm_workspace_move_client(WmCore *core, AbstractClient *client, WmWorkspaceId to_workspace); + +WmContainer* wm_workspace_get_clients(WmCore *core, WmWorkspaceId id); + +AbstractClient* wm_workspace_get_focused_client(WmCore *core, WmWorkspaceId id); +void wm_workspace_set_focused_client(WmCore *core, WmWorkspaceId id, AbstractClient *client); + +AbstractClient* wm_workspace_get_first_client(WmCore *core, WmWorkspaceId id); +AbstractClient* wm_workspace_get_last_client(WmCore *core, WmWorkspaceId id); + +/*============================================================================== + * Layout Management + *============================================================================*/ + +WmLayoutType wm_workspace_get_layout(WmCore *core, WmWorkspaceId id); +void wm_workspace_set_layout(WmCore *core, WmWorkspaceId id, WmLayoutType layout); +void wm_workspace_cycle_layout(WmCore *core, WmWorkspaceId id); +void wm_workspace_cycle_layout_reverse(WmCore *core, WmWorkspaceId id); + +float wm_workspace_get_master_ratio(WmCore *core, WmWorkspaceId id); +void wm_workspace_set_master_ratio(WmCore *core, WmWorkspaceId id, float ratio); +void wm_workspace_adjust_master_ratio(WmCore *core, WmWorkspaceId id, float delta); + +int wm_workspace_get_master_count(WmCore *core, WmWorkspaceId id); +void wm_workspace_set_master_count(WmCore *core, WmWorkspaceId id, int count); +void wm_workspace_adjust_master_count(WmCore *core, WmWorkspaceId id, int delta); + +/*============================================================================== + * Workspace Arrangement + *============================================================================*/ + +void wm_workspace_arrange(WmCore *core, WmWorkspaceId id); +void wm_workspace_arrange_all(WmCore *core); +void wm_workspace_arrange_current(WmCore *core); + +WmRect wm_workspace_get_arrange_area(WmCore *core, WmWorkspaceId id); + +/*============================================================================== + * Workspace Visibility + *============================================================================*/ + +void wm_workspace_show(WmCore *core, WmWorkspaceId id); +void wm_workspace_hide(WmCore *core, WmWorkspaceId id); +bool wm_workspace_is_visible(WmCore *core, WmWorkspaceId id); + +/*============================================================================== + * Focus Management + *============================================================================*/ + +void wm_workspace_focus_next(WmCore *core, WmWorkspaceId id); +void wm_workspace_focus_prev(WmCore *core, WmWorkspaceId id); +void wm_workspace_focus_master(WmCore *core, WmWorkspaceId id); + +/*============================================================================== + * MRU (Most Recently Used) Stack + *============================================================================*/ + +void wm_workspace_mru_push(WmCore *core, WmWorkspaceId id, AbstractClient *client); +void wm_workspace_mru_remove(WmCore *core, WmWorkspaceId id, AbstractClient *client); +AbstractClient* wm_workspace_mru_get_next(WmCore *core, WmWorkspaceId id, AbstractClient *current); +AbstractClient* wm_workspace_mru_get_prev(WmCore *core, WmWorkspaceId id, AbstractClient *current); + +/*============================================================================== + * Alt-Tab Navigation + *============================================================================*/ + +void wm_workspace_alt_tab_start(WmCore *core, WmWorkspaceId id); +void wm_workspace_alt_tab_next(WmCore *core, WmWorkspaceId id); +void wm_workspace_alt_tab_prev(WmCore *core, WmWorkspaceId id); +void wm_workspace_alt_tab_end(WmCore *core, WmWorkspaceId id); +bool wm_workspace_alt_tab_is_active(WmCore *core, WmWorkspaceId id); + +/*============================================================================== + * Workspace Iteration + *============================================================================*/ + +WmWorkspaceId wm_workspace_get_first(WmCore *core); +WmWorkspaceId wm_workspace_get_last(WmCore *core); +WmWorkspaceId wm_workspace_get_next(WmCore *core, WmWorkspaceId id); +WmWorkspaceId wm_workspace_get_prev(WmCore *core, WmWorkspaceId id); + +/*============================================================================== + * Configuration + *============================================================================*/ + +void wm_workspace_save_config(WmCore *core, WmWorkspaceId id, const WmWorkspaceConfig *config); +bool wm_workspace_load_config(WmCore *core, WmWorkspaceId id, WmWorkspaceConfig *config); + +#ifdef __cplusplus +} +#endif + +#endif /* WM_WORKSPACE_H */ diff --git a/include/dwn.h b/include/dwn.h index 3a32cc7..366ad30 100644 --- a/include/dwn.h +++ b/include/dwn.h @@ -49,6 +49,9 @@ typedef enum { LAYOUT_TILING, LAYOUT_FLOATING, LAYOUT_MONOCLE, + LAYOUT_CENTERED_MASTER, + LAYOUT_COLUMNS, + LAYOUT_FIBONACCI, LAYOUT_COUNT } LayoutType; @@ -64,7 +67,8 @@ typedef enum { CLIENT_URGENT = (1 << 2), CLIENT_MINIMIZED = (1 << 3), CLIENT_STICKY = (1 << 4), - CLIENT_MAXIMIZED = (1 << 5) + CLIENT_MAXIMIZED = (1 << 5), + CLIENT_UNMANAGING = (1 << 6) /* Being destroyed, skip processing */ } ClientFlags; typedef enum { diff --git a/include/keys.h b/include/keys.h index e1b7c2e..9c9fb7b 100644 --- a/include/keys.h +++ b/include/keys.h @@ -89,6 +89,17 @@ void key_start_demo(void); void key_show_desktop(void); void key_move_to_workspace_prev(void); void key_move_to_workspace_next(void); +void key_kill_all_clients(void); +void key_move_window_left(void); +void key_move_window_right(void); +void key_move_window_up(void); +void key_move_window_down(void); +void key_resize_window_left(void); +void key_resize_window_right(void); +void key_resize_window_up(void); +void key_resize_window_down(void); +void key_set_mark(void); +void key_goto_mark(void); void tutorial_start(void); void tutorial_stop(void); diff --git a/include/layout.h b/include/layout.h index a83c881..aaae375 100644 --- a/include/layout.h +++ b/include/layout.h @@ -13,6 +13,9 @@ void layout_arrange(int workspace); void layout_arrange_tiling(int workspace); void layout_arrange_floating(int workspace); void layout_arrange_monocle(int workspace); +void layout_arrange_centered_master(int workspace); +void layout_arrange_columns(int workspace); +void layout_arrange_fibonacci(int workspace); int layout_get_usable_area(int *x, int *y, int *width, int *height); int layout_count_tiled_clients(int workspace); diff --git a/include/marks.h b/include/marks.h new file mode 100644 index 0000000..99548c9 --- /dev/null +++ b/include/marks.h @@ -0,0 +1,33 @@ +/* + * DWN - Desktop Window Manager + * retoor + * Window marks for quick navigation + */ + +#ifndef DWN_MARKS_H +#define DWN_MARKS_H + +#include "dwn.h" +#include + +#define MAX_MARKS 26 + +void marks_init(void); +void marks_cleanup(void); + +void marks_set(char mark, Client *client); +Client *marks_get(char mark); +void marks_clear(char mark); +void marks_clear_all(void); +void marks_remove_client(Client *client); + +bool marks_is_waiting_for_mark(void); +bool marks_is_waiting_for_goto(void); +void marks_start_set_mode(void); +void marks_start_goto_mode(void); +void marks_cancel_mode(void); +bool marks_handle_key(char key); + +char marks_get_mark_for_client(Client *client); + +#endif diff --git a/include/plugins/builtin_layouts.h b/include/plugins/builtin_layouts.h new file mode 100644 index 0000000..19dc605 --- /dev/null +++ b/include/plugins/builtin_layouts.h @@ -0,0 +1,57 @@ +/* + * DWN - Desktop Window Manager + * Built-in Layout Registration + */ + +#ifndef BUILTIN_LAYOUTS_H +#define BUILTIN_LAYOUTS_H + +#include "plugins/layout_plugin.h" +#include "dwn.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Initialize and register all built-in layouts. + * Called during DWN startup. + */ +bool wm_layouts_builtin_init(void); + +/** + * Get a layout plugin by legacy LayoutType. + */ +LayoutPlugin* wm_layout_get_by_type(LayoutManager *mgr, LayoutType type); + +/** + * Bridge function to arrange a workspace using the plugin system. + */ +bool wm_layout_arrange_workspace(LayoutManager *mgr, int workspace, LayoutType type); + +/** + * Get symbol for a layout type. + */ +const char* wm_layout_get_symbol_for_type(LayoutType type); + +/** + * Get name for a layout type. + */ +const char* wm_layout_get_name_for_type(LayoutType type); + +/** + * Get LayoutType from name. + */ +LayoutType wm_layout_type_from_name(const char *name); + +/* External layout interface getters */ +const LayoutPluginInterface* wm_layout_tiling_get_interface(void); +const LayoutPluginInterface* wm_layout_floating_get_interface(void); +const LayoutPluginInterface* wm_layout_monocle_get_interface(void); +const LayoutPluginInterface* wm_layout_grid_get_interface(void); + +#ifdef __cplusplus +} +#endif + +#endif /* BUILTIN_LAYOUTS_H */ diff --git a/include/plugins/layout_plugin.h b/include/plugins/layout_plugin.h new file mode 100644 index 0000000..3cc9b32 --- /dev/null +++ b/include/plugins/layout_plugin.h @@ -0,0 +1,365 @@ +/* + * DWN - Desktop Window Manager + * Layout Plugin Interface + */ + +#ifndef LAYOUT_PLUGIN_H +#define LAYOUT_PLUGIN_H + +#include "core/wm_types.h" +#include "core/wm_client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Layout Plugin API Version + *============================================================================*/ + +#define WM_LAYOUT_PLUGIN_API_VERSION 1 + +/*============================================================================== + * Forward Declarations + *============================================================================*/ + +typedef struct LayoutPlugin LayoutPlugin; +typedef struct LayoutContext LayoutContext; + +/*============================================================================== + * Layout Geometry + *============================================================================*/ + +/** + * Layout geometry for a single client. + */ +typedef struct { + int x, y; + int width, height; + bool floating; /* If true, layout doesn't manage this client */ + bool fullscreen; /* If true, client should be fullscreen */ + bool hidden; /* If true, client should be hidden */ +} WmLayoutGeometry; + +/** + * Work area for layout calculations. + */ +typedef struct { + int x, y; + int width, height; + int padding_top; + int padding_bottom; + int padding_left; + int padding_right; + int gap; +} WmLayoutWorkArea; + +/*============================================================================== + * Layout Configuration + *============================================================================*/ + +/** + * Layout configuration parameter. + */ +typedef struct { + const char *name; + const char *description; + union { + int int_value; + float float_value; + bool bool_value; + const char *string_value; + } default_value; + enum { + WM_LAYOUT_PARAM_INT, + WM_LAYOUT_PARAM_FLOAT, + WM_LAYOUT_PARAM_BOOL, + WM_LAYOUT_PARAM_STRING, + WM_LAYOUT_PARAM_CHOICE + } type; + /* For PARAM_CHOICE */ + const char **choices; + int num_choices; +} WmLayoutParameter; + +/** + * Layout configuration instance. + */ +typedef struct { + WmLayoutParameter *parameters; + int num_parameters; + void *user_data; /* Plugin can store parsed config here */ +} WmLayoutConfig; + +/*============================================================================== + * Layout State + *============================================================================*/ + +/** + * Opaque layout state per workspace. + * Layout plugins can store workspace-specific state here. + */ +typedef struct WmLayoutState WmLayoutState; + +/*============================================================================== + * Layout Context + *============================================================================*/ + +/** + * Context passed to layout operations. + */ +struct LayoutContext { + /* Workspace info */ + WmWorkspaceId workspace; + WmLayoutWorkArea work_area; + + /* Client counts */ + int client_count; + int master_count; + int stack_count; + + /* Layout parameters */ + float master_ratio; + int master_count_target; + int gap; + + /* Configuration */ + WmLayoutConfig *config; + + /* Layout state (managed by plugin) */ + WmLayoutState *state; + + /* User data (for plugin use) */ + void *user_data; +}; + +/*============================================================================== + * Layout Plugin Interface + *============================================================================*/ + +/** + * Layout plugin interface vtable. + * All layouts must implement these functions. + */ +typedef struct { + /* Version check */ + int api_version; + + /* Metadata */ + const char *name; + const char *description; + const char *author; + const char *version; + + /* Configuration */ + WmLayoutParameter *parameters; + int num_parameters; + + /* Lifecycle */ + bool (*init)(LayoutPlugin *plugin); + void (*shutdown)(LayoutPlugin *plugin); + + /* State management */ + WmLayoutState* (*state_create)(LayoutPlugin *plugin, WmWorkspaceId workspace); + void (*state_destroy)(LayoutPlugin *plugin, WmLayoutState *state); + void (*state_reset)(LayoutPlugin *plugin, WmLayoutState *state); + + /* Configuration */ + bool (*config_parse)(LayoutPlugin *plugin, WmLayoutConfig *config, + const char *key, const char *value); + void (*config_apply)(LayoutPlugin *plugin, WmLayoutConfig *config); + + /* Layout calculation */ + bool (*arrange)(LayoutPlugin *plugin, LayoutContext *ctx, + AbstractClient **clients, int num_clients, + WmLayoutGeometry *geometries); + + /* Client operations */ + void (*client_added)(LayoutPlugin *plugin, LayoutContext *ctx, + AbstractClient *client); + void (*client_removed)(LayoutPlugin *plugin, LayoutContext *ctx, + AbstractClient *client); + void (*client_floating_changed)(LayoutPlugin *plugin, LayoutContext *ctx, + AbstractClient *client, bool floating); + + /* Layout manipulation */ + void (*inc_master)(LayoutPlugin *plugin, LayoutContext *ctx, int delta); + void (*set_master_ratio)(LayoutPlugin *plugin, LayoutContext *ctx, float ratio); + void (*set_master_count)(LayoutPlugin *plugin, LayoutContext *ctx, int count); + void (*swap_master)(LayoutPlugin *plugin, LayoutContext *ctx); + void (*rotate)(LayoutPlugin *plugin, LayoutContext *ctx, bool clockwise); + + /* Mouse resizing support */ + void (*resize_master)(LayoutPlugin *plugin, LayoutContext *ctx, + int x, int y, int *new_master_count, float *new_ratio); + +} LayoutPluginInterface; + +/*============================================================================== + * Layout Plugin Structure + *============================================================================*/ + +/** + * Layout plugin instance. + */ +struct LayoutPlugin { + /* Interface vtable */ + const LayoutPluginInterface *interface; + + /* Plugin handle (for dynamic loading) */ + void *handle; + + /* Plugin path */ + char *path; + + /* Enabled state */ + bool enabled; + + /* Global configuration */ + WmLayoutConfig config; + + /* Per-workspace states */ + WmLayoutState **workspace_states; + int num_workspaces; + + /* Plugin-private data */ + void *user_data; +}; + +/*============================================================================== + * Layout Manager + *============================================================================*/ + +/** + * Layout manager handles all loaded layouts. + */ +typedef struct LayoutManager LayoutManager; + +/** + * Get the global layout manager. + */ +LayoutManager* wm_layout_manager_get(void); + +/** + * Initialize the layout manager. + */ +bool wm_layout_manager_init(void); + +/** + * Shutdown the layout manager. + */ +void wm_layout_manager_shutdown(void); + +/** + * Register a layout plugin. + */ +bool wm_layout_manager_register(LayoutManager *mgr, LayoutPlugin *plugin); + +/** + * Unregister a layout plugin. + */ +void wm_layout_manager_unregister(LayoutManager *mgr, LayoutPlugin *plugin); + +/** + * Load a layout plugin from a file. + */ +LayoutPlugin* wm_layout_manager_load(LayoutManager *mgr, const char *path); + +/** + * Unload a layout plugin. + */ +void wm_layout_manager_unload(LayoutManager *mgr, LayoutPlugin *plugin); + +/** + * Get a loaded layout by name. + */ +LayoutPlugin* wm_layout_manager_get_layout(LayoutManager *mgr, const char *name); + +/** + * Get the default layout. + */ +LayoutPlugin* wm_layout_manager_get_default(LayoutManager *mgr); + +/** + * Set the default layout. + */ +void wm_layout_manager_set_default(LayoutManager *mgr, LayoutPlugin *plugin); + +/** + * Get list of available layouts. + */ +const char** wm_layout_manager_list(LayoutManager *mgr, int *count); + +/*============================================================================== + * Layout Operations + *============================================================================*/ + +/** + * Apply a layout to a workspace. + */ +bool wm_layout_arrange(LayoutPlugin *plugin, WmWorkspaceId workspace); + +/** + * Apply layout to specific clients. + */ +bool wm_layout_arrange_clients(LayoutPlugin *plugin, LayoutContext *ctx, + AbstractClient **clients, int num_clients); + +/** + * Create a layout context for a workspace. + */ +bool wm_layout_context_init(LayoutContext *ctx, WmWorkspaceId workspace); + +/** + * Clean up a layout context. + */ +void wm_layout_context_cleanup(LayoutContext *ctx); + +/*============================================================================== + * Built-in Layouts + *============================================================================*/ + +/* Tiling layout */ +extern const LayoutPluginInterface wm_layout_tiling; + +/* Floating layout */ +extern const LayoutPluginInterface wm_layout_floating; + +/* Monocle (maximized) layout */ +extern const LayoutPluginInterface wm_layout_monocle; + +/* Grid layout */ +extern const LayoutPluginInterface wm_layout_grid; + +/* Spiral layout */ +extern const LayoutPluginInterface wm_layout_spiral; + +/* Dwindle layout */ +extern const LayoutPluginInterface wm_layout_dwindle; + +/*============================================================================== + * Plugin Entry Point + *============================================================================*/ + +/** + * Layout plugins must export this function. + */ +typedef const LayoutPluginInterface* (*LayoutPluginEntryFunc)(void); + +#define WM_LAYOUT_PLUGIN_ENTRY "wm_layout_plugin_entry" + +/*============================================================================== + * Helper Macros + *============================================================================*/ + +#define WM_LAYOUT_REGISTER(name, iface) \ + __attribute__((unused)) static const LayoutPluginInterface* wm_layout_plugin_entry(void) { return &(iface); } + +/* Typedef for built-in layout getters */ +typedef const LayoutPluginInterface* (*WmLayoutBuiltinFunc)(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LAYOUT_PLUGIN_H */ diff --git a/include/plugins/widget_plugin.h b/include/plugins/widget_plugin.h new file mode 100644 index 0000000..2e36d02 --- /dev/null +++ b/include/plugins/widget_plugin.h @@ -0,0 +1,435 @@ +/* + * DWN - Desktop Window Manager + * Widget Plugin Interface + * Panel components (taskbar, clock, workspaces, etc.) + */ + +#ifndef WIDGET_PLUGIN_H +#define WIDGET_PLUGIN_H + +#include "core/wm_types.h" +#include "core/wm_client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Widget Plugin API Version + *============================================================================*/ + +#define WM_WIDGET_PLUGIN_API_VERSION 1 + +/*============================================================================== + * Forward Declarations + *============================================================================*/ + +typedef struct WidgetPlugin WidgetPlugin; +typedef struct WidgetContext WidgetContext; +typedef struct WidgetInstance WidgetInstance; + +/*============================================================================== + * Widget Position + *============================================================================*/ + +typedef enum { + WM_WIDGET_POSITION_LEFT, + WM_WIDGET_POSITION_CENTER, + WM_WIDGET_POSITION_RIGHT +} WmWidgetPosition; + +/*============================================================================== + * Widget Size Constraints + *============================================================================*/ + +typedef struct { + int min_width; + int min_height; + int max_width; + int max_height; + bool expand_horizontal; /* Take available horizontal space */ + bool expand_vertical; /* Take available vertical space */ +} WmWidgetConstraints; + +/*============================================================================== + * Widget Geometry + *============================================================================*/ + +typedef struct { + int x, y; + int width, height; +} WmWidgetGeometry; + +/*============================================================================== + * Widget State + *============================================================================*/ + +typedef enum { + WM_WIDGET_STATE_NORMAL = 0, + WM_WIDGET_STATE_HOVERED = (1 << 0), + WM_WIDGET_STATE_PRESSED = (1 << 1), + WM_WIDGET_STATE_ACTIVE = (1 << 2), + WM_WIDGET_STATE_DISABLED = (1 << 3), + WM_WIDGET_STATE_HIDDEN = (1 << 4), + WM_WIDGET_STATE_URGENT = (1 << 5) +} WmWidgetState; + +/*============================================================================== + * Widget Context + *============================================================================*/ + +struct WidgetContext { + /* Position in panel */ + WmWidgetPosition position; + + /* Geometry */ + WmWidgetGeometry geometry; + WmWidgetConstraints constraints; + + /* Panel info */ + WmRect panel_geometry; + bool is_top_panel; + + /* Rendering context */ + void *render_context; /* Backend-specific (X11 GC, cairo, etc.) */ + WmColor bg_color; + WmColor fg_color; + + /* Font */ + void *font; /* Opaque font handle */ + int font_size; + + /* User data */ + void *user_data; +}; + +/*============================================================================== + * Widget Event Types + *============================================================================*/ + +typedef enum { + WM_WIDGET_EVENT_NONE, + WM_WIDGET_EVENT_MOUSE_ENTER, + WM_WIDGET_EVENT_MOUSE_LEAVE, + WM_WIDGET_EVENT_MOUSE_MOVE, + WM_WIDGET_EVENT_BUTTON_PRESS, + WM_WIDGET_EVENT_BUTTON_RELEASE, + WM_WIDGET_EVENT_SCROLL, + WM_WIDGET_EVENT_KEY_PRESS, + WM_WIDGET_EVENT_FOCUS_IN, + WM_WIDGET_EVENT_FOCUS_OUT, + WM_WIDGET_EVENT_UPDATE, /* Request to redraw */ + WM_WIDGET_EVENT_CONFIGURE, /* Size/position changed */ + WM_WIDGET_EVENT_DATA_CHANGED /* External data changed */ +} WmWidgetEventType; + +typedef struct { + WmWidgetEventType type; + WmWidgetGeometry widget_geometry; + union { + struct { int x, y; } point; + struct { int button; int x, y; } button; + struct { int delta; bool horizontal; } scroll; + struct { unsigned int keycode; unsigned int state; } key; + } data; +} WmWidgetEvent; + +/*============================================================================== + * Widget Configuration + *============================================================================*/ + +typedef struct { + const char *name; + const char *value; +} WmWidgetConfigOption; + +typedef struct { + WmWidgetConfigOption *options; + int num_options; +} WmWidgetConfig; + +/*============================================================================== + * Widget Information + *============================================================================*/ + +typedef struct { + const char *id; /* Unique identifier */ + const char *name; /* Display name */ + const char *description; /* Description */ + const char *author; /* Author */ + const char *version; /* Version */ + + /* Default constraints */ + WmWidgetConstraints default_constraints; + + /* Default position */ + WmWidgetPosition default_position; + + /* Configuration schema */ + const char **config_options; /* List of accepted config option names */ + int num_config_options; +} WmWidgetInfo; + +/*============================================================================== + * Widget Plugin Interface + *============================================================================*/ + +typedef struct { + /* Version check */ + int api_version; + + /* Metadata */ + WmWidgetInfo info; + + /* Lifecycle */ + bool (*init)(WidgetPlugin *plugin); + void (*shutdown)(WidgetPlugin *plugin); + + /* Instance management */ + WidgetInstance* (*instance_create)(WidgetPlugin *plugin, + const WmWidgetConfig *config); + void (*instance_destroy)(WidgetPlugin *plugin, WidgetInstance *instance); + void (*instance_configure)(WidgetPlugin *plugin, WidgetInstance *instance, + const WmWidgetConfig *config); + + /* Rendering */ + void (*render)(WidgetPlugin *plugin, WidgetInstance *instance, + WidgetContext *ctx); + + /* Event handling */ + bool (*handle_event)(WidgetPlugin *plugin, WidgetInstance *instance, + const WmWidgetEvent *event); + + /* Update notification */ + void (*update)(WidgetPlugin *plugin, WidgetInstance *instance); + + /* Size calculation */ + void (*get_preferred_size)(WidgetPlugin *plugin, WidgetInstance *instance, + int *width, int *height); + +} WidgetPluginInterface; + +/*============================================================================== + * Widget Instance + *============================================================================*/ + +struct WidgetInstance { + /* Plugin that created this instance */ + WidgetPlugin *plugin; + + /* Instance state */ + WmWidgetState state; + WmWidgetGeometry geometry; + WmWidgetConstraints constraints; + + /* Configuration */ + WmWidgetConfig config; + + /* Context */ + WidgetContext *context; + + /* Plugin-private data */ + void *user_data; + + /* Linked list for panel */ + WidgetInstance *next; + WidgetInstance *prev; +}; + +/*============================================================================== + * Widget Plugin Structure + *============================================================================*/ + +struct WidgetPlugin { + /* Interface vtable */ + const WidgetPluginInterface *interface; + + /* Plugin handle (for dynamic loading) */ + void *handle; + + /* Plugin path */ + char *path; + + /* Enabled state */ + bool enabled; + + /* Instances */ + WidgetInstance *instances; + int instance_count; + + /* Plugin-private data */ + void *user_data; +}; + +/*============================================================================== + * Widget Manager + *============================================================================*/ + +typedef struct WidgetManager WidgetManager; + +/** + * Get the global widget manager. + */ +WidgetManager* wm_widget_manager_get(void); + +/** + * Initialize the widget manager. + */ +bool wm_widget_manager_init(void); + +/** + * Shutdown the widget manager. + */ +void wm_widget_manager_shutdown(void); + +/** + * Register a widget plugin. + */ +bool wm_widget_manager_register(WidgetManager *mgr, WidgetPlugin *plugin); + +/** + * Unregister a widget plugin. + */ +void wm_widget_manager_unregister(WidgetManager *mgr, WidgetPlugin *plugin); + +/** + * Load a widget plugin from a file. + */ +WidgetPlugin* wm_widget_manager_load(WidgetManager *mgr, const char *path); + +/** + * Unload a widget plugin. + */ +void wm_widget_manager_unload(WidgetManager *mgr, WidgetPlugin *plugin); + +/** + * Get a loaded widget by ID. + */ +WidgetPlugin* wm_widget_manager_get_widget(WidgetManager *mgr, const char *id); + +/** + * Get list of available widgets. + */ +const char** wm_widget_manager_list(WidgetManager *mgr, int *count); + +/*============================================================================== + * Widget Instance Operations + *============================================================================*/ + +/** + * Create a widget instance. + */ +WidgetInstance* wm_widget_create_instance(WidgetPlugin *plugin, + const WmWidgetConfig *config); + +/** + * Destroy a widget instance. + */ +void wm_widget_destroy_instance(WidgetInstance *instance); + +/** + * Render a widget instance. + */ +void wm_widget_render(WidgetInstance *instance, WidgetContext *ctx); + +/** + * Send an event to a widget instance. + */ +bool wm_widget_send_event(WidgetInstance *instance, const WmWidgetEvent *event); + +/** + * Update a widget instance (request redraw). + */ +void wm_widget_update(WidgetInstance *instance); + +/** + * Get preferred size for a widget instance. + */ +void wm_widget_get_preferred_size(WidgetInstance *instance, + int *width, int *height); + +/*============================================================================== + * Widget Panel Integration + *============================================================================*/ + +typedef struct WidgetPanel WidgetPanel; + +/** + * Create a widget panel (container for widget instances). + */ +WidgetPanel* wm_widget_panel_create(void); + +/** + * Destroy a widget panel. + */ +void wm_widget_panel_destroy(WidgetPanel *panel); + +/** + * Add a widget instance to a panel. + */ +void wm_widget_panel_add(WidgetPanel *panel, WidgetInstance *instance, + WmWidgetPosition position); + +/** + * Remove a widget instance from a panel. + */ +void wm_widget_panel_remove(WidgetPanel *panel, WidgetInstance *instance); + +/** + * Arrange widgets in a panel. + */ +void wm_widget_panel_arrange(WidgetPanel *panel, const WmRect *panel_geometry); + +/** + * Render all widgets in a panel. + */ +void wm_widget_panel_render(WidgetPanel *panel); + +/** + * Handle mouse event in a panel. + */ +bool wm_widget_panel_handle_event(WidgetPanel *panel, + const WmWidgetEvent *event); + +/*============================================================================== + * Built-in Widgets + *============================================================================*/ + +/* Workspace switcher widget */ +extern const WidgetPluginInterface wm_widget_workspaces; + +/* Taskbar widget */ +extern const WidgetPluginInterface wm_widget_taskbar; + +/* Clock widget */ +extern const WidgetPluginInterface wm_widget_clock; + +/* System tray widget */ +extern const WidgetPluginInterface wm_widget_systray; + +/* CPU/Memory monitor widget */ +extern const WidgetPluginInterface wm_widget_system_stats; + +/* News ticker widget */ +extern const WidgetPluginInterface wm_widget_news; + +/*============================================================================== + * Plugin Entry Point + *============================================================================*/ + +typedef const WidgetPluginInterface* (*WidgetPluginEntryFunc)(void); + +#define WM_WIDGET_PLUGIN_ENTRY "wm_widget_plugin_entry" + +/*============================================================================== + * Helper Macros + *============================================================================*/ + +#define WM_WIDGET_REGISTER(name, iface) \ + static const WidgetPluginInterface* wm_widget_plugin_entry(void) { return &(iface); } + +#ifdef __cplusplus +} +#endif + +#endif /* WIDGET_PLUGIN_H */ diff --git a/include/rules.h b/include/rules.h new file mode 100644 index 0000000..4c03379 --- /dev/null +++ b/include/rules.h @@ -0,0 +1,61 @@ +/* + * DWN - Desktop Window Manager + * retoor + * Window rules engine for auto-applying settings + */ + +#ifndef DWN_RULES_H +#define DWN_RULES_H + +#include "dwn.h" +#include + +#define MAX_RULES 64 +#define RULE_PATTERN_SIZE 128 + +typedef enum { + RULE_MATCH_CLASS, + RULE_MATCH_TITLE, + RULE_MATCH_CLASS_AND_TITLE +} RuleMatchType; + +typedef struct { + RuleMatchType match_type; + char class_pattern[RULE_PATTERN_SIZE]; + char title_pattern[RULE_PATTERN_SIZE]; + + bool has_workspace; + int workspace; + + bool has_floating; + bool floating; + + bool has_sticky; + bool sticky; + + bool has_fullscreen; + bool fullscreen; + + bool has_size; + int width; + int height; + + bool has_position; + int x; + int y; + + bool has_opacity; + float opacity; +} WindowRule; + +void rules_init(void); +void rules_cleanup(void); +bool rules_load(const char *path); +void rules_add(const WindowRule *rule); +void rules_clear(void); +int rules_count(void); + +bool rules_apply_to_client(Client *client); +bool rules_match_pattern(const char *str, const char *pattern); + +#endif diff --git a/include/slider.h b/include/slider.h new file mode 100644 index 0000000..434610b --- /dev/null +++ b/include/slider.h @@ -0,0 +1,72 @@ +/* + * DWN - Desktop Window Manager + * retoor + * Generic slider widget for panel controls + */ + +#ifndef DWN_SLIDER_H +#define DWN_SLIDER_H + +#include "dwn.h" +#include + +#define SLIDER_WIDTH 30 +#define SLIDER_HEIGHT 120 +#define SLIDER_PADDING 8 +#define SLIDER_KNOB_HEIGHT 8 + +/* Forward declaration */ +typedef struct GenericSlider GenericSlider; + +/* Callback type for value changes */ +typedef void (*SliderValueChangedCallback)(GenericSlider *slider, int value); + +/* Generic slider structure */ +struct GenericSlider { + Window window; + int x, y; + int width, height; + bool visible; + bool dragging; + + /* Value (always 0-100 internally) */ + int value; + + /* Display */ + const char *label_prefix; + bool show_percentage; + + /* Callback */ + SliderValueChangedCallback on_value_changed; + void *user_data; +}; + +/* Lifecycle */ +GenericSlider *slider_create(int x, int y, + const char *label_prefix, + bool show_percentage, + SliderValueChangedCallback callback, + void *user_data); +void slider_destroy(GenericSlider *slider); + +/* Visibility */ +void slider_show(GenericSlider *slider, int x, int y); +void slider_hide(GenericSlider *slider); +bool slider_is_visible(const GenericSlider *slider); + +/* Rendering */ +void slider_render(GenericSlider *slider); + +/* Event handling */ +void slider_handle_click(GenericSlider *slider, int x, int y); +void slider_handle_motion(GenericSlider *slider, int x, int y); +void slider_handle_release(GenericSlider *slider); + +/* Value */ +void slider_set_value(GenericSlider *slider, int value); +int slider_get_value(const GenericSlider *slider); + +/* Hit testing */ +bool slider_hit_test(const GenericSlider *slider, int x, int y); + +#endif diff --git a/include/systray.h b/include/systray.h index ae89a87..9dff486 100644 --- a/include/systray.h +++ b/include/systray.h @@ -8,6 +8,7 @@ #define DWN_SYSTRAY_H #include "dwn.h" +#include "slider.h" #include #define MAX_TRAY_ICONS 32 @@ -84,12 +85,22 @@ typedef struct { bool dragging; } VolumeSlider; +/* Generic slider wrapper for fade controls */ +typedef struct { + GenericSlider *slider; + int icon_x; /* Position for popup */ +} FadeControl; + extern WifiState wifi_state; extern AudioState audio_state; extern BatteryState battery_state; extern MultiBatteryState multi_battery_state; extern VolumeSlider *volume_slider; +/* Fade control externs */ +extern FadeControl fade_speed_control; +extern FadeControl fade_intensity_control; + void systray_init(void); void systray_cleanup(void); @@ -113,6 +124,15 @@ void volume_slider_handle_click(VolumeSlider *slider, int x, int y); void volume_slider_handle_motion(VolumeSlider *slider, int x, int y); void volume_slider_handle_release(VolumeSlider *slider); +/* Fade control functions */ +void fade_controls_init(void); +void fade_controls_cleanup(void); +void fade_controls_render(Panel *panel, int x); +int fade_controls_get_width(void); +void fade_controls_handle_click(int control_id, int x, int y, int button); +int fade_controls_hit_test(int x); +void fade_controls_hide_all(void); + void systray_render(Panel *panel, int x, int *width); int systray_get_width(void); void systray_handle_click(int x, int y, int button); diff --git a/include/thread_workers.h b/include/thread_workers.h new file mode 100644 index 0000000..71652e1 --- /dev/null +++ b/include/thread_workers.h @@ -0,0 +1,263 @@ +/* + * DWN - Desktop Window Manager + * retoor + * Specialized Worker Threads - High-Level API + * + * Pre-built worker types for common async operations: + * - I/O Worker: File operations, networking + * - Compute Worker: CPU-intensive tasks + * - System Worker: /proc monitoring, system stats + * - Deferred Worker: Delayed/scheduled execution + */ + +#ifndef DWN_THREAD_WORKERS_H +#define DWN_THREAD_WORKERS_H + +#include "threading.h" + +/* ============================================================================ + * I/O Worker - Async File and Network Operations + * ============================================================================ */ + +typedef void (*IoCallback)(void *result, size_t size, int error, void *user_data); +typedef void (*IoProgressCallback)(size_t processed, size_t total, void *user_data); + +/** + * Initialize I/O worker subsystem + */ +bool io_worker_init(void); + +/** + * Shutdown I/O worker subsystem + */ +void io_worker_shutdown(void); + +/** + * Read file asynchronously + * @param path File path + * @param callback Called with file contents + * @param user_data Passed to callback + * @return Task handle or NULL + */ +TaskHandle io_read_file_async(const char *path, IoCallback callback, void *user_data); + +/** + * Write file asynchronously + */ +TaskHandle io_write_file_async(const char *path, const void *data, size_t size, + IoCallback callback, void *user_data); + +/** + * Read directory contents asynchronously + * Result is a null-separated list of filenames + */ +TaskHandle io_read_dir_async(const char *path, IoCallback callback, void *user_data); + +/** + * HTTP GET request asynchronously + * @param url URL to fetch + * @param callback Called with response body + * @param user_data Passed to callback + * @return Task handle or NULL + */ +TaskHandle io_http_get_async(const char *url, IoCallback callback, void *user_data); + +/** + * HTTP POST request asynchronously + */ +TaskHandle io_http_post_async(const char *url, const void *data, size_t size, + IoCallback callback, void *user_data); + +/** + * Download file with progress callback + */ +TaskHandle io_download_async(const char *url, const char *dest_path, + IoProgressCallback progress, + IoCallback callback, void *user_data); + +/* ============================================================================ + * Compute Worker - CPU-Intensive Tasks + * ============================================================================ */ + +typedef void (*ComputeCallback)(void *result, void *user_data); + +/** + * Initialize compute worker subsystem + */ +bool compute_worker_init(void); + +/** + * Shutdown compute worker subsystem + */ +void compute_worker_shutdown(void); + +/** + * Parallel for - distribute work across threads + * @param start Start index + * @param end End index (exclusive) + * @param func Function called for each index + * @param user_data Passed to each invocation + */ +void compute_parallel_for(int start, int end, + void (*func)(int index, void *user_data), + void *user_data); + +/** + * Map operation - apply function to each element + */ +void* compute_map(void *array, size_t count, size_t elem_size, + void (*func)(void *in, void *out, void *user_data), + void *user_data); + +/** + * Reduce operation - aggregate values + */ +void* compute_reduce(void *array, size_t count, size_t elem_size, + void (*func)(void *accum, void *elem, void *user_data), + void *initial, void *user_data); + +/** + * Submit compute task + */ +TaskHandle compute_submit(void (*func)(void *user_data), void *user_data, + ComputeCallback callback, void *callback_data); + +/* ============================================================================ + * System Worker - System Monitoring + * ============================================================================ */ + +typedef struct { + float cpu_percent; + uint64_t memory_used; + uint64_t memory_total; + float memory_percent; + float load_avg[3]; + uint64_t uptime_seconds; +} SystemStats; + +typedef struct { + uint32_t pid; + char name[64]; + float cpu_percent; + uint64_t memory_bytes; +} ProcessInfo; + +typedef void (*SystemStatsCallback)(const SystemStats *stats, void *user_data); +typedef void (*ProcessListCallback)(ProcessInfo *processes, uint32_t count, void *user_data); + +/** + * Initialize system worker + */ +bool system_worker_init(void); + +/** + * Shutdown system worker + */ +void system_worker_shutdown(void); + +/** + * Get cached system stats (non-blocking, updated periodically) + */ +bool system_worker_get_cached_stats(SystemStats *stats); + +/** + * Get fresh system stats (blocking) + */ +Future* system_worker_get_stats_async(void); + +/** + * Get process list asynchronously + */ +TaskHandle system_worker_get_processes_async(ProcessListCallback callback, void *user_data); + +/** + * Subscribe to periodic stats updates + * @param interval_ms Update interval (0 to disable) + * @param callback Called with new stats + * @param user_data Passed to callback + * @return Subscription ID + */ +uint32_t system_worker_subscribe_stats(uint32_t interval_ms, + SystemStatsCallback callback, + void *user_data); + +/** + * Unsubscribe from stats updates + */ +bool system_worker_unsubscribe_stats(uint32_t subscription_id); + +/* ============================================================================ + * Deferred Worker - Delayed Execution + * ============================================================================ */ + +typedef uint64_t DeferredId; +typedef void (*DeferredCallback)(DeferredId id, void *user_data); + +/** + * Initialize deferred worker + */ +bool deferred_worker_init(void); + +/** + * Shutdown deferred worker + */ +void deferred_worker_shutdown(void); + +/** + * Execute after delay + * @param delay_ms Milliseconds to wait + * @param callback Function to call + * @param user_data Passed to callback + * @return Deferred ID + */ +DeferredId deferred_after(uint64_t delay_ms, DeferredCallback callback, void *user_data); + +/** + * Execute at regular interval + */ +DeferredId deferred_every(uint64_t interval_ms, DeferredCallback callback, void *user_data); + +/** + * Cancel deferred execution + */ +bool deferred_cancel(DeferredId id); + +/** + * Process deferred tasks (call from main loop) + * @return Number of tasks executed + */ +uint32_t deferred_process(void); + +/** + * Get poll fd for select() + */ +int deferred_get_poll_fd(void); + +/* ============================================================================ + * High-Level Integration API + * ============================================================================ */ + +/** + * Initialize all worker subsystems + */ +bool thread_workers_init(void); + +/** + * Shutdown all worker subsystems + */ +void thread_workers_shutdown(void); + +/** + * Process all pending async work (call from main loop) + * @return true if work was processed + */ +bool thread_workers_process_all(void); + +/** + * Get combined poll fds for select() + * @param fds Array to fill (size at least 4) + * @return Number of fds filled + */ +int thread_workers_get_poll_fds(int *fds); + +#endif /* DWN_THREAD_WORKERS_H */ diff --git a/include/threading.h b/include/threading.h new file mode 100644 index 0000000..e81fdc9 --- /dev/null +++ b/include/threading.h @@ -0,0 +1,704 @@ +/* + * DWN - Desktop Window Manager + * retoor + * Extensive Abstract Threading Framework + * + * This module provides a comprehensive, abstract threading system with: + * - Lock-free data structures + * - Thread pools with work stealing + * - Async/await pattern support + * - Thread-safe event bus + * - Memory barriers and atomic operations + */ + +#ifndef DWN_THREADING_H +#define DWN_THREADING_H + +#include +#include +#include +#include +#include + +/* ============================================================================ + * Platform Abstraction Layer + * ============================================================================ */ + +/* Cache line size (commonly 64 bytes on x86_64) */ +#define CACHE_LINE_SIZE 64 + +/* Align to cache line to prevent false sharing */ +#define CACHE_ALIGN __attribute__((aligned(CACHE_LINE_SIZE))) + +/* Memory ordering shortcuts */ +#define ATOMIC_RELAXED memory_order_relaxed +#define ATOMIC_ACQUIRE memory_order_acquire +#define ATOMIC_RELEASE memory_order_release +#define ATOMIC_ACQ_REL memory_order_acq_rel +#define ATOMIC_SEQ_CST memory_order_seq_cst + +/* ============================================================================ + * Core Types and Status Codes + * ============================================================================ */ + +typedef enum { + THREAD_OK = 0, + THREAD_ERROR = -1, + THREAD_ERROR_NOMEM = -2, + THREAD_ERROR_BUSY = -3, + THREAD_ERROR_CLOSED = -4, + THREAD_ERROR_TIMEOUT = -5, + THREAD_ERROR_INVALID = -6 +} ThreadStatus; + +typedef enum { + TASK_PRIORITY_CRITICAL = 0, /* UI-critical, must execute immediately */ + TASK_PRIORITY_HIGH = 1, /* User-initiated actions */ + TASK_PRIORITY_NORMAL = 2, /* Default background work */ + TASK_PRIORITY_LOW = 3, /* Maintenance tasks */ + TASK_PRIORITY_IDLE = 4, /* Only when system idle */ + TASK_PRIORITY_COUNT +} TaskPriority; + +typedef enum { + TASK_STATE_PENDING = 0, + TASK_STATE_RUNNING = 1, + TASK_STATE_COMPLETED = 2, + TASK_STATE_CANCELLED = 3, + TASK_STATE_ERROR = 4 +} TaskState; + +/* Forward declarations */ +typedef struct ThreadPool ThreadPool; +typedef struct Task Task; +typedef struct Channel Channel; +typedef struct Future Future; +typedef struct EventBus EventBus; +typedef struct AsyncContext AsyncContext; +typedef struct Worker Worker; + +/* ============================================================================ + * Task System - Abstract Unit of Work + * ============================================================================ */ + +/* Task function signature - receives user data and cancellation flag */ +typedef void (*TaskFunc)(void *user_data, atomic_int *cancelled); + +/* Callback for task completion (called in worker thread) */ +typedef void (*TaskCallback)(Task *task, void *user_data, ThreadStatus status); + +/* Task handle - opaque pointer */ +typedef Task* TaskHandle; + +/** + * Create a new task + * @param func The function to execute + * @param user_data Data passed to the function + * @param priority Task priority level + * @return Task handle or NULL on error + */ +TaskHandle task_create(TaskFunc func, void *user_data, TaskPriority priority); + +/** + * Create a task with completion callback + */ +TaskHandle task_create_with_callback(TaskFunc func, void *user_data, + TaskPriority priority, + TaskCallback on_complete, + void *callback_data); + +/** + * Destroy a task (only if not submitted) + */ +void task_destroy(TaskHandle task); + +/** + * Cancel a task (best effort - may already be running) + */ +bool task_cancel(TaskHandle task); + +/** + * Get current task state + */ +TaskState task_get_state(TaskHandle task); + +/** + * Wait for task completion (blocking) + */ +ThreadStatus task_wait(TaskHandle task, uint64_t timeout_ms); + +/** + * Check if task was cancelled + */ +bool task_is_cancelled(TaskHandle task); + +/* ============================================================================ + * Thread Pool - Manage Worker Threads + * ============================================================================ */ + +/* Thread pool configuration */ +typedef struct { + uint32_t min_threads; /* Minimum threads to keep alive */ + uint32_t max_threads; /* Maximum threads allowed */ + uint32_t queue_capacity; /* Task queue capacity per priority */ + uint32_t steal_attempts; /* Work stealing attempts before blocking */ + uint64_t idle_timeout_ms; /* Time before idle thread terminates */ + bool enable_work_stealing; /* Enable work stealing between queues */ +} ThreadPoolConfig; + +/* Default configuration */ +#define THREAD_POOL_DEFAULT_CONFIG ((ThreadPoolConfig){ \ + .min_threads = 2, \ + .max_threads = 8, \ + .queue_capacity = 256, \ + .steal_attempts = 4, \ + .idle_timeout_ms = 60000, \ + .enable_work_stealing = true \ +}) + +/** + * Create a thread pool + */ +ThreadPool* thread_pool_create(const ThreadPoolConfig *config); + +/** + * Destroy thread pool, cancelling pending tasks + */ +void thread_pool_destroy(ThreadPool *pool); + +/** + * Submit a task to the pool + */ +ThreadStatus thread_pool_submit(ThreadPool *pool, TaskHandle task); + +/** + * Submit a function as a task (convenience) + */ +ThreadStatus thread_pool_submit_func(ThreadPool *pool, TaskFunc func, + void *user_data, TaskPriority priority); + +/** + * Get number of active threads + */ +uint32_t thread_pool_active_count(ThreadPool *pool); + +/** + * Get number of pending tasks + */ +uint32_t thread_pool_pending_count(ThreadPool *pool); + +/** + * Shutdown pool gracefully, waiting for tasks to complete + */ +ThreadStatus thread_pool_shutdown(ThreadPool *pool, uint64_t timeout_ms); + +/** + * Get the default/global thread pool + */ +ThreadPool* thread_pool_default(void); + +/** + * Initialize the default thread pool + */ +ThreadStatus thread_pool_init_default(const ThreadPoolConfig *config); + +/** + * Shutdown the default thread pool + */ +void thread_pool_shutdown_default(void); + +/* ============================================================================ + * Lock-Free Queue - Single Producer Single Consumer + * ============================================================================ */ + +#define SPSC_QUEUE_SIZE 1024 + +typedef struct { + _Atomic uint64_t head CACHE_ALIGN; /* Write index - producer only */ + _Atomic uint64_t tail CACHE_ALIGN; /* Read index - consumer only */ + void *buffer[SPSC_QUEUE_SIZE]; +} SpscQueue; + +/** + * Initialize SPSC queue + */ +void spsc_queue_init(SpscQueue *q); + +/** + * Push item (producer only) + * @return false if queue full + */ +bool spsc_queue_push(SpscQueue *q, void *item); + +/** + * Pop item (consumer only) + * @return false if queue empty + */ +bool spsc_queue_pop(SpscQueue *q, void **item); + +/** + * Check if queue is empty (consumer only) + */ +bool spsc_queue_empty(SpscQueue *q); + +/** + * Get approximate size (not synchronized) + */ +uint64_t spsc_queue_size_approx(SpscQueue *q); + +/* ============================================================================ + * Lock-Free Queue - Multi Producer Single Consumer + * ============================================================================ */ + +typedef struct MpscQueue MpscQueue; + +/** + * Create MPSC queue + */ +MpscQueue* mpsc_queue_create(uint32_t capacity); + +/** + * Destroy MPSC queue + */ +void mpsc_queue_destroy(MpscQueue *q); + +/** + * Push item (thread-safe, any producer) + * @return false if queue full + */ +bool mpsc_queue_push(MpscQueue *q, void *item); + +/** + * Pop item (consumer only - single thread) + * @return false if queue empty + */ +bool mpsc_queue_pop(MpscQueue *q, void **item); + +/** + * Check if queue is empty + */ +bool mpsc_queue_empty(MpscQueue *q); + +/* ============================================================================ + * Channel - Thread-Safe Communication + * ============================================================================ */ + +typedef enum { + CHANNEL_UNBUFFERED = 0, /* Synchronous - sender blocks until received */ + CHANNEL_BUFFERED = 1 /* Asynchronous - uses internal buffer */ +} ChannelType; + +/** + * Create a channel + * @param capacity Buffer size (0 for unbuffered synchronous channel) + */ +Channel* channel_create(uint32_t capacity); + +/** + * Destroy channel + */ +void channel_destroy(Channel *ch); + +/** + * Send data through channel (blocking) + * @return THREAD_OK on success, THREAD_ERROR_CLOSED if closed + */ +ThreadStatus channel_send(Channel *ch, void *data); + +/** + * Send with timeout + */ +ThreadStatus channel_send_timeout(Channel *ch, void *data, uint64_t timeout_ms); + +/** + * Try send (non-blocking) + */ +ThreadStatus channel_try_send(Channel *ch, void *data); + +/** + * Receive from channel (blocking) + */ +ThreadStatus channel_recv(Channel *ch, void **data); + +/** + * Receive with timeout + */ +ThreadStatus channel_recv_timeout(Channel *ch, void **data, uint64_t timeout_ms); + +/** + * Try receive (non-blocking) + */ +ThreadStatus channel_try_recv(Channel *ch, void **data); + +/** + * Close channel (no more sends allowed) + */ +void channel_close(Channel *ch); + +/** + * Check if channel is closed + */ +bool channel_is_closed(Channel *ch); + +/** + * Select on multiple channels (like Go's select) + * Returns index of ready channel or -1 on timeout + */ +int channel_select(Channel **channels, uint32_t count, uint64_t timeout_ms, + void **out_data); + +/* ============================================================================ + * Future/Promise - Async Result Handling + * ============================================================================ */ + +typedef void* FutureResult; +typedef void (*FutureCallback)(Future *f, FutureResult result, void *user_data); + +/** + * Create a future + */ +Future* future_create(void); + +/** + * Destroy future + */ +void future_destroy(Future *f); + +/** + * Set the result (called by producer) + */ +void future_set_result(Future *f, FutureResult result); + +/** + * Set error result + */ +void future_set_error(Future *f, int error_code); + +/** + * Get result (blocking) + */ +FutureResult future_get(Future *f, ThreadStatus *status); + +/** + * Get result with timeout + */ +FutureResult future_get_timeout(Future *f, uint64_t timeout_ms, ThreadStatus *status); + +/** + * Check if future is ready + */ +bool future_is_ready(Future *f); + +/** + * Attach callback to be called when ready (thread-safe) + */ +void future_then(Future *f, FutureCallback callback, void *user_data); + +/** + * Create future that completes when all given futures complete + */ +Future* future_all(Future **futures, uint32_t count); + +/** + * Create future that completes when any given future completes + */ +Future* future_any(Future **futures, uint32_t count); + +/* ============================================================================ + * Event Bus - Thread-Safe Pub/Sub + * ============================================================================ */ + +typedef uint32_t EventType; +typedef uint32_t SubscriptionId; + +/* Event handler signature */ +typedef void (*EventHandler)(EventType type, void *event_data, void *user_data); + +/* Event filter - return true to allow event */ +typedef bool (*EventFilter)(EventType type, void *event_data, void *user_data); + +/** + * Create event bus + */ +EventBus* event_bus_create(void); + +/** + * Destroy event bus + */ +void event_bus_destroy(EventBus *bus); + +/** + * Subscribe to event type + * @return Subscription ID or 0 on error + */ +SubscriptionId event_bus_subscribe(EventBus *bus, EventType type, + EventHandler handler, void *user_data); + +/** + * Subscribe with filter + */ +SubscriptionId event_bus_subscribe_filtered(EventBus *bus, EventType type, + EventHandler handler, void *user_data, + EventFilter filter, void *filter_data); + +/** + * Unsubscribe + */ +bool event_bus_unsubscribe(EventBus *bus, SubscriptionId id); + +/** + * Publish event (thread-safe) + */ +void event_bus_publish(EventBus *bus, EventType type, void *event_data); + +/** + * Publish event with custom free function + */ +void event_bus_publish_owned(EventBus *bus, EventType type, void *event_data, + void (*free_fn)(void*)); + +/** + * Process pending events (call from main thread) + * @return number of events processed + */ +uint32_t event_bus_process(EventBus *bus); + +/** + * Set processing limit per call + */ +void event_bus_set_batch_size(EventBus *bus, uint32_t batch_size); + +/** + * Get the global/default event bus + */ +EventBus* event_bus_default(void); + +/** + * Initialize default event bus + */ +bool event_bus_init_default(void); + +/** + * Shutdown default event bus + */ +void event_bus_shutdown_default(void); + +/* ============================================================================ + * Async Context - Per-Module Async State + * ============================================================================ */ + +/* Context for managing async operations within a module */ +struct AsyncContext { + ThreadPool *pool; + EventBus *event_bus; + Channel *completion_channel; + atomic_int operation_count; + atomic_int shutdown_requested; + pthread_mutex_t mutex; +}; + +/** + * Create async context + */ +AsyncContext* async_context_create(const char *name); + +/** + * Destroy async context (cancels all pending operations) + */ +void async_context_destroy(AsyncContext *ctx); + +/** + * Submit work to context's thread pool + */ +TaskHandle async_submit(AsyncContext *ctx, TaskFunc func, void *user_data, + TaskPriority priority); + +/** + * Submit work and get future + */ +Future* async_submit_future(AsyncContext *ctx, TaskFunc func, void *user_data, + TaskPriority priority); + +/** + * Check for completed operations (call from main thread) + */ +uint32_t async_poll(AsyncContext *ctx); + +/** + * Get file descriptor for select() integration + * Returns -1 if not available + */ +int async_get_poll_fd(AsyncContext *ctx); + +/* ============================================================================ + * Timer/Scheduler - Delayed Execution + * ============================================================================ */ + +typedef uint64_t TimerId; +typedef void (*TimerCallback)(TimerId id, void *user_data); + +/** + * Schedule one-shot timer + */ +TimerId timer_schedule(uint64_t delay_ms, TimerCallback callback, void *user_data); + +/** + * Schedule repeating timer + */ +TimerId timer_schedule_repeating(uint64_t interval_ms, TimerCallback callback, + void *user_data); + +/** + * Cancel timer + */ +bool timer_cancel(TimerId id); + +/** + * Check if timer exists + */ +bool timer_exists(TimerId id); + +/** + * Process timer events (call from main thread) + * @return Number of timers fired + */ +uint32_t timer_process(void); + +/** + * Get timer file descriptor for select() + */ +int timer_get_poll_fd(void); + +/** + * Initialize timer subsystem + */ +bool timer_init(void); + +/** + * Shutdown timer subsystem + */ +void timer_shutdown(void); + +/* ============================================================================ + * Thread-Local Storage Abstraction + * ============================================================================ */ + +typedef struct TlsKey TlsKey; + +/** + * Create TLS key + */ +TlsKey* tls_create(void (*destructor)(void*)); + +/** + * Destroy TLS key + */ +void tls_destroy(TlsKey *key); + +/** + * Set TLS value + */ +void tls_set(TlsKey *key, void *value); + +/** + * Get TLS value + */ +void* tls_get(TlsKey *key); + +/* ============================================================================ + * Read-Write Lock Wrapper + * ============================================================================ */ + +typedef struct RwLock RwLock; + +RwLock* rwlock_create(void); +void rwlock_destroy(RwLock *lock); +void rwlock_read_lock(RwLock *lock); +bool rwlock_read_trylock(RwLock *lock); +void rwlock_read_unlock(RwLock *lock); +void rwlock_write_lock(RwLock *lock); +bool rwlock_write_trylock(RwLock *lock); +void rwlock_write_unlock(RwLock *lock); + +/* ============================================================================ + * Barrier and Synchronization + * ============================================================================ */ + +typedef struct Barrier Barrier; + +Barrier* barrier_create(uint32_t count); +void barrier_destroy(Barrier *b); +bool barrier_wait(Barrier *b, uint64_t timeout_ms); + +/* ============================================================================ + * Initialization and Cleanup + * ============================================================================ */ + +/** + * Initialize entire threading subsystem + */ +bool threading_init(void); + +/** + * Shutdown entire threading subsystem + */ +void threading_shutdown(void); + +/** + * Get number of hardware threads + */ +uint32_t threading_hw_concurrency(void); + +/** + * Current thread ID + */ +uint64_t threading_current_thread_id(void); + +/** + * Set current thread name (for debugging) + */ +void threading_set_name(const char *name); + +/** + * Yield current thread + */ +void threading_yield(void); + +/* ============================================================================ + * Utility Macros + * ============================================================================ */ + +/* Run function in background */ +#define ASYNC(func, data) \ + thread_pool_submit_func(thread_pool_default(), (func), (data), TASK_PRIORITY_NORMAL) + +/* Run function with priority */ +#define ASYNC_PRIORITY(func, data, prio) \ + thread_pool_submit_func(thread_pool_default(), (func), (data), (prio)) + +/* Create future and submit */ +#define ASYNC_FUTURE(ctx, func, data) \ + async_submit_future((ctx), (func), (data), TASK_PRIORITY_NORMAL) + +/* Synchronized block using mutex */ +#define WITH_MUTEX(mutex, code) do { \ + pthread_mutex_lock(&(mutex)); \ + code; \ + pthread_mutex_unlock(&(mutex)); \ +} while(0) + +/* Read lock block */ +#define WITH_READ_LOCK(rwlock, code) do { \ + rwlock_read_lock((rwlock)); \ + code; \ + rwlock_read_unlock((rwlock)); \ +} while(0) + +/* Write lock block */ +#define WITH_WRITE_LOCK(rwlock, code) do { \ + rwlock_write_lock((rwlock)); \ + code; \ + rwlock_write_unlock((rwlock)); \ +} while(0) + +#endif /* DWN_THREADING_H */ diff --git a/include/threading_integration.h b/include/threading_integration.h new file mode 100644 index 0000000..1e1bfa9 --- /dev/null +++ b/include/threading_integration.h @@ -0,0 +1,75 @@ +/* + * DWN - Desktop Window Manager + * retoor + * Threading Integration Header + */ + +#ifndef DWN_THREADING_INTEGRATION_H +#define DWN_THREADING_INTEGRATION_H + +#include "threading.h" +#include "thread_workers.h" +#include + +/** + * Initialize threading integration with main loop + */ +bool threading_integration_init(void); + +/** + * Shutdown threading integration + */ +void threading_integration_shutdown(void); + +/** + * Prepare fd_set for select() - adds threading fds + */ +void threading_integration_prepare_select(int xfd, fd_set *fds, int *max_fd); + +/** + * Process threading events after select() returns + */ +void threading_integration_process(fd_set *fds); + +/** + * Non-blocking poll for async work + */ +void threading_integration_poll(void); + +/** + * Run one iteration with integrated threading + */ +void threading_integration_run_iteration(int xfd, void (*handle_xevent)(void)); + +/** + * Get stats string for display + */ +void threading_integration_get_stats(char *buf, size_t bufsize); + +/** + * Initialize per-module async contexts + */ +bool threading_integration_init_module_contexts(void); + +/** + * Cleanup per-module async contexts + */ +void threading_integration_cleanup_module_contexts(void); + +/** + * Get module-specific async contexts + */ +AsyncContext* threading_integration_get_ai_context(void); +AsyncContext* threading_integration_get_screenshot_context(void); +AsyncContext* threading_integration_get_ocr_context(void); + +/** + * High-level task submission + */ +TaskHandle threading_integration_submit_ai(TaskFunc func, void *user_data); +TaskHandle threading_integration_submit_screenshot(TaskFunc func, void *user_data); +TaskHandle threading_integration_submit_ocr(TaskFunc func, void *user_data); +TaskHandle threading_integration_submit_ui(TaskFunc func, void *user_data); +TaskHandle threading_integration_submit_background(TaskFunc func, void *user_data); + +#endif /* DWN_THREADING_INTEGRATION_H */ diff --git a/include/util.h b/include/util.h index 5858f9f..6236dd0 100644 --- a/include/util.h +++ b/include/util.h @@ -11,6 +11,7 @@ #include #include #include +#include #define DWN_ASSERT(cond) assert(cond) #define DWN_ASSERT_MSG(cond, msg) assert((cond) && (msg)) @@ -46,6 +47,27 @@ bool str_ends_with(const char *str, const char *suffix); int str_split(char *str, char delim, char **parts, int max_parts); char *shell_escape(const char *str); +/* Safe string copy that always null-terminates */ +static inline void safe_strncpy(char *dest, const char *src, size_t n) +{ + if (n == 0) return; + size_t src_len = strlen(src); + size_t copy_len = (src_len < n - 1) ? src_len : n - 1; + memcpy(dest, src, copy_len); + dest[copy_len] = '\0'; +} + +/* Check if value is within valid range */ +static inline bool in_range_int(int val, int min, int max) +{ + return val >= min && val <= max; +} + +static inline bool in_range_size_t(size_t val, size_t min, size_t max) +{ + return val >= min && val <= max; +} + bool file_exists(const char *path); char *file_read_all(const char *path); bool file_write_all(const char *path, const char *content); diff --git a/manual/abstraction-layer.html b/manual/abstraction-layer.html new file mode 100644 index 0000000..78704cc --- /dev/null +++ b/manual/abstraction-layer.html @@ -0,0 +1,305 @@ + + + + + + Abstraction Layer - DWN Documentation + + + + + +
+ + +
+
+ + + + +

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 TypeX11 EquivalentDescription
WmWindowHandleWindowOpaque window reference
WmClientId-Unique client identifier
WmWorkspaceIdintWorkspace identifier
WmRect-Rectangle geometry (x, y, w, h)
WmColorunsigned longRGBA 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:

+ +
    +
  1. Phase 1: Infrastructure (Complete) +
      +
    • Core types defined
    • +
    • Backend interface specified
    • +
    • X11 backend implemented
    • +
    +
  2. +
  3. Phase 2: Client Migration (Complete) +
      +
    • AbstractClient type created
    • +
    • Bidirectional sync with legacy Client
    • +
    • Client manager with MRU tracking
    • +
    +
  4. +
  5. Phase 3: Plugin System (Complete) +
      +
    • Layout plugin API
    • +
    • Widget plugin API
    • +
    • 4 built-in layout plugins
    • +
    +
  6. +
  7. Phase 4: Future +
      +
    • Gradual migration of existing code
    • +
    • Wayland backend implementation
    • +
    • Legacy code deprecation (long-term)
    • +
    +
  8. +
+ +
+ Note: The abstraction layer is fully backward compatible. Existing code using X11 types continues to work unchanged. +
+ +
+

DWN Window Manager - retoor <retoor@molodetz.nl>

+
+
+
+
+ + + + diff --git a/manual/ai-features.html b/manual/ai-features.html index 33c4295..39a573c 100644 --- a/manual/ai-features.html +++ b/manual/ai-features.html @@ -13,7 +13,7 @@