Add a compositor-side pointer grab so clients can interactively move and
resize their windows. When an XDG toplevel sends request_move or
request_resize, the compositor records the current pointer position and
window geometry, then routes all subsequent motion events directly to
wl_grab_apply_motion() instead of the normal pointer-focus path.
- wl_grab_begin_move / wl_grab_begin_resize: snapshot grab origin,
clear seat pointer focus so the client stops receiving motion events.
- wl_grab_apply_motion: on every motion event, compute dx/dy from the
grab origin and reposition (MOVE) or stretch (RESIZE) the scene node.
Resize honours all WL_SHELL_SURFACE_RESIZE_* edge combinations.
Minimum window size clamped to 32×32 px. XWayland windows use
wlr_xwayland_surface_configure; XDG toplevels use set_size + schedule_configure.
- wl_grab_end: clears grab state; any button release while a grab is
active ends it and resumes normal pointer-focus delivery.
- grab_type, grab_view, grab_start_{ptr,win}_{x,y,w,h}, grab_resize_edges
added to wl_compositor_state.
Smoke test: build-only check added (no existing test client emits
request_move); all 22/22 checks continue to pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Switch wlr_xwayland_create from lazy=false to lazy=true. With eager
start the Xwayland process forks before the compositor's event loop is
running; Xwayland's Wayland client tries to negotiate globals immediately,
gets no response, and closes its connection ("Broken pipe" / "xcb connect
failed: 1"). Lazy mode defers the fork until the first X11 client
connects, by which time the event loop is fully running.
The pre-allocated display number is still available immediately so DISPLAY
is set for child processes regardless of whether Xwayland has started.
On shutdown, after SIGKILL-ing the Xwayland process, explicitly remove
/tmp/.X{n}-lock and /tmp/.X11-unix/X{n}. Without this, if the dead
process's PID is reused by another process before the next wmaker run,
wlroots' stale-lock detection (kill(old_pid,0)) wrongly reports the
display as in-use and the next run fails to claim the same display number.
Smoke test updated: check for "XWayland DISPLAY=.*lazy" instead of the
old "XWayland started DISPLAY=" pattern.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In nested mode the wlr_wl_backend creates virtual pointer/keyboard devices
that mirror the host compositor's seat. Wire handle_backend_new_input on
backend->events.new_input (before wlr_backend_start) to capture these real
devices and add separate wl_listener structs for their key/modifier/button/
motion_absolute/frame events. At the end of wl_display_open, switch the
seat to the real keyboard so focus notifications carry the correct keymap
and modifier state from the host.
handle_keyboard_key / handle_keyboard_modifiers updated to use
seat->keyboard_state.keyboard instead of wl_state.keyboard_dev so the
correct modifier state is used regardless of which keyboard fired the event.
Add a grey wlr_scene_rect root background in handle_backend_new_output so
the compositor output shows a proper desktop instead of solid black. The
rect is inserted first in the scene tree (always below client surfaces).
Pointer bounds clamping in handle_pointer_motion, handle_pointer_motion_-
absolute, wl_pointer_warp and wl_pointer_warp_to updated to use actual
output dimensions instead of hardcoded 1920x1079.
All 6 new wl_listener nodes removed in wl_display_close. Smoke test
22/22 PASS, exit 0.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
WMAKER_WAYLAND_NESTED=0 no longer forces headless when WAYLAND_DISPLAY
is set (auto-detect wins), so the mode check now accepts either
"headless compositor mode" or "nested Wayland compositor mode" and
reports whichever was logged. Remove the now-useless NESTED=0 override
from the launch line.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously nested compositor mode required WMAKER_WAYLAND_NESTED=1 to
be set explicitly. Now wl_display_open() checks WAYLAND_DISPLAY: if it
is set the process is already running inside a Wayland session, so
wlr_wl_backend is used automatically and wmaker appears as a window on
the host desktop.
WMAKER_WAYLAND_NESTED=0 overrides the auto-detection and forces headless
mode (used by the smoke test to avoid accidentally going nested when
WAYLAND_DISPLAY is set in the test environment).
Smoke test: add WMAKER_WAYLAND_NESTED=0 to the wmaker launch line so
the headless path is always exercised regardless of the environment.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Three bugs in the shutdown path caused wmaker to exit with SIGABRT (134)
or hang on SIGTERM when running the Wayland backend:
1. wl_display_destroy() SIGABRT — wlroots 0.15 double-remove bug
wlroots registers internal listeners on the XWayland wl_client's destroy
signal. Those listeners self-remove during client destruction.
wlr_xwayland_server_destroy() then tries wl_list_remove() on the same
already-nulled links, corrupting the heap → SIGABRT.
Fix: skip wl_display_destroy() entirely; Exit() calls exit(0) immediately
after wl_display_close() returns, so the kernel reclaims all resources.
2. wl_display_destroy_clients() hang
wlroots' XWayland client destroy handler performs blocking cleanup
that can hang when Xwayland is in mid-dispatch.
Fix: skip wl_display_destroy_clients() for the same reason as (1).
3. Global listener leak — dangling wl_listener.link pointers
All globally-registered wl_listeners (output frame, backend new_output,
xdg_shell new_surface, decoration, xwayland new_surface, keyboard key/
modifiers, pointer motion/button/frame) were never removed before the
owning wlroots objects were freed. This left link.prev/next dangling
into freed signal structs, causing heap corruption in later allocations.
Fix: WL_LISTENER_REMOVE() all 11 global listeners in wl_display_close()
before any display teardown.
Additional fixes included in this phase:
- handle_toplevel_destroy: remove all 10 per-view listeners (was only 4),
preventing dangling pointers after each client session.
- handle_output_frame: guard on wl_state.allocator; call
wlr_scene_output_send_frame_done() when no GPU allocator so frame
callbacks still fire (fixes weston-simple-shm stall on headless output).
- handle_backend_new_output: call wlr_output_schedule_done() after a
failed commit so weston-info does not hang waiting for wl_output.done.
- XWayland shutdown: SIGKILL Xwayland before display teardown to prevent
waitpid() hanging; null server->client to skip double-free in
wlr_xwayland_server_destroy().
- Self-pipe shutdown: write() to a pipe from the SIGTERM signal handler;
event loop reads it and calls wl_display_terminate() from loop context,
avoiding async-signal-safety issues of calling display APIs from a handler.
Smoke test result: 22/22 checks PASS, wmaker exits cleanly (status 0).
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
When the Wayland backend is active dpy is NULL; all X11 drawing calls
in framewin.c (XMapRaised, XSetWindowBackground, XSetWindowBorder,
XSetWindowBorderWidth, XSetWindowBackgroundPixmap, XClearWindow,
XDrawLine) must be skipped to prevent SIGSEGV when managing XWayland
or synthetic frame windows.
Changes:
- allocFrameBorderPixel: early return when !dpy (no X11 colormap)
- wFrameWindowUpdateBorders: guard XSetWindowBorderWidth and
XSetWindowBorder blocks; guard XMapRaised/XSetWindowBackground in
button-creation branches; guard XMapWindow/XLowerWindow for resizebar
- wFrameWindowChangeState: guard XSetWindowBorder block
- wFrameWindowHideButton: guard XUnmapWindow calls
- wFrameWindowShowButton: guard XMapWindow and XClearWindow calls
- updateTexture: early return when !dpy
- remakeTexture: guard resizebar XSetWindowBackgroundPixmap/XClearWindow
- wFrameWindowPaint: guard entire resizebar XDrawLine section
Frame window structure (wCoreCreate, descriptor setup, stacking) still
runs normally; only the visual rendering is skipped in Wayland mode.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add check 4h-b: grep for "scene output created" to confirm that
handle_backend_new_output found a valid wl_state.scene when it fired
(the Phase 18 ordering fix). Without the fix the scene was NULL and
scene_output was never created, leaving the nested window invisible.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
handle_backend_new_output fires during wlr_backend_start (the nested
Wayland backend triggers a host compositor roundtrip that delivers the
new_output event synchronously). The scene graph and output layout
were previously created *after* wlr_backend_start, so scene_output was
never created, no buffer was ever committed to the host surface, and the
nested window remained invisible.
Move wlr_output_layout_create() and wlr_scene_create() to just before
the backend_new_output listener is wired, ensuring handle_backend_new_output
finds a valid wl_state.scene and can create the scene_output on the spot.
Smoke test: 9/9 checks pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two major additions:
1. Nested Wayland mode (WMAKER_WAYLAND_NESTED=1):
wlr_multi_backend wraps wlr_wl_backend (visual output as a host
Wayland window) and wlr_headless_backend (for synthetic input
devices). wlr_wl_output_create queues the output window before
start; handle_backend_new_output initialises the render pipeline
(wlr_output_init_render, preferred mode, enable, commit) and sets
the window title to "Window Maker".
2. wlr_scene compositing (both modes):
wlr_scene_create() produces a scene graph; per-surface scene nodes
are added in handle_toplevel_map (wlr_scene_xdg_surface_create) and
handle_xwayland_map (wlr_scene_subsurface_tree_create). Positions
are kept in sync via wlr_scene_node_set_position from wl_window_move
and wl_client_synth_configure. handle_output_frame calls
wlr_scene_output_commit on every output vsync to render and send
frame callbacks.
Other changes:
- wlr_allocator_autocreate added; wlr_output_init_render called in
handle_backend_new_output for proper buffer allocation
- headless_inner / wl_backend_inner stored separately so
wlr_headless_add_input_device always uses the headless sub-backend
- frame_timer_cb skips wlr_output_send_frame in nested mode (host
drives frame schedule via output->events.frame)
- Scene nodes removed on surface destroy; allocator/scene torn down
in wl_display_close
Smoke test: new "scene check" verifies "scene graph created" and
"headless compositor mode" log lines.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add wlr_xwayland to the headless compositor so X11 applications
(e.g. GNUstep apps) can run under the Wayland backend.
Key changes:
- Include <wlr/xwayland.h>; add xwayland/xwayland_new_surface_listener
to wl_compositor_state
- Add xw_surface field to wl_toplevel_view so XDG and XWayland windows
share the same view struct and context-store keyed by WNativeWindow
- XWayland window_id used directly as WNativeWindow (no conflict with
XDG synthetic IDs ≥ 0x10000000)
- handle_xwayland_{map,unmap,destroy,set_class}: same wManageWindow/
wUnmanageWindow lifecycle as XDG toplevels
- override_redirect windows (menus, tooltips) are skipped
- view_surface_at: bounds-check path for XWayland surfaces alongside
wlr_xdg_surface_surface_at for XDG toplevels
- vtable functions updated: focus_set, prop_get_normal_hints,
prop_get_wm_class, window_fetch_name, window_get_icon_name,
window_get_client_attrs, client_synth_configure, window_resize,
window_move, client_close, window_get_rect, prop_get_transient_for,
client_get_pid all handle xw_surface != NULL
- wlr_xwayland_create(lazy=false) called in wl_display_open after
compositor and seat; DISPLAY env var set from display_name
- wlr_xwayland_destroy in wl_display_close
- Smoke test: new check 4g verifies "XWayland started DISPLAY=:<n>" log
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire xdg-toplevel event listeners for the remaining lifecycle events:
- request_maximize: toggles wMaximizeWindow / wUnmaximizeWindow
- request_fullscreen: calls wFullscreenWindow
- request_minimize: calls wIconifyWindow
- set_app_id: updates wwin->wm_class when the app changes its app_id
Include actions.h and xinerama.h for the WM action function declarations.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire handle_toplevel_request_move and handle_toplevel_request_resize
listeners to each xdg_toplevel so clients that initiate CSD drag
operations (e.g. GTK titlebar drag) receive an ack rather than hanging.
In the headless compositor both handlers are currently no-ops; a real
compositor would start a pointer grab here.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire handle_pointer_motion, handle_pointer_motion_absolute,
handle_pointer_button, and handle_pointer_frame listeners to the
headless pointer device. Motion handlers update the virtual pointer
position and call wl_update_pointer_focus; button handler forwards
button state to wlr_seat_pointer_notify_button. This completes the
input event pipeline so a real pointer device added later will
dispatch events to focused Wayland clients automatically.
Smoke test check 4f2 verifies "pointer motion/button/frame listeners
wired" is logged at startup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement view_surface_at() and wl_update_pointer_focus() to deliver
wl_pointer.enter/motion/frame events to the Wayland surface under the
virtual pointer. wl_client_synth_configure now records the WM-assigned
position in view->x/y so hit-testing works correctly. After
wManageWindow succeeds, the virtual pointer is warped to the window
centre to immediately deliver pointer focus.
Smoke test check 16c verifies "pointer focus entered surface" is logged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
doAppBounce calls XMoveWindow which crashes when dpy is NULL. Add
early return so urgent-window bounce animations are silently skipped
in Wayland mode (no X11 icon window to move).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Set noclip=1 and nodock=1 in wl_screen_create_internals so wWorkspaceNew
does not call wDockCreate (which requires X11 GCs, pixmaps, and windows
unavailable when dpy is NULL). Smoke test check 4f verifies the log.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add !dpy guards to update_icon_pixmap, wIconPaint, wAppIconPaint,
paint_app_icon, and wAppIconMove so the app-icon creation path
(wApplicationCreate → create_appicon_for_application → wIconUpdate)
does not crash when dpy is NULL in Wayland mode. X11 pixmap and
window-drawing operations are silently skipped; icon state is still
tracked for future Wayland rendering.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add wWaylandKeyPress(keycode, modifiers) to event.c/h: scans
wKeyBindings and dispatches a subset of WM shortcuts (miniaturize,
hide, maximize, raise/lower, close, focus-next/prev, workspace switch)
using raw XKB keycode + modifier values instead of an XEvent.
In wl_backend.c, wire handle_keyboard_key and handle_keyboard_modifiers
listeners on the headless keyboard device so that:
- key events are checked against WM shortcuts first
- non-shortcut keys are forwarded to the focused client via
wlr_seat_keyboard_notify_key
- modifier changes are always notified via wlr_seat_keyboard_notify_modifiers
The headless backend doesn't generate real key events so the listener
is a no-op in the smoke test, but the infrastructure is ready for a
real DRM+libinput backend.
Smoke test: check for "keyboard key+modifiers listeners wired" log.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Set a default XKB keymap on the headless keyboard device in
wl_display_open() so the keyboard has a keycode↔keysym mapping
available from startup.
Implement wl_keysym_to_keycode() by scanning the XKB keymap for the
first keycode that produces the given keysym; XKB keycodes equal
evdev+8 == X11 keycodes, so wKeyBindings are directly compatible.
Implement wl_keysym_from_keycode() as the reverse lookup.
Call wSetModifierMasks(Mod1Mask, Mod1Mask, Mod4Mask, 0) from
wl_screen_create_internals() so AltMask/MetaMask/SuperMask are
non-zero in Wayland mode, making modifier parsing in wXModifierFromKey
produce correct values.
Add wSetModifierMasks() to xmodifier.c/h as the non-X11 entry point.
Replace the four XKeysymToKeycode(dpy, ksym) call sites in
defaults.c, rootmenu.c, and usermenu.c with
wm_backend->keysym_to_keycode() so they work when dpy==NULL.
Smoke test: check for "XKB keymap set on headless keyboard" log line.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
wSwitchPanelSelectNext, wSwitchPanelSelectFirst, and
wSwitchPanelHandleEvent all access wwin->frame->title to display
the window title in the Alt-Tab switcher panel.
Fall back to wwin->wm_class when frame is NULL so Wayland windows
appear in the switcher without crashing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>