Commit Graph

17 Commits

Author SHA1 Message Date
Levi Neely 2d3d6d4716 wayland: Phase 47 — prop_get_normal_hints from XDG toplevel constraints
Implement wl_prop_get_normal_hints: look up the wl_toplevel_view, read
wlr_xdg_toplevel::current.{min,max}_{width,height} for WNH_P_MIN/MAX_SIZE
flags, and report the current committed surface size as WNH_P_SIZE so
wManageWindow/wClientGetNormalHints sees real constraints.

Returns 1 if any flags were set, 0 if the view has no constraints.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 06:49:58 +01:00
Levi Neely fc0e233865 wayland: Phase 46 — client_close vtable; title updates; protocol guards
Add client_close vtable slot to WMBackend:
  - x11: XKillClient + XFlush
  - wl: wlr_xdg_toplevel_send_close (politely asks client to close)
  - wClientKill: use wm_backend->client_close() for Wayland path

Guard wClientSendProtocol with if (!dpy) return so it is safe to call
on Wayland windows (protocols.DELETE_WINDOW is always 0 for Wayland).

Wire XDG toplevel set_title signal: add title_listener to
wl_toplevel_view; handle_toplevel_title updates wwin->wm_class /
wm_instance when the client changes its title, and calls
wWindowUpdateName (which no-ops on frameless windows but posts
WMNChangedName when a frame is present).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 06:46:46 +01:00
Levi Neely 69cee6fb15 wayland: Phase 45 — pointer_query returns on-screen; focus path guarded
pointer_query / pointer_query_full: return 1 when compositor is running
(wl_state.started) so the same_screen check in wManageWindow passes and
wSetFocusTo is called for newly mapped XDG toplevels.

Guard frame-dependent calls in the focus update path:
  - wWindowFocus (window.c): guard wFrameWindowChangeState on frame!=NULL
  - wWindowUnfocus (window.c): same; also guard wFrameWindowPaint on
    owner->frame when clearing semi-focus on transient owner

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 06:43:16 +01:00
Levi Neely 4574fe8873 wayland: Phase 44 — client_synth_configure/window_resize send XDG configure
Implement three vtable slots:
  - client_synth_configure: calls wlr_xdg_toplevel_set_size + schedule_configure
    so the WM can resize/reposition XDG toplevel clients
  - window_resize: same — sends a configure with the new width/height
  - window_move: no-op comment (position is WM-side only for Wayland)

All three use wl_find_view_by_id to recover the wl_toplevel_view.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 06:41:17 +01:00
Levi Neely 0fe2960995 wayland: Phase 43 — focus_set delivers keyboard focus via wlr_seat
Create a headless keyboard input device during wl_display_open and
attach it to wlr_seat so wlr_seat_keyboard_notify_enter() can deliver
keyboard focus to XDG toplevel surfaces.

Implement wl_focus_set: look up the view by synthetic ID, call
wlr_seat_keyboard_notify_enter with the xdg_surface->surface.
Call wl_focus_set from handle_toplevel_map immediately after
wManageWindow so newly mapped toplevels receive keyboard focus.

Smoke test: add Phase 43 check — grep "focus_set id=" in stderr.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 06:40:16 +01:00
Levi Neely d9a70e9177 wayland: Phase 42 — window_get_client_attrs returns real map/geometry
Implement wl_window_get_client_attrs: look up the toplevel view, return
WCLIENT_VIEWABLE with width/height from wlr_surface.current for mapped
surfaces; WCLIENT_UNMAPPED for unknown IDs.

Extend the wManageWindow success log to include geo=WxH so the smoke
test can verify the geometry is non-zero after the client commits a frame.

Smoke test: add Phase 42 check — grep geo= and verify it is logged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 06:37:59 +01:00
Levi Neely 0ea33dc830 wayland: Phase 41 — prop_get_wm_class/window_fetch_name from XDG metadata
Add wl_find_view_by_id() helper that walks toplevel_list to recover a
wl_toplevel_view from its synthetic WNativeWindow ID.

Implement vtable slots:
  - prop_get_wm_class: returns XDG app_id as both WM_CLASS and WM_INSTANCE
  - window_fetch_name: returns XDG toplevel title

Extend the wManageWindow success log to include class= and name= so
the smoke test can verify these fields are populated from Wayland metadata.

Smoke test: add Phase 41 check — grep for
"class=org.freedesktop.weston.simple-shm" in manage log.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 06:36:22 +01:00
Levi Neely 490ecb34ff wayland: Phase 40 — wire toplevel unmap to wUnmanageWindow
Guard all dpy==NULL / frame==NULL crash sites in the unmanage path:
  - wUnmanageWindow (window.c): frame ptr set to NULL-safe expression;
    window_unmap, raise_delay timer, and owner border change all
    guarded on frame != NULL
  - wSelectWindow (actions.c): early return if !wwin->frame
  - wNETCleanupFrameExtents (wmspec.c): early return if !dpy
  - wClientRestore (client.c): early return if !dpy

Wire handle_toplevel_unmap → context_find → wUnmanageWindow(destroyed=True)
so XDG toplevels are removed from scr->focused_window on client disconnect.

Smoke test: add Phase 40 check — grep "toplevel unmapped".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 06:34:15 +01:00
Levi Neely ca09635129 wayland: Phase 39 — wire toplevel map to wManageWindow
Guard all dpy==NULL crash sites reached from wManageWindow:
  - wNETWMGetPidForWindow (wmspec.c) — XGetWindowProperty with NULL dpy
  - wNETWMCheckClientHints (wmspec.c) — XGetWindowProperty
  - wNETWMCheckInitialClientState (wmspec.c) — XChangeProperty chain
  - getMWMHints (motif.c) — XInternAtom before NULL dpy check
  - wClientSetState (client.c) — XChangeProperty
  - wColormapInstallForWindow (colormap.c) — XGetWindowAttributes
  - wWindowSetKeyGrabs (window.c) — frame->core->window dereference

