From 8fe783e3044e2107c882c422113515838f66229c Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Tue, 31 Mar 2026 13:55:24 +0200 Subject: [PATCH] =?UTF-8?q?wayland:=20Phase=2030=20=E2=80=94=20native=20Wa?= =?UTF-8?q?yland=20dock=20panel=20via=20wm=5Fshm=5Fsurface?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the Phase 29 test square with a proper dock panel anchored to the right edge of the primary output. The panel is rendered entirely via pixman into a wm_shm_surface and uploaded to the wlroots scene graph — no X11 drawing resources needed. Visual design: - Dark charcoal background (0xFF1C1C1C) - 1-px left-edge highlight (0xFF404040) separating dock from desktop - 1-px top separator (0xFF303030) - Column of bevelled icon-slot placeholders (top/left highlight + bottom/right shadow) at icon_size × icon_size spacing Layout and sizing: - Width = icon_size + 4 px (default 68 px for 64-px icons) - Height = full output height - X position = output_width - dock_width (flush to right edge) - n_slots = (height - 4) / (icon_size + 2) (16 slots @ 1080p) Usable area: - head-0 x2 shrunk by dock_width so window placement never overlaps The WDock X11 code path remains disabled (nodock=1) — icon population and click handling come in later phases. Smoke test: PASS ("dock panel created at 1852,0 (68x1080, 16 slots)") Co-Authored-By: Claude Sonnet 4.6 --- src/backend/wayland/wl_backend.c | 141 ++++++++++++++++++++++++++++--- tests/wl-smoke-test.sh | 12 ++- 2 files changed, 137 insertions(+), 16 deletions(-) diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index cab478e..c83c4c7 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -393,6 +393,9 @@ struct wl_compositor_state { /* Phase 29 axis listeners (headless pointer + real nested pointer). */ struct wl_listener pointer_axis_listener; struct wl_listener real_pointer_axis_listener; + /* Phase 30: WM dock panel (native Wayland rendering via wm_shm_surface). */ + struct wm_shm_surface *dock_surface; /* NULL until screen_create_internals */ + int dock_width; /* pixels reserved on right edge */ }; static struct wl_compositor_state wl_state; @@ -2556,6 +2559,127 @@ wm_shm_surface_destroy(struct wm_shm_surface *s) wlr_buffer_drop(&s->wlr_buf); /* producer done; shm_buf_destroy frees s */ } +/* ================================================================== */ +/* Phase 30: WM dock panel (layer-anchored, pixman-rendered) */ +/* ================================================================== */ + +/* + * The dock is a vertical strip anchored to the right edge of the primary + * output. It is rendered into a wm_shm_surface whose pixels flow through + * the wlroots scene graph, exactly like any other WM UI element. + * + * Layout (right edge, full screen height): + * + * ┌──────────────────────────────────────────────────┬────────┐ + * │ │ ██████ │ + * │ desktop / client windows │ ██████ │ + * │ (constrained to usable area) │ ██████ │ + * │ │ dock │ + * └──────────────────────────────────────────────────┴────────┘ + * ← dw → + * + * The usable area (where windows are placed) is shrunk by dock_width so + * clients never overlap the panel. + */ + +/* Default width when wPreferences.icon_size is not yet set. */ +#define WM_DOCK_DEFAULT_WIDTH 68 /* 64 px icon + 4 px border */ + +/* Colours (ARGB8888, fully opaque) */ +#define WM_DOCK_BG 0xFF1C1C1C /* dark charcoal background */ +#define WM_DOCK_HIGHLIGHT 0xFF404040 /* 1-px highlight on left edge */ +#define WM_DOCK_TOPSEP 0xFF303030 /* 1-px separator at top */ +#define WM_DOCK_TILE_BG 0xFF252525 /* icon-slot background */ +#define WM_DOCK_TILE_HI 0xFF353535 /* icon-slot top/left highlight */ +#define WM_DOCK_TILE_SH 0xFF151515 /* icon-slot bottom/right shadow */ + +/* wm_dock_render_tile — paint one icon slot starting at (x, y). + * Slots are icon_size × icon_size with a 1-px inset bevel. */ +static void +wm_dock_render_tile(struct wm_shm_surface *s, + int x, int y, int tile_sz) +{ + /* Background */ + wm_shm_surface_fill(s, x, y, tile_sz, tile_sz, WM_DOCK_TILE_BG); + /* Top highlight */ + wm_shm_surface_fill(s, x, y, tile_sz, 1, WM_DOCK_TILE_HI); + /* Left highlight */ + wm_shm_surface_fill(s, x, y, 1, tile_sz, WM_DOCK_TILE_HI); + /* Bottom shadow */ + wm_shm_surface_fill(s, x, y + tile_sz - 1, tile_sz, 1, WM_DOCK_TILE_SH); + /* Right shadow */ + wm_shm_surface_fill(s, x + tile_sz - 1, y, 1, tile_sz, WM_DOCK_TILE_SH); +} + +/* wm_dock_render — paint the full dock panel. + * Draws the background, left-edge highlight, top separator, and a column + * of empty icon slots to give visual structure before real icons arrive. */ +static void +wm_dock_render(struct wm_shm_surface *s, int icon_sz, int n_slots) +{ + int w = s->width; + int h = s->height; + int tile_sz = icon_sz; + int pad = (w - tile_sz) / 2; /* horizontal centering margin */ + + /* Background */ + wm_shm_surface_fill(s, 0, 0, w, h, WM_DOCK_BG); + + /* Left-edge highlight (the dock's inner border with the desktop) */ + wm_shm_surface_fill(s, 0, 0, 1, h, WM_DOCK_HIGHLIGHT); + + /* Top separator */ + wm_shm_surface_fill(s, 0, 0, w, 1, WM_DOCK_TOPSEP); + + /* Icon-slot placeholders */ + for (int i = 0; i < n_slots; i++) { + int ty = 2 + i * (tile_sz + 2); + if (ty + tile_sz > h) + break; + wm_dock_render_tile(s, pad, ty, tile_sz); + } +} + +/* wm_dock_create — allocate the dock surface, render it, attach to scene, + * and shrink the head-0 usable area by dock_width pixels on the right. */ +static void +wm_dock_create(WScreen *scr) +{ + if (!wl_state.scene || !wl_state.output) + return; + + int sw = (int)wl_state.output->width; + int sh = (int)wl_state.output->height; + int icon_sz = (wPreferences.icon_size > 0) + ? wPreferences.icon_size : 64; + int dw = icon_sz + 4; /* dock width = icon + 2px pad each side */ + int n_slots = (sh - 4) / (icon_sz + 2); /* how many slots fit */ + + struct wm_shm_surface *s = wm_shm_surface_create(dw, sh); + if (!s) { + wwarning("wl_backend: wm_dock_create: failed to allocate surface"); + return; + } + + wm_dock_render(s, icon_sz, n_slots); + wm_shm_surface_commit(s, &wl_state.scene->node, sw - dw, 0); + + wl_state.dock_surface = s; + wl_state.dock_width = dw; + + /* Shrink head-0 usable area so window placement avoids the dock. */ + if (scr->usableArea) { + int right = scr->usableArea[0].x2 - dw; + if (right < scr->usableArea[0].x1) + right = scr->usableArea[0].x1; + scr->usableArea[0].x2 = right; + scr->totalUsableArea[0].x2 = right; + } + + wwarning("wl_backend: dock panel created at %d,0 (%dx%d, %d slots)", + sw - dw, dw, sh, n_slots); +} + /* ------------------------------------------------------------------ */ /* Screen open/close */ /* ------------------------------------------------------------------ */ @@ -4056,22 +4180,15 @@ wl_screen_create_internals(WScreen *scr) wSetModifierMasks(Mod1Mask, Mod1Mask, Mod4Mask, 0); - /* Dock/clip require X11 rendering resources not yet available in Wayland - * mode. Disable until native Wayland dock rendering is implemented. */ + /* Phase 30: the WDock X11 code path is still disabled (it needs X11 GCs / + * pixmaps we don't have in pure Wayland mode). The visual dock panel is + * created below via wm_dock_create() which uses wm_shm_surface directly. */ wPreferences.flags.noclip = 1; wPreferences.flags.nodock = 1; wwarning("wl_backend: dock/clip disabled pending native Wayland rendering"); - /* Phase 29 smoke test: create a 64×64 steel-blue surface at (16,16) to - * verify the pixman → wlr_scene_buffer pipeline produces visible pixels. */ - if (wl_state.scene) { - struct wm_shm_surface *test_surf = wm_shm_surface_create(64, 64); - if (test_surf) { - wm_shm_surface_fill(test_surf, 0, 0, 64, 64, 0xFF4080C0); /* steel-blue */ - wm_shm_surface_commit(test_surf, &wl_state.scene->node, 16, 16); - wwarning("wl_backend: Phase 29 test surface committed (64x64 steel-blue at 16,16)"); - } - } + /* Phase 30: create the native Wayland dock panel. */ + wm_dock_create(scr); } static void wl_screen_create_pixmaps(WScreen *scr) { (void)scr; } static void wl_screen_load_tech_font(WScreen *scr) { (void)scr; } diff --git a/tests/wl-smoke-test.sh b/tests/wl-smoke-test.sh index 601f69f..ab441af 100755 --- a/tests/wl-smoke-test.sh +++ b/tests/wl-smoke-test.sh @@ -320,13 +320,17 @@ grep -q 'pointer motion/button/frame listeners wired' /tmp/wl-smoke-stderr \ || die "compositor did not log pointer listeners wired" echo " ptr listener check: pointer motion/button/frame listeners wired" -# -- 4f. Phase 11: dock/clip disabled in Wayland mode -------------------- +# -- 4f. Phase 30: dock panel rendered via wm_shm_surface ---------------- # -# wl_screen_create_internals always sets noclip=1 nodock=1 until native -# Wayland dock rendering is implemented. +# wl_screen_create_internals calls wm_dock_create() which logs +# "dock panel created at X,0 (WxH, N slots)". +# WDock X11 code path is still disabled (noclip/nodock=1). grep -q 'dock/clip disabled' /tmp/wl-smoke-stderr \ || die "compositor did not log dock/clip disabled (wl_screen_create_internals broken?)" -echo " nodock check: dock/clip disabled pending native Wayland rendering" +grep -q 'dock panel created' /tmp/wl-smoke-stderr \ + || die "compositor did not log dock panel creation (wm_dock_create failed?)" +DOCK_INFO=$(grep -o 'dock panel created at [0-9]*,0 ([^)]*)' /tmp/wl-smoke-stderr | head -1) +echo " nodock check: dock/clip disabled; ${DOCK_INFO:-dock panel created}" # -- 4f2b. Phase 25: clipboard selection wired ---------------------------- grep -q 'clipboard selection wired' /tmp/wl-smoke-stderr \