Commit Graph

182 Commits

Author SHA1 Message Date
Levi Neely c26a3bec30 WINGs/widgets: rewrite makePixmap to use RImage + RConvertImage
Replace X11 XDrawPoint pixel rendering with RImage construction
and RConvertImage, which dispatches through the backend vtable.
Fixes checkbox/radio button images not appearing in Wayland mode.
2026-05-14 16:59:26 +02:00
Levi Neely fdf0956c02 WINGs/wview_wl: re-composite top-level after children draw
The top-level was composited into root before children had painted
into its backing image, resulting in a blank dialog. Now we
composite the top-level a second time after wl_map_subviews so
the final image includes all child content.
2026-05-14 16:56:29 +02:00
Levi Neely 05d819bf15 WINGs: add flush vtable entry, remove XFlush from wbutton.c
Add flush() to W_ViewBackend. X11 backend calls XFlush,
Wayland backend is a no-op (compositing happens at frame
boundaries). wbutton.c WMPerformButtonClick now uses the vtable.
2026-05-14 16:51:03 +02:00
Levi Neely bb420ef536 WINGs/wpanel: use WMEvent keysym instead of XLookupString
All three handleKeyPress functions in wpanel.c were dereferencing
event->_x11_raw (NULL in Wayland mode) to call XLookupString.
Use event->u.key.keysym directly — it's already translated by
the backend.
2026-05-14 16:47:07 +02:00
Levi Neely 4f462357e1 WINGs/wframe: remove X11 GC/region clipping from paintFrame
Replace XClearWindow with render backend fill_rect.
Remove X11 region-based clip masking around relief drawing —
the title is drawn on top afterward, making the clip unnecessary.
Eliminates WMColorGC/XCreateGC crash in Wayland mode.
2026-05-14 16:44:29 +02:00
Levi Neely 685eb42ecc wrlib: split RConvertImage into X11/Wayland backends
RConvertImage and RConvertImageMask now dispatch through function
pointers on RContext, set during context creation:
- RCreateContext sets x11_convert_image/x11_convert_image_mask
- RCreateContextWayland sets wl_convert_image/wl_convert_image_mask

The Wayland backend creates pixman_image_t from RImage RGBA data
instead of returning NULL pixmaps, fixing the SIGSEGV in the exit
dialog when compositing the application icon.

X11 code moved to convert_x11.c, Wayland code in convert_wl.c.
No dpy guards in the middle layer.
2026-05-14 16:41:15 +02:00
Levi Neely 3edf25e0b4 fix build: add missing WINGs vtable fields, fix double-free and linker errors
- Add selection_acquire, selection_release, platform_init to
  W_ViewBackend struct (were used but not declared).
- Add lookup_string to W_FontBackend struct (same issue).
- Guard selection_acquire call with NULL check in selection.c.
- Remove pixman_image_unref in wl_frame_configure resize path —
  wlroots manages the buffer lifecycle via scene refcounting.
  LSan confirms no leak.
- Remove #include of wmspec.c/xdnd.c/xmodifier.c from x11_backend.c
  — they are already compiled as standalone objects, causing
  multiple-definition linker errors on clean builds.
2026-05-14 16:24:59 +02:00
Levi Neely 57536b9991 moveres: replace XEvent with WMEvent in move/resize functions
wMouseMoveWindow and wMouseResizeWindow took XEvent* but were
being passed WMEvent* via casts. The XEvent union layout differs
completely from WMEvent, so ev->xmotion.x_root read garbage —
causing the window to jump to a wrong position and the move to
become uncontrollable.

