raiseWindow: skip stacking operations when wwin->frame is NULL
(Wayland windows have no X11 frame window to restack).
change_focus_and_raise: skip fullscreen stacking-level restore when
oldFocused->frame is NULL.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
wWindowConfigure: add early-return Wayland path that dispatches
client_synth_configure via vtable and updates client geometry instead
of trying to configure a non-existent X11 frame window.
wWindowSingleFocus: use client dimensions when frame is NULL for the
wScreenBringInside call.
wWindowSaveState: fall back to client width/height when frame is NULL
(non-maximized path).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Guard wNETFrameExtents (returns early when !dpy || !frame), so it
does not try to set X11 properties or dereference titlebar/resizebar
for Wayland windows.
Guard OpenWindowMenu, execWindowOptionCommand, and updateOptionsMenu
in winmenu.c so that the window menu and its KeepOnTop/KeepAtBottom
stacking callbacks do not crash when wwin->frame is NULL.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Guard all keyboard shortcut handlers in event.c that dereference
wwin->frame->core for stacking operations (WKBD_KEEP_ON_TOP,
WKBD_KEEP_AT_BOTTOM, WKBD_RAISE, WKBD_LOWER, WKBD_RAISELOWER,
WKBD_WINDOWMENU, WKBD_XKB_TOGGLE) so they skip cleanly when a
Wayland window is focused.
Add early-return guards to wKeyboardMoveResizeWindow,
wMouseMoveWindow, and wMouseResizeWindow in moveres.c so that
Wayland windows (frame==NULL) do not crash if those entry points
are reached.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Guard the remaining wwin->frame dereferences that are reachable for
Wayland windows:
- wSetFocusTo: skip ChangeStackingLevel for fullscreen if !frame
- set_window_coords: fall back to client size when frame is NULL
(called by find_Maximus_geometry on neighbour windows)
- wFullscreenMonitorsWindow: early return if !frame
- wMakeWindowVisible: skip wRaiseFrame if !frame
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add if (!wwin->frame) return guards to wShadeWindow, wUnshadeWindow,
wMaximizeWindow, wUnmaximizeWindow, wFullscreenWindow, wIconifyWindow,
and wDeiconifyWindow so that Wayland-managed windows (frame==NULL) do
not crash when these actions are triggered via menu or keyboard shortcut.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add WIN_WORKSPACE(w) macro to window.h that returns frame->workspace
when the window has a frame (X11 path) or wwin->workspace when it does
not (Wayland path, set in Phase 67).
Replace all unsafe frame->workspace reads with WIN_WORKSPACE() in:
- window.c: wWindowObscuresWindow (workspace comparison + geometry),
wWindowFocusPrev/Next (same-workspace filter),
wWindowSaveState (state serialization)
- session.c: session save (workspace name lookup)
- switchmenu.c: all five switch-menu workspace comparisons/lookups
Also guard wWindowObscuresWindow's frame->core width/height reads with
a ternary that falls back to client.{width,height} for frameless windows.
This eliminates the last class of NULL frame->workspace dereferences
reachable from workspace-switch, focus-cycle, session-save, and
switch-menu code paths.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Guard all frame->core and frame->workspace dereferences in placement.c
against NULL frame pointers (Wayland windows have no WFrameWindow):
- calcSumOfCoveredAreas: skip windows without frame (no stacking level
or geometry available via frame; Wayland window client geometry is
tracked separately in wwin->client.* and wwin->frame_x/y).
- window_overlaps: add early-return path for frameless windows that uses
wwin->client.{width,height} and wwin->frame_x/y for the overlap test,
bypassing the frame->core stacking level check.
- getPlaceOrigin (icon-placement helper): guard frame->workspace reads
for WCLASS_MINIWINDOW and WCLASS_WINDOW parent types using logical-OR
with the wwin->workspace fallback.
Together these prevent NULL dereferences when smart/auto/cascade
placement iterates the managed-window list and encounters Wayland
windows alongside X11 windows.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add int workspace to WWindow so Wayland-managed windows (which have no
WFrameWindow and therefore no frame->workspace slot) can track their
workspace assignment. Set wwin->workspace = workspace in the Wayland
branch of wManageWindow alongside the existing geometry recording.
Guard wWorkspaceForceChange against NULL frame dereferences: introduce a
tmp_workspace local that falls back to tmp->workspace when frame is NULL,
and protect the omnipresent workspace assignment the same way. Also add
a NULL guard for tmp->icon->core in the miniwindow-unmap path.
This prevents NULL dereferences if workspace switching is triggered
(e.g., via a root-menu action) while Wayland windows are managed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Handle WLR_XDG_SURFACE_ROLE_POPUP surfaces in handle_xdg_new_surface by
scheduling the initial configure event. XDG popups (context menus,
autocomplete dropdowns, tooltips) need a compositor configure before they
can commit their first buffer; without it they stall indefinitely.
Popups are not managed by the policy layer — they are self-contained
transient surfaces positioned relative to their parent by the positioner.
We schedule configure and log the event without creating a wl_toplevel_view.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement prop_get_transient_for for the Wayland backend by walking the
xdg_surface->toplevel->parent pointer and looking up the corresponding
wl_toplevel_view to return its synthetic WNativeWindow ID.
This ensures dialog windows and other transient toplevels that set a
parent via set_parent() are correctly identified as transients by the
policy layer (wManageWindow sets transient_for / no_miniaturizable /
no_miniaturize_button correctly).
Add a helper wl_find_view_by_xdg_surface() for surface-based lookups.
Smoke test gains a header comment noting Phase 65 is a build-only check.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Advertise the XDG decoration manager protocol so clients that support
server-side decoration negotiation can communicate with the compositor.
Since the Wayland path has no X11 frame rendering, respond to all
new_toplevel_decoration events with CLIENT_SIDE mode, directing clients
to draw their own title bars and borders.
Smoke test gains two new checks: compositor logs "xdg-decoration-manager
created" at startup, and weston-info reports zxdg_decoration_manager_v1
in the global registry.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All XDG toplevels support polite close via wlr_xdg_toplevel_send_close.
PropGetProtocols now sets DELETE_WINDOW=1 in the Wayland path so
wManageWindow sets kill_close=0 (prefer polite close over force-kill)
and the MC_CLOSE menu item is enabled for Wayland windows.
wClientSendProtocol dispatches wm_backend->client_close in the Wayland
path instead of returning early; since all atoms are 0 in Wayland, atom
comparison is unreliable, but all callers that reach wClientSendProtocol
are requesting a polite close — the only Wayland-meaningful WM_PROTOCOL.
wManageWindow succeeded log gains a kill_close= field; smoke test check
21 verifies kill_close=0 for each managed Wayland toplevel.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three related fixes to make the WM focus lifecycle work end-to-end in
the Wayland path:
1. window.c: set wwin->flags.mapped=1 for Wayland windows (the
wWindowMap call in wManageWindow is guarded by if(wwin->frame)
which is NULL in Wayland, leaving mapped=0 and causing wSetFocusTo
to take the no-focus branch immediately).
2. screen.c: call screen_create_internals in the Wayland goto path;
this was skipped by goto screen_done but is needed to set
auto_focus=1 and clear initial keyboard focus via wlr_seat.
3. wl_backend.c: implement wl_screen_create_internals (sets
no_focus_win=WNATIVE_NONE, auto_focus=1, clears seat focus);
wl_focus_set now calls wlr_seat_keyboard_clear_focus and logs
"focus_clear" when win==WNATIVE_NONE; remove the redundant direct
wl_focus_set call from handle_toplevel_map since wManageWindow now
handles focus via wSetFocusTo.
Smoke test: add check 20 verifying "focus_clear" is logged after the
last managed window unmaps.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
wScreenInit skips wWorkspaceNew (which calls wDockCreate, an X11
operation) via goto screen_done. This left workspace_count=0, causing
a divide-by-zero in wManageWindow when a window carries saved state
(workspace % scr->workspace_count). Allocate a minimal WWorkspace
directly before the goto so the Wayland path always has exactly one
workspace.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
wWorkspaceMapUpdate calls XGetImage(dpy) and RCreateImageFromXImage
(scr->rcontext) directly; both are NULL in the Wayland path. Add
early-return guards so enabling the workspace pager in Wayland mode
does not crash.
set_workspace_map_background_image calls RConvertImageMask(scr->rcontext)
for pixmap textures; guard that path with the same rcontext check.
wl_window_get_icon_name was a stub returning False. Implement it to
return the XDG toplevel title so window icon labels are populated on
the Wayland path (Wayland has no separate WM_ICON_NAME concept).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
scr->rcontext is NULL in the Wayland path (RContextCreate is only
called under dpy). SetupEnvironment() is reachable via shell command
launch and RelaunchWindow; wrap the WRASTER_COLOR_RESOLUTION putenv
in a scr->rcontext NULL-check to prevent a crash.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement stacking_raise/lower by moving views to the head/tail of
wl_state.toplevel_list. stacking_restack reorders the list to match a
given array (inserts from last to first so head = highest Z-order).
stacking_query now returns 1 with the list of synthetic IDs (head-to-tail
= top-to-bottom Z-order). RemakeStackList finds no WM_CTX_STACK frames
for synthetic IDs (as expected — no frame windows on Wayland), so
window_count stays 0, but the change from returning 0→1 eliminates the
"could not get window list" log warning on every stacking operation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add wm_command/wm_command_n fields to wl_toplevel_view.
wl_icccm_set_command stores a deep copy of argv in the view struct;
wl_icccm_get_command returns a NULL-terminated heap copy (caller frees
each string plus the array via wl_icccm_free_command).
handle_toplevel_destroy frees the stored command on cleanup.
Update getCommandForWindow in misc.c: when dpy is NULL (Wayland path),
call wm_backend->icccm_get_command instead of returning NULL immediately.
This allows fixLeaderProperties and session.c to retrieve the command
string for Wayland-managed windows.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add wm_state/wm_state_n fields to wl_toplevel_view. prop_set_wm_state now
stores the 10-long WM state array (workspace, miniaturized, shaded, hidden,
geometry, shortcut slots) in the view; prop_get_wm_state returns a heap
copy so wWindowGetSavedState works correctly when a Wayland client
reconnects. handle_toplevel_destroy frees the stored state on cleanup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add x,y position fields to wl_toplevel_view. wl_window_move now records
the WM-assigned position in the view struct instead of discarding it.
wl_window_get_rect previously returned 0 (invalid) for all synthetic IDs,
causing wIconifyWindow and similar callers to treat every Wayland window as
destroyed. Now returns 1 with real surface dimensions (from wlr_surface
current.width/height) for valid toplevel views, 1 with output dimensions
for other virtual windows, and 0 only for WNATIVE_NONE.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add pointer_x/pointer_y fields to wl_compositor_state, initialised to
screen centre (960,540) in wl_display_open. pointer_warp/warp_to now
update the tracked position (clamped to output bounds); pointer_query and
pointer_query_full return the tracked coordinates instead of hardcoded 0,0.
Also fix the smoke test to ensure XDG_RUNTIME_DIR is set before launching
wmaker (the fix from Phase 53 was already applied; this commits it
permanently). Adds a Phase 54 check verifying the "virtual pointer
initialised at" log line.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a headless pointer input device (WLR_INPUT_DEVICE_POINTER) to the
Wayland seat alongside the existing keyboard device. wlr_seat now
advertises both WL_SEAT_CAPABILITY_KEYBOARD and WL_SEAT_CAPABILITY_POINTER
to clients that bind wl_seat.
Also fix the smoke test to set XDG_RUNTIME_DIR when it is unset so
wl_display_add_socket_auto() can always create the compositor socket.
Smoke test gains a Phase 53 check: weston-info must show 'pointer' in the
wl_seat capabilities output.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add wwin->frame NULL check before accessing wwin->frame->titlebar in
wWindowSynthConfigureNotify so frameless Wayland windows do not
dereference a NULL frame pointer when a synthetic configure notify
is sent.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add if (wwin->frame) guards to wWindowMap and wWindowUnmap so that
frameless Wayland windows do not dereference wwin->frame->core->window.
Guard getCommandForWindow in misc.c against NULL dpy to prevent
XGetCommand crash when the PID-based haveCommand path fires.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Run two weston-simple-shm processes in parallel during the smoke test
and verify that all three toplevels (one from the single-client section
plus two from the parallel section) are managed and unmanaged without
crashing the compositor. The synthetic-ID counter, focus chain, and
wUnmanageWindow path all survive the multi-client scenario.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement wl_client_get_pid using wl_resource_get_client +
wl_client_get_credentials so the WM can retrieve the OS PID of
Wayland clients. Guard getCommandForWindow in misc.c against NULL
dpy to prevent XGetCommand crash when the real PID path fires.
Guard wWindowChangeWorkspace against NULL frame for frameless
Wayland windows. Log pid= in the wManageWindow-succeeded line;
add Phase 50 pid check to smoke test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add if (!dpy) return guards to PropSetWMakerProtocols,
PropSetIconTileHint, and PropCleanUp so the Wayland path does not
call XChangeProperty/XInternAtom/XDeleteProperty on a NULL display
during screen setup and shutdown.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add if (!dpy) return guards to wNETWMInitStuff, wNETWMCleanup,
wNETWMUpdateDesktop, wNETWMGetCurrentDesktopFromHint,
wNETWMUpdateActions, and updateWindowOpacity so the Wayland backend
path does not crash calling XChangeProperty/XDeleteProperty/
XGetWindowProperty on a NULL display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- startup.c: include wl_backend.h when USE_WAYLAND_BACKEND is defined;
select wl_backend when WMAKER_USE_WAYLAND env var is set, otherwise
fall back to x11_backend (no-op for non-Wayland builds)
- tests/smoke-test.sh renamed to tests/x11-smoke-test.sh (X11-only path)
- tests/wl-smoke-test.sh: new Wayland smoke test; currently verifies
wl_backend symbol presence and wlroots linkage; headless compositor
tests will be added as vtable slots are implemented
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>