Commit Graph

60 Commits

Author SHA1 Message Date
Window Maker a789abc09f arch: eliminate last _x11_raw escape from src/ (winspector)
The Window Inspector's 'select window' feature grabbed the pointer on
the root window then read XEvent.xbutton.subwindow to learn which
window was clicked.  This was the last access to _x11_raw in shared
src/ code.

Add a subwindow field to WMEButton.  The X11 backend's WMEvent
translation populates it from xbutton.subwindow.  The Wayland backend
leaves it 0 (Wayland has no equivalent grab semantic — the click
reports the actual frame as event.window directly).  winspector.c
now uses event.u.button.subwindow with fallback to
event.u.button.window, working on both backends.

Net: src/ has zero _x11_raw escapes from shared code.  Remaining
references are inside the X11 backend (legitimately consuming the
field set by its own event translator).
2026-05-24 08:40:38 +02:00
Ollie a438713b92 WINGs/wview_wl: implement internal DnD for Wayland
Implement wl_drag_begin as a simple internal drag-and-drop state machine
for WINGs-to-WINGs drag operations (color wells, text widgets).

On button press, waits for motion to confirm drag intent, then enters
a drag loop tracking the cursor. On release, finds the view under the
cursor and if it has drag destination procs + matching types, fetches
data from the source and calls performDragOperation on the destination.

This handles same-process DnD without needing wl_data_device protocol.
2026-05-23 19:07:54 +02:00
Ollie 5558a1edf0 WINGs/wfont_wl: remove stale text comparison in wl_text_width
The optimization that skipped pango_layout_set_text when the text
matched the previous layout content used pango_layout_get_text()
which returns an internal pointer. This pointer comparison with
arbitrary input text could read freed memory or trigger heap
corruption in Pango internals when the layout state was stale.

Always call pango_layout_set_text unconditionally. The cost is
negligible (Pango internally short-circuits if text is identical).
2026-05-23 16:41:44 +02:00
Ollie 3acf2f6b2b WINGs: implement Wayland selection fetch (middle-click paste)
Add selection_fetch vtable slot for synchronous selection retrieval.
On Wayland, WMRequestSelection uses this to fetch clipboard/primary
selection data directly (via W_ClipboardFetchFn -> seat pipe read)
and calls the callback immediately. On X11, the async path
(selection_request -> SelectionNotify event) is unchanged.

This makes middle-click paste work in WINGs text widgets on Wayland.
2026-05-23 16:37:58 +02:00
Ollie 7077e00d12 WINGs: remove dead X11 code from wtext.c and wmisc.c
- wtext.c: remove unused XEvent variable
- wmisc.c: remove dead #ifndef DOUBLE_BUFFER branches (XClearWindow)
  DOUBLE_BUFFER is always defined; these were unreachable.
2026-05-23 16:19:48 +02:00
Ollie 1ab108f7aa WINGs/wevent: fix NULL toplevel crash on Wayland expose dispatch
W_TopLevelOfView returns NULL for views without a topLevel ancestor
(e.g. geometry display widgets parented directly to root). On X11 this
never triggered because expose events only arrived for mapped windows
with proper widget hierarchy. On Wayland, wl_redisplay synthesizes
expose events for any view, exposing the NULL case.

Fix: fall back to the view itself when no topLevel ancestor exists.
2026-05-23 16:17:18 +02:00
Ollie 8ec338016a WINGs/wcolorpanel: gate magnifier via vtable callback dispatch
The magnifier is X11-backend-specific (screen capture). Instead of a
disguised is_x11 check, the view backend provides the callback directly:
- X11: .magnify_callback = W_ColorPanelMagnify (the magnifier impl)
- Wayland: .magnify_callback = NULL (button does nothing)

The button wiring uses the vtable value as the action callback.
No conditionals, no capability flags, pure vtable dispatch.