Changed both functions to take WMEvent*, accessing ev->u.button
fields directly. Removes all XEvent references from the core
policy layer (zero backend-specific types in the middle).
2026-05-14 13:15:34 +02:00
Levi Neely c47fc49290 wayland: restore cursor when pointer leaves client surface
When a client (e.g. foot) sets its own cursor surface via
wl_pointer.set_cursor, the cursor disappears once the pointer
moves off the client surface because nobody resets it. Now
wl_update_pointer_focus resets to left_ptr when the pointer
leaves all surfaces or enters a new one (before the client
gets a chance to override via request_set_cursor).
2026-05-14 13:04:30 +02:00
Levi Neely 6dfdc5a108 wayland: fix frame/client desync and titlebar offset
Three issues fixed:

1. Frame and client surface moved independently during interactive
   window move. The client surface (wl_toplevel_view) and frame
   decorations (wl_frame_buf) are independent scene graph nodes —
   unlike X11 where reparenting creates an implicit parent-child
   relationship. Added frame_id/frame_rel_x/frame_rel_y to
   wl_toplevel_view so wl_window_move keeps them in sync.

2. window_move(client_win, x, y) treated coordinates as absolute,
   but the WM core passes relative-to-frame coordinates (matching
   X11 child window semantics). Now detected via frame_id and
   converted to absolute scene positions.

3. Titlebar scene node was offset by left_button_width because
   updateTitlebar() configures it for X11 layout (separate
   overlapping windows). Since the Wayland backend composites
   buttons directly into the titlebar buffer, override the
   titlebar position to frame origin during wl_frame_paint.
2026-05-14 12:59:39 +02:00
Levi Neely 4be05c799c Phase 84: eliminate all backend guards from policy code
Remove every is_wayland / !is_wayland guard from WM policy files.
All backend-specific logic now lives exclusively in the backends:

- main.c: display_post_open vtable slot handles fatal check, visual ID,
  display name, and multiHead parsing (X11) or no-ops (Wayland)
- event.c: EventLoop() unconditionally calls event_loop_run(); the X11
  backend's implementation contains the WMNextEvent+inotify loop
- screen.c: screen_init_display vtable slot handles RContext/WMScreen/
  color creation (each backend owns its full init path)
- monitor.c: show_crash_dialog vtable slot (X11 shows panel, Wayland
  returns abort)
- startup.c: InitializeSwitchMenu called unconditionally (it's
  backend-agnostic); defaults polling timer no longer guarded
- shutdown.c: wScreenSaveState called unconditionally
- window.c: client_reparent called unconditionally (Wayland no-ops);
  dead frameless-window code removed

Policy code is now completely backend-agnostic. The only references to
is_wayland are the vtable field definitions in the two backend files.
2026-05-14 12:41:01 +02:00
Levi Neely ac1dbd3b8e Phase 83: frame decorations for native Wayland clients
- Create WM frames (titlebar, buttons, resizebar) for native XDG
  toplevels — remove the is_wayland guard that skipped frame creation
- Set decoration mode to SERVER_SIDE so clients don't draw their own
  titlebar (CSD)
- Skip client_reparent for Wayland (no X11 reparenting needed; the
  client scene node is independent of the frame scene buffers)
- Set frame_border_width=0 in wl_screen_create_internals (Wayland has
  no X11-style window border; the frame_buf renders all decoration)
- Use wlr_scene_subsurface_tree_create for client surface (avoids XDG
  geometry offset issues)

Known issue: transient size mismatch on initial map when saved session
state or size constraints differ from the client's committed buffer.
Resolves after the client processes the configure event.
2026-05-14 12:18:13 +02:00
Levi Neely 288d2ad3a7 Phase 82: wlroots 0.19 compatibility + native Wayland client support
- Add wlr_subcompositor global (required by all modern Wayland clients)
- Switch from xdg_shell new_surface to new_toplevel signal (wlroots 0.19
  fires new_surface with role=NONE before get_toplevel assigns the role)
- Defer initial xdg_surface configure to first client commit via
  surface->events.commit listener (surface must be initialized first)
- Defer xdg_decoration set_mode to first commit (set_mode internally
  calls schedule_configure which asserts initialized)
- Wire destroy_listener to toplevel->events.destroy instead of
  xdg_surface->events.destroy (wlroots asserts toplevel event lists
  are empty before the toplevel is freed)
- Log DISPLAY and WAYLAND_DISPLAY env vars at startup
- Add WAYLAND_ROADMAP.md

Native Wayland clients (foot, etc.) can now connect, render, and
disconnect without crashing the compositor.
2026-05-14 11:57:15 +02:00
Levi Neely da4f662844 Fix modal loop re-composite: use vb->map for correct paint order
Was calling redisplay then map_subviews separately, with background
overwriting children. Now calls vb->map which does background first,
then children composite on top, with final commit showing everything.
2026-05-13 22:57:47 +02:00
Levi Neely 71c4bfdfbc Fix xkb_state NULL and respect host keyboard layout
- Only apply default XKB keymap as fallback when the host compositor
  hasn't provided one yet (kb->xkb_state == NULL)
- The nested backend receives the host's keymap (Dvorak, etc.) via
  wl_keyboard.keymap — don't overwrite it with QWERTY default
2026-05-13 22:55:39 +02:00
Levi Neely 8f0ec30759 Fix keyboard input: don't forward keys to seat without focused surface
wlr_seat_keyboard_notify_key was being called unconditionally, which
caused re-entrancy that consumed WINGs events from the queue before
the modal loop could fetch them. Now only forwards to the seat when
there's an actual focused client surface.

Also use 16ms timeout in wl_flush so keyboard events from the nested
compositor are actually received during modal loop dispatch.
2026-05-13 22:48:13 +02:00
Levi Neely ace0585ec3 Unify WMCreateScreenWithRContext: single path, vtable dispatch
Eliminated the separate Wayland/X11 code paths. Now ONE path:
1. Backend selection (based on WMAKER_USE_WAYLAND)
2. Backend init
3. Common init (colors, fonts, antialiasedText)
4. viewBackend->platform_init() — X11 does GCs, atoms, cursors,
   cut buffers, modifier masks, pixmaps, IM, W_InitApplication.
   Wayland is NULL (no platform-specific late init needed).
5. rootView, balloon, return

All X11-specific screen setup moved to W_X11PlatformInit() called
through the view backend vtable. No if-guards, no early returns,
no separate paths.
2026-05-13 22:16:54 +02:00
Levi Neely 2e631eef15 Add selection_acquire/release to view backend vtable
- WINGsP.h: add selection_acquire/release slots to W_ViewBackend
- wview_x11.c: implement via XSetSelectionOwner/XGetSelectionOwner
- wview_wl.c: stub that returns True (TODO: wl_data_device)
- selection.c: use vtable instead of direct X11 calls
2026-05-13 21:53:55 +02:00
Levi Neely 840b00819d Route pointer events to deepest child view at click point
In X11, the server delivers events to the deepest child window.
In Wayland, all widgets share one frame_buf. WMHandleEvent now
does hit-testing within the view tree to find the correct child
widget for button press/release/motion events.
2026-05-13 21:49:29 +02:00
Levi Neely 01f2e4463e Re-composite dialog after each event in modal loop
After WMHandleEvent processes a key press, the text field repaints
into its backing image. The modal loop now re-composites the view tree
and commits to the scene graph so changes are visible immediately.
2026-05-13 21:47:24 +02:00
Levi Neely df7f681c14 Fail loudly when xkb_state is NULL in handle_keyboard_key
Warn and drop the event rather than silently swallowing it. This makes
the root cause visible — key events arriving before keyboard is fully
initialized.
2026-05-13 21:45:04 +02:00
Levi Neely 4e9043ad6d Guard xkb_state against NULL in handle_keyboard_key
Key events can arrive before the keyboard's xkb_state is initialized.
2026-05-13 21:44:30 +02:00
Levi Neely 76080cd2eb Implement keyboard input via font backend abstraction
- WMEKey: add keysym, utf8[8], utf8_len fields
- handle_keyboard_key: translate keycode via xkb_state, fill keysym/utf8,
  route event to focused WINGs view
- W_FontBackend: add lookup_string slot
- wfont_x11.c: implement via W_LookupString (wraps XLookupString)
- wfont_wl.c: implement by reading pre-translated keysym/utf8 from event
- wtextfield.c: use font backend lookup_string (no X11 guards)
2026-05-13 21:43:24 +02:00
Levi Neely 94b45b342e Fix dialog: paint background before children, not after
wl_map was calling wl_map_subviews (children) then wl_redisplay (bg fill),
overwriting children with the background. Reversed order so background
is filled first, then children composite on top.
2026-05-13 21:35:18 +02:00
Levi Neely bf9a0a9cf5 Fix dialog titlebar and background rendering
- window.c: always call frame_paint for internal windows (title=NULL
  skipped wFrameWindowChangeTitle which was the only paint trigger)
- wview_wl.c: fill view backing with background color before expose
  (X11 server fills background automatically, Wayland needs explicit fill)
2026-05-13 21:34:07 +02:00
Levi Neely 4440476a35 Fix dialog position: update children when reparenting frame_buf
When fake_leader is reparented into the frame, its children (the WINGs
view frame_buf) weren't being repositioned. Now cascades position
updates to children of the reparented frame_buf.
2026-05-13 21:29:46 +02:00
Levi Neely 6cda661609 Fix dialog content rendering: re-trigger child paint when top-level maps
Children were painted during panel creation (before frame_buf backing
was connected). Now wl_map triggers wl_map_subviews when a top-level
view is mapped, re-painting all children into the correct backing image.
2026-05-13 21:27:22 +02:00
Levi Neely 305b8096da Fix regression: only trigger redisplay on map for top-level views
wl_map was calling wl_redisplay on every view map, including internal
widgets during startup. This caused crashes when non-dialog views
received expose events before being fully set up.
2026-05-13 21:24:07 +02:00
Levi Neely 3a0ca5444e Fix NULL gview crash: create geometry view in Wayland screen path
The Wayland screen init path had 'goto screen_done' which skipped
gview creation. Now creates it before the goto. Also added safety
guard in moveGeometryDisplayCentered.
2026-05-13 20:05:17 +02:00
Levi Neely f348b3a04b Guard moveGeometryDisplayCentered against NULL gview 2026-05-13 20:01:13 +02:00
Levi Neely 72377068fd Dialog rendering: child view compositing and text field fixes
- wl_realize: allocate pixman backing image for every view
- wl_map_subviews: recursively trigger redisplay on child views
- wl_redisplay: composite child backing into parent, commit top-level
- wtextfield.c: replace XDefineCursor with W_SetViewCursor
- wtextfield.c: guard W_LookupString against NULL _x11_raw
2026-05-13 19:58:55 +02:00
Levi Neely b53cc4f0da Dialog rendering: composite child views into parent backing
- wl_realize: allocate pixman backing image for every view
- wl_map_subviews: recursively trigger redisplay on child views
- wl_redisplay: composite child's backing into parent's backing,
  then commit the top-level view's frame_buf
- wtextfield.c: guard W_LookupString against NULL _x11_raw
2026-05-13 19:57:12 +02:00
Levi Neely 4870c72c78 Fix dialog visibility: trigger paint on map, enable scene node on commit
- wl_map: set mapped=1 before calling wl_redisplay (was bailing because
  mapped flag wasn't set yet)
- wl_view_commit_backing_impl: enable scene node when content is committed
  (frame_buf was created disabled, never enabled before frame was mapped)
2026-05-13 19:51:22 +02:00
Levi Neely 6d9450ea8b Make dialogs visible: fake_leader, recursive reparent/map/move
- fake_leader_create: return a real frame_buf ID (was returning 0)
- client_reparent: handle frame_buf-to-frame_buf reparenting
- client_reparent: get WINGs view size from view table
- window_map: enable grandchildren (dialog content is grandchild of frame)
- window_move: move grandchildren when parent moves
- dialog.c: guard scr->w_visual for Wayland mode in Info panel
2026-05-13 19:45:41 +02:00
Levi Neely 9191f12913 Fix render backend crashes: resolve view IDs in all drawing functions
All WINGs render backend functions (draw_line, draw_rect, fill_rect,
pixmap_copy, composite_pixmap) now use resolve_drawable() to handle
WINGs view IDs (0x20000000+) by looking up the backing pixman image.

Also fixes:
- wfont_wl.c: resolve view IDs in draw_string/draw_image_string
- wtextfield.c paintCursor: use render backend draw_line (not XDrawLine)
- dialog.c wShowInfoPanel: guard scr->w_visual for Wayland mode
2026-05-13 19:40:31 +02:00
Levi Neely 1d0b82eed5 Implement WINGs dialog rendering infrastructure
- wl_client_reparent: create child frame_buf for WINGs views, connect
  backing pixman image so widgets paint into the scene graph
- View lookup table: map synthetic IDs to W_View* for event dispatch
- render_wl_pixmap_copy: detect view IDs and copy into backing image
- W_ViewCommitBacking callback: commit frame_buf after WINGs paint
- WMHandleEvent: use view table in Wayland mode (was always NULL)
- wtextfield.c paintCursor: use render backend draw_line instead of
  XDrawLine (crash fix for Run dialog)
2026-05-13 19:33:26 +02:00
Levi Neely 531dcf8235 Fix text rendering and titlebar positioning
- wl_draw_string: remove ascent subtraction, y is TOP position (matches
  X11 Pango behavior where pango_xft_render_layout takes top-left)
- Menu entry text: pass top position (y+3) not baseline (y+3+fh-1)
- Icon title: pass y=0 (top) not y=fh (baseline)
- frame_paint_titlebar: pass centered top not baseline
- frame_configure: compute absolute position from parent for children
  (was setting absolute pos to relative coords, warping to 0,0)
- Titlebar buffer: always render full frame width, resize if needed
- Frame scene node: disable when no resizebar (transparent, not needed)
- Always call frame_paint after show/hide button (TS_NEW was skipping it)
2026-05-13 19:03:49 +02:00
Levi Neely 3a48a0eb30 Fix close button: always call frame_paint after show/hide button
wFrameWindowShowButton was only calling updateTitlebar (not frame_paint)
when new_style==TS_NEW. Now always calls frame_paint so the close button
icon is rendered into the frame buffer after pinning a menu.
2026-05-13 18:28:45 +02:00
Levi Neely 147b9d0694 Fix hit-testing: prefer child frame_bufs over parents
frame_buf_at was returning the parent frame instead of child windows
(titlebar, content area) because the parent was later in the list.
Now prefers children (frame_bufs with parent_id set) over parents.

This fixes menu titlebar click detection — clicking the titlebar now
dispatches to titlebarMouseDown/menuTitleMouseDown instead of
menuMouseDown, enabling menu pinning and drag-to-move.
2026-05-13 18:21:07 +02:00
Levi Neely 08c0e07f6c Fix clean shutdown: remove pointer listeners, reset signal handlers
On SIGINT/SIGTERM:
- signalfd handler sets terminate flag and exits the event loop
- After loop exit, remove wlroots pointer listeners to prevent
  assertion failure in wlr_pointer_finish
- Reset SIGTERM/SIGINT/SIGHUP to SIG_DFL after signalfd takes over
  to prevent the old handleExitSig from competing
2026-05-13 18:06:01 +02:00
Levi Neely 8922525d3c Fix crash: guard wRootMenuPerformShortcut against NULL _x11_raw
handleKeyPress passed event->_x11_raw (NULL in Wayland mode) to
wRootMenuPerformShortcut which dereferences it immediately. Skip
the call when _x11_raw is NULL.
2026-05-13 18:01:07 +02:00
Levi Neely a517c16f5e Guard WINGs realizeWindow against NULL display in Wayland mode
When a menu entry triggers a WINGs dialog (e.g. 'Run...'), the
realizeObserver notification calls realizeWindow which does X11 calls
(XSetClassHint, XAllocWMHints). In Wayland mode scr->display is NULL,
causing a segfault. Skip the entire function when display is NULL.
2026-05-13 17:56:46 +02:00
Levi Neely fb2d0ab2ef Implement pointer_get_position: return tracked cursor coordinates
pointer_get_position was a noop returning (0,0), causing findMenu to
always return NULL. This made the menu close on every button release
regardless of pointer position. Now returns wl_state.pointer_x/y which
are updated on every pointer motion event.

With this fix, the root menu stays open when the pointer is over it on
release (matching X11 behavior), allowing entry selection or titlebar
pinning.
2026-05-13 17:52:17 +02:00
Levi Neely bfa248ae29 Fix findMenu y_ret: subtract top_width for content-relative coords
findMenu was returning y relative to the frame top (including titlebar).
getEntryAt expects y relative to the content area. Subtracting top_width
means pointer in titlebar gives y<0 → entry_no=-1 (no selection), which
is correct behavior matching the X11 path.
2026-05-13 17:48:08 +02:00
Levi Neely 784fcfbfb2 Implement frame button rendering (close/iconify icons)
Add wl_frame_paint_button which renders button icons from XPM data
into the parent frame buffer. Called both from the vtable slot and
from wl_frame_paint during titlebar rendering. Uses PRED_CLOSE_XPM
and PRED_ICONIFY_XPM parsed lazily via RGetImageFromXPMData.

Also removes XEvent from all WFrameWindow callbacks (on_click_left,
on_click_right, on_dblclick_right, on_mousedown_resizebar) — they
now take WMEvent*.
2026-05-13 17:46:21 +02:00
Levi Neely 1af95d539f Fix menu unmap: hide children when parent is unmapped
wl_window_unmap now disables child scene nodes when the parent is
hidden. This fixes the menu entries staying visible after the menu
frame (titlebar) was unmapped. The entire menu now disappears
together, matching X11 behavior where the brother menu closes on
button release.
2026-05-13 17:32:49 +02:00
Levi Neely 0dc38e4d79 Fix findMenu: check brother menus and dock menus
The root menu uses a 'brother' copy for the live instance. findMenu
was only checking the original, not the brother, so it returned NULL
when the pointer was over the active menu copy. This caused the menu
to close immediately on button release (closeCascade triggered by
!smenu condition).
2026-05-13 17:29:40 +02:00
Levi Neely f2dfe4a4d0 Remove XEvent from frame callbacks (titlebar, resizebar, buttons)
All WFrameWindow callbacks (on_mousedown_titlebar, on_dblclick_titlebar,
on_mousedown_resizebar, on_click_left, on_click_right, on_dblclick_right)
now take WMEvent* instead of XEvent*. This fixes the crash when clicking
the menu titlebar in Wayland mode (_x11_raw was NULL).

Affected files: framewin.h, framewin.c, menu.c, window.c, dialog.c,
winspector.c. All verified X11-free with nm.
2026-05-13 17:27:02 +02:00
Levi Neely b248dd04a7 Fix findMenu: use bounds checking instead of broken X11 window query
findMenu always returned NULL because the refactored code set win=0
then checked 'if (win == None) return NULL'. Replace with geometric
bounds checking against mapped menus. This fixes the menu disappearing
on button release (closeCascade was called because smenu was NULL).
2026-05-13 17:02:05 +02:00
Levi Neely 1905fdf08a Fix frame buffer: clear to transparent so children show through
The frame buffer was cleared to opaque black, covering the menu
content child buffer. Now cleared to alpha=0 (transparent).
2026-05-13 16:59:47 +02:00