Wire handle_toplevel_map → wManageWindow(scr, view->id) so mapped
XDG toplevels appear in scr->focused_window.  Log success via
"wl_backend: wManageWindow succeeded id=0x%lx".

Smoke test: add Phase 39 check — grep "wManageWindow succeeded".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 06:23:23 +01:00
Levi Neely 74a43f0180 wayland: Phase 38 — per-toplevel view lifecycle and context store
Introduce struct wl_toplevel_view with map/unmap/destroy wl_signal
listeners and a synthetic WNativeWindow ID (>= 0x10000000).
Implement context_save/find/delete as a per-key linked list of
(WNativeWindow, void*) entries — enables downstream policy code to
look up views by handle.  wl-smoke-test now verifies "toplevel mapped"
appears in compositor stderr when weston-simple-shm creates its surface.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 23:19:18 +01:00
Levi Neely 3e1fd061e9 wayland: Phase 37 — frame timer drives client frame callbacks at 60 fps
Replace the output frame listener + render pipeline approach (which
required a swapchain allocator) with a simple wl_event_loop timer that
calls wlr_output_send_frame every 16 ms.  Clients (weston-simple-shm)
now complete their render loops without the compositor needing a GPU
allocator.  Also schedule an initial xdg_surface configure on new
toplevels so they can commit their first buffer.  wl-smoke-test verifies
weston-simple-shm runs for 3 s without crashing the compositor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 23:15:59 +01:00
Levi Neely 2182ec0fc1 wayland: Phase 36 — wl_shm, wl_output, XDG toplevel listener
Advertise wl_shm (via wlr_renderer_init_wl_shm) and expose the headless
output as a wl_output global so SHM buffer clients can render.  Wire up
the xdg_shell new_surface listener to track incoming XDG toplevels
(management hook placeholder).  wl-smoke-test now verifies wl_shm and
wl_output in the registry and that weston-simple-shm can connect without
crashing the compositor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 23:12:21 +01:00
Levi Neely 075b648021 wayland: Phase 35 — advertise core Wayland protocol globals
Register wl_compositor (+ wl_subcompositor), wl_seat, wl_data_device_manager,
and xdg_wm_base in the compositor's global registry so that Wayland clients
can enumerate and bind them.  Add generated xdg-shell-protocol.{h,c} from
wayland-scanner.  wl-smoke-test now uses weston-info to verify all three
key globals are present.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 23:09:39 +01:00
Levi Neely 97a9209b4f wayland: Phase 34 — Wayland socket, output layout, real monitors_query
Create the compositor UNIX socket via wl_display_add_socket_auto so
Wayland clients can connect; store socket name and set WAYLAND_DISPLAY.
Add wlr_output_layout for multi-head tracking and implement monitors_query
to return real 1920x1080 head geometry from the headless output.
wl-smoke-test now verifies the socket file exists in XDG_RUNTIME_DIR.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 23:06:49 +01:00
Levi Neely f7dfc50f26 wayland: Phase 33 — event_loop_run/atom_intern vtable; wmaker starts and exits cleanly under Wayland
Add display_default_screen, atom_intern, and event_loop_run vtable slots.
Guard all X11-only paths in startup.c/screen.c/shutdown.c/event.c/xdnd.c
with if (!dpy) so the Wayland path reaches wl_display_run() and exits
cleanly (exit 0) on SIGTERM.  wl-smoke-test.sh now PASSES.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 23:02:26 +01:00
Levi Neely d07362b90e wayland: Phase 32 — display_open/close/screen_count through vtable
Add three display-lifecycle slots to WMBackend:
  display_open(name)    — open/init display connection, return Display*
                          (NULL for Wayland; compositor init side-effect)
  display_close()       — tear down display connection
  display_screen_count() — number of logical screens

x11_backend: implement with XOpenDisplay (including close-on-exec fcntl),
XCloseDisplay, ScreenCount(dpy); remove fcntl/FD_CLOEXEC from main.c.

wl_backend: implement display_open() with full wlroots headless compositor
init — wl_display_create, wlr_headless_backend_create, wlr_renderer_autocreate,
wlr_backend_start.  display_close() tears down in reverse order.
Compositor state held in a file-static struct.  Adds -DWLR_USE_UNSTABLE
to WLROOTS_CFLAGS in configure.ac.

main.c: move backend selection before display_open() (was in StartUp()),
call wm_backend->display_open() instead of XOpenDisplay(); guard all
X11-specific post-open code (visual-id, DisplayName, wXModifierInitialize)
in if(dpy != NULL).

startup.c: replace ScreenCount(dpy) with wm_backend->display_screen_count();
remove now-redundant backend-selection block (owned by main.c).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 22:35:54 +01:00
Levi Neely d2632b8487 wayland: Phase 31 — Wayland backend skeleton (complete stub vtable)
Add --enable-wayland-backend configure option (default: auto).
Requires wlroots >= 0.15, wayland-server, xkbcommon via pkg-config.
Detected at build time on this system: wlroots 0.15.1.

New files:
  src/backend/wayland/wl_backend.h — declares extern const WMBackend wl_backend
  src/backend/wayland/wl_backend.c — complete stub vtable (108 slots)

All stubs return safe zero/null/false values.  Every slot matches the
exact WMBackend function-pointer signature; zero compiler warnings.
Build system compiles the Wayland backend files conditionally when
USE_WAYLAND_BACKEND is set; WLROOTS_CFLAGS/LIBS wired into AM_CFLAGS
and wmaker_LDADD.

Subsequent phases will replace stubs with real wlroots implementations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 22:12:41 +01:00