Also removes the screen_grab_image vtable slot that was a disguised check.
2026-05-23 16:15:03 +02:00
Ollie 0e26aa878c WINGs/wcolorpanel: replace pixmap/copy/fill X11 calls with render backend
Converts 60 X11 calls (XCreatePixmap, XFreePixmap, XCopyArea,
XFillRectangle) to render backend vtable dispatch. Remaining 40
calls are all in the magnifier feature (screen capture, inherently
platform-specific) and will be handled separately.
2026-05-23 16:09:10 +02:00
Ollie 9ccfd33971 WINGs: route selection acquire/release/request through vtable
- WMDeleteSelectionHandler: X11 grab/release replaced with selection_release vtable
- WMRequestSelection: XGetSelectionOwner+XConvertSelection replaced with selection_request vtable
- x11_selection_release: now properly releases ownership (was no-op)
- x11_selection_request: new vtable impl for X11 selection conversion
- Wayland selection_request: NULL (no-op, returns False)
2026-05-23 16:02:11 +02:00
Ollie 2dce45432d WINGs: route XOR drawing through vtable, remove X11 from wtextfield/wsplitview
- wsplitview.c: XFillRectangle+ixorGC replaced with xor_fill_rect vtable call
- wtextfield.c: removed Display *dpy and XRotateBuffers (cut buffer is dead)
- Added xor_fill_rect to W_ViewBackend (X11 impl, Wayland NULL/no-op)
2026-05-23 15:53:16 +02:00
Window Maker 9eecb2511c WINGs Phase D: port wballoon, wpopupbutton, wtext to vtable
New vtable slots: pointer_grab, pointer_ungrab, bell, balloon_draw, text_init
All implemented in X11 backend, no-ops in Wayland backend.

wballoon.c: XTranslateCoordinates -> get_screen_position, showText -> balloon_draw
wpopupbutton.c: all 7 Xlib calls replaced (grabs, coords, flush)
wtext.c: XMapWindow, XBell, XGrabPointer, XUngrabPointer, cursor, GC init all ported
2026-05-23 15:26:48 +02:00
Window Maker 264679a2d1 WINGs: port wwindow.c to vtable dispatch (Phase D)
Removes all direct Xlib calls from wwindow.c (25 calls eliminated).
ICCM/EWMH property setting dispatched through W_ViewBackend slots:
- window_set_title, window_set_icon_title, window_set_icon_image
- window_realize (WM_CLASS, WM_HINTS, WM_PROTOCOLS, transient-for)
- window_set_geometry (WM_NORMAL_HINTS)
- window_withdraw (XWithdrawWindow)

X11 backend implements full property setting.
Wayland backend is no-op (compositor-internal windows).
Struct moved to wwindow_p.h for backend access.
2026-05-23 15:19:52 +02:00
Window Maker 11c5625d1e WINGs: add Phase D vtable slots, port wballoon.c
Adds window_set_title, window_realize, window_set_geometry,
window_withdraw, pointer_grab, pointer_ungrab, bell, balloon_draw
slots to W_ViewBackend.

Ports wballoon.c:
- XTranslateCoordinates replaced with get_screen_position vtable
- showText replaced with balloon_draw vtable dispatch
- X11 backend calls existing rendering code
- Wayland backend is no-op (WM-level balloon handles dock tooltips)
2026-05-23 15:13:38 +02:00
Window Maker eeda48d24e Fix clipboard free mismatch: XFree -> wfree
x11_clipboard_fetch now returns wmalloc copy (XFree internally).
Callers use wfree uniformly on both backends. Prevents X11 regression
where XFree was called on wmalloc memory or vice versa.
2026-05-23 15:04:15 +02:00
Window Maker 0083654d2e WINGs: route DnD through view backend vtable
Adds drag_begin slot to W_ViewBackend. WMDragImageFromView dispatches
through it. X11 backend sets NULL (falls through to existing XDND
code). Wayland backend is a no-op — prevents crash without guards.
2026-05-23 15:02:30 +02:00
Window Maker cee271f2cd WINGs: cross-client clipboard via wlr_seat selection
Bridges WINGs internal clipboard to the Wayland seat selection so
copy/paste works between compositor-internal dialogs and real
Wayland clients. Store creates a wlr_data_source and sets seat
selection. Fetch reads from foreign selection sources via pipe.
2026-05-23 14:59:42 +02:00
Window Maker 0dc7e33e4b WINGs: route clipboard through view backend vtable
Adds clipboard_store/clipboard_fetch to W_ViewBackend. Replaces
direct XFetchBuffer/XStoreBuffer calls in wtextfield.c and wtext.c
with vtable dispatch. X11 backend wraps Xlib, Wayland backend uses
an internal buffer.
2026-05-23 14:55:59 +02:00
Window Maker e7427f08db WINGs Wayland: implement view ops (move, resize, unmap, raise, lower, reparent)
Replaces all no-ops in wview_wl.c with real implementations:
- move: updates pos, triggers parent redisplay
- resize: reallocates pixman buffer, triggers redisplay
- unmap/unmap_subviews: clears mapped flag, triggers parent redisplay
- raise: moves view to end of sibling list (drawn last = on top)
- lower: moves view to front of sibling list (drawn first = on bottom)
- reparent: moves between parent children lists
2026-05-23 14:51:07 +02:00
lkn ee8489e3a1 fix: WINGs widget clicks on Wayland (child view hit-testing)
On Wayland, all WINGs child widgets composite into a single scene_buf
for the toplevel dialog. Clicks always arrived with the toplevel window
ID, so WMHandleEvent delivered them to the toplevel view which has no
ButtonPressMask handler. Child widget handlers never fired.

Fix: add W_FindViewAtPoint() to walk the view tree and find the deepest
mapped child at click coordinates. In handle_pointer_button, resolve the
child view for WINGs surfaces and pass it as the direct target to
W_WL_EnqueueEvent. WMHandleEvent then delivers directly to the widget.
2026-05-23 13:50:00 +02:00
Window Maker ce8783c0d4 fix: X11 backend rendering — frame paint pipeline and icon recursion
- x11_frame_paint_impl: delegate to wFrameWindowPaint() which handles
  texture remake, background setup, bevel drawing, and title/button paint.
  The old implementation only drew title text and resizebar lines, missing
  all background/texture setup.

- x11_icon_paint: add recursion guard. wIconPaint() calls icon_paint()
  which called wIconPaint() again — infinite recursion causing stack
  overflow crash on first dock/clip icon paint (blank desktop).

- Remove debug wwarning lines from wevent_x11.c and menu.c.
2026-05-23 12:56:43 +02:00
ollie 3f9182b24a fix: destroy scene graph nodes when WINGs views close on Wayland
When a WINGs toplevel (modal dialog, info panel, etc.) is destroyed,
   wl_destroy() now calls W_ViewDestroyBackingFn, which invokes
   wl_view_destroy_backing_impl() to remove the frame_buf from the
   frame list and destroy the wlr_scene_node. This ensures closed
   WINGs windows actually disappear from screen.
2026-05-17 19:34:30 +02:00
Window Maker 15bec04b1b fix: eliminate use-after-free crash on modal dialog close
- wevent_wl.c: W_IsValidView() validates _view_target against view_table
     at fetch boundary (wl_fetch, wl_check_mask, wl_check_typed_window);
     nulls target before returning event if view was destroyed
   - wevent_wl.c: W_WL_InvalidateView() nulls queue entries at destroy time
   - wview.c: set view->screen=NULL before wfree(view)
   - wevent.c: defense-in-depth: check !view->screen || alreadyDead before use
2026-05-17 19:16:32 +02:00
Window Maker 6d42151d2e wayland: iconify/deiconify and post_dispatch struct field
- Remove !wwin->frame early exits in wIconifyWindow/wDeiconifyWindow
- Guard frame-dependent code with wwin->frame checks
- Implement wl_client_set_state (scene node enable/disable)
- Add post_dispatch to W_EventBackend struct (.h + .h.in)
- Fix client_snapshot, animateResize, and frame refs for Wayland
2026-05-15 18:55:14 +02:00
lkn d29f2a29c9 wayland: fix close/iconify buttons and miniwindow rendering
Three bugs fixed:

1. Close and iconify buttons broken after frame rendering model change
   Buttons are composited into the titlebar buffer, so their scene_buf
   nodes carry no committed buffer and are invisible to wlr_scene_node_at.
   frame_buf_at() returned the titlebar fb for all button-area clicks,
   routing them to titlebarMouseDown instead of buttonMouseDown.

   Fix: add frame_buf_button_at() -- coordinate walk of frame_list entries
   with scene_buf->buffer == NULL -- and frame_buf_hit() which tries button
   resolution first then falls back to the scene graph. Replace all
   frame_buf_at() calls in button and motion handlers with frame_buf_hit().
   Also emit synthetic WME_LEAVE/WME_ENTER events on sub-window boundary
   crossings so buttonMouseDown's press-track loop works correctly.

2. Iconify crash (SIGSEGV in update_icon_title)
   WMDrawString() was passed icon->core->window (a frame_buf synthetic ID,
   0x10000000+) as the drawable. wl_font_resolve_drawable() only recognised
   WINGs view IDs (0x20000000+), so it cast the frame_buf ID directly as a
   pixman_image_t* -- wild pointer -- SIGSEGV.

   Fix: add W_RegisterBacking()/W_UnregisterBacking() to wview_wl.c.
   Register each frame_buf's pixman image in the backing table on creation
   and unregister on destroy. Extend the ID range check in wfont_wl.c and
   wrender_wl.c from 0x20000000 down to 0x10000000 so frame_buf IDs resolve
   correctly via W_GetViewBacking().

3. Resizebar visible after iconify + miniwindow not rendering
   wl_window_unmap() disabled fb->scene_buf->node individually, but a
   subsequent wl_frame_paint() could re-enable and re-commit it while the
   window was still iconified.

   Fix: for top-level frames, disable fb->tree->node -- hides the entire
   scene tree (frame buffer, titlebar, resizebar, client surface) atomically.
   Symmetric enable in wl_window_map().

   Miniwindow icons were invisible: icon_paint was a noop so the frame_buf
   image was never committed to the scene graph. Add wl_icon_paint() mirroring
   wl_appicon_paint(): tile + file_image composite + title text, committed
   via wlr_scene_buffer_set_buffer(). Wire into wIconPaint() in icon.c so
   the backend finalises the surface after policy-layer setup.
2026-05-15 09:49:06 +02:00
lkn 859c4d8e78 wl_backend: fix unshade — re-enable and raise client surface and frame
On shade, the client scene node was lowered and disabled, and the
frame_buf scene node was disabled. On unshade, the frame_buf node
was not re-enabled, and the client node was enabled but remained
behind the frame (at bottom of Z-order from stacking_lower).

Fix: re-enable frame_buf node when show_resizebar is true, and
raise the client scene node to top on window_map so it's above
the frame background.
2026-05-14 22:26:07 +02:00
Levi Neely 95b0b8ee7c WINGs/wevent: remove _x11_raw from WMHandleEvent dispatch path
WMHandleEvent is the middle layer — it must not contain any
backend-specific code. Move view lookup to _view_target field
set by each event backend during fetch. Move XRefreshKeyboardMapping
and XFilterEvent into x11_fetch. Selection and DND handling removed
from middle layer (handled by extraEventHandler in the WM layer).

The _x11_raw field remains in WMEvent for now (used by src/event.c
and other WM-layer code that still needs the raw XEvent), but the
middle layer no longer touches it.
2026-05-14 20:24:05 +02:00
Levi Neely ed2f825ca0 WINGs/wfont_wl: fix text y-offset in draw_image_string
Don't add ascent offset — pango_ft2_render_layout renders from the
top of the layout, not from the baseline. The extra ascent was
pushing text below the visible area of the text field.
2026-05-14 19:12:36 +02:00
Levi Neely 213f5a6528 WINGs: move updateDisabledMask to render backend vtable
Add create_disabled_mask to W_RenderBackend. X11 backend uses
XCreatePixmap + stippled GC fill. Wayland backend creates a
pixman a8 checkerboard mask. Middle layer (wbutton.c) dispatches
through vtable — zero X11 code remains.
2026-05-14 17:58:33 +02:00
Levi Neely 2910e73878 WINGs/widgets: move makePixmap calls to common init
Widget pixmaps (checkbox, radio, arrows, etc.) were created inside
W_X11PlatformInit, so they were NULL in Wayland mode. Since
makePixmap now uses RImage+RConvertImage (backend-neutral), move
all makePixmap calls to common init after platform_init.
2026-05-14 17:11:31 +02:00
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 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 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 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 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 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 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 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