Commit Graph

228 Commits

Author SHA1 Message Date
Window Maker eaea7464b2 arch: drop USE_DOCK_XDND guards from shared src/
The XDND-on-dock feature was a configure-time toggle (--disable-xdnd)
gating ~25 #ifdef sites across shared src/.  This was a pre-Wayland
feature flag, not a backend distinction, but it polluted the policy
layer with build-time conditionals.

Make it unconditional:

  configure.ac    Remove --disable-xdnd and AM_CONDITIONAL.  XDND on
                  the dock is always built.
  src/Makefile.am Move xdnd.c from the if-USE_DOCK_XDND block into
                  the unconditional wmaker_SOURCES list.
  src/dock.h, dock.c, dockedapp.c, appicon.h, appicon.c, event.c,
  misc.c, startup.c, dialog.c, screen.h
                  Strip all #ifdef USE_DOCK_XDND/#endif pairs.  In
                  dockedapp.c the #else branch (rendering an 'XDnD
                  support was not compiled in' label) is dead and
                  removed.

Backend routing: the X11 backend continues to drive the XDND protocol
through xdnd.c via the existing xdnd_process_client_message /
xdnd_process_selection / xdnd_make_awareness vtable slots.  Wayland's
slots are no-ops (XWayland clients drop into the X11 path naturally
via wl_state.x_display).

src/ is now free of feature-flag guards related to DnD.
2026-05-24 08:55:43 +02:00
Window Maker d79f7b5243 arch: widen final void* vtable signatures to WMEvent*; event.c is _x11_raw-free
Three more vtable slots that took void* (intended for an XEvent*) widened
to take WMEvent*; the X11 impls extract _x11_raw internally:

  event_handle_extensions(WMEvent*)
  netwm_process_client_message(WMEvent*)
  xdnd_process_client_message(WMEvent*)

Also added a new client_message_forward(WMEvent*, WNativeWindow) slot for
the OffiX DND ClientMessage redirect (icon frame -> real client_win).
The X11 backend rewrites xclient.window and XSendEvent's it; the Wayland
backend does the same on wl_state.x_display for XWayland clients.

After this change, src/event.c contains zero _x11_raw references — the
last X11 escape from the shared event dispatch layer is closed.
2026-05-24 08:49:44 +02:00
Window Maker ee1e5b0f70 arch: move X11 locale init into X11 backend display_open
XSupportsLocale and XSetLocaleModifiers in main.c were the last
direct Xlib calls in src/main.c.  Move them into x11_display_open
(guarded by I18N) where they naturally belong.  The Wayland backend
does not need them — locale handling for native Wayland clients is
just standard libc, and XWayland clients still receive locale-aware
input via the wmaker-attached XWayland server's own setup.

main.c is now Xlib-free.
2026-05-24 08:47:16 +02:00
Window Maker 60d71f46b4 arch: usermenu key send through vtable; drop dead misc.c code
* usermenu.c notifyClient: replace XSendEvent KeyPress/KeyRelease
  synthesis with two wm_backend->client_send_key calls.

* New vtable slot client_send_key(win, keycode, modifier_mask, press).
  X11: synthesize XKeyEvent and XSendEvent.
  Wayland: same but on wl_state.x_display (XWayland clients).  Native
           Wayland clients deferred (would need
           zwp_virtual_keyboard_v1).

* misc.c: keysymToString was dead code inside #if 0 — removed.

After this change misc.c and usermenu.c carry zero direct Xlib calls.
2026-05-24 08:46:03 +02:00
Window Maker 9cca44c765 arch: move X11 modifier-keymap discovery into X11 backend
xmodifier.c contained x_reset_modifier_mapping which walked the X
server's modifier map via XGetModifierMapping / XFreeModifiermap to
discover the X11 modifier indices for Meta/Hyper/Super/Alt keysyms.
This was 4 direct Xlib calls in shared src/.

Refactor:
  src/xmodifier.c  — now only holds the modifier-mask state and the
                     portable wXModifierFromKey / wXModifierToShortcut
                     Label / wSetModifierMasks helpers used by shared
                     policy code.  No more Xlib symbols.

  src/backend/x11/x11_backend.c  — owns x11_reset_modifier_mapping,
                     called from x11_extensions_init.  Calls
                     wSetModifierMasks at the end so shared code
                     answers modifier lookups correctly.

  src/xmodifier.h  — drops wXModifierInitialize.  Wayland never needed
                     it; X11 calls the local x11_reset_modifier_mapping
                     directly.

The unused ModeMask static was dropped along the way.
2026-05-24 08:43:32 +02:00
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
Window Maker 1c1f261fb2 arch: eliminate _x11_raw escapes from event.c
Five _x11_raw accesses in shared event.c (the worst architectural leak)
removed by widening vtable signatures and moving X11-only logic into
the X11 backend:

  WME_SELECTION_REQUEST / WME_SELECTION_CLEAR
    * handle_selection_request/clear functions deleted from event.c
    * Reimplemented in x11_backend.c as x11_handle_selection_request/clear
      where they read _x11_raw internally and call XChangeProperty etc.
    * New vtable slots handle_selection_request / handle_selection_clear
      (WMEvent*).  Wayland: no-ops (wmaker UI does not own a WM_Sn
      selection on the X server).

  WME_CONFIGURE
    * event_randr_update vtable widened to (WMEvent*).
    * Root-window check (DefaultRootWindow) moved into x11 impl.

  WME_MAPPING
    * Dropped the if (xev) guard — keyboard_mapping_refresh already
      took WMEvent*.

  WME_SELECTION
    * xdnd_process_selection vtable widened to (WMEvent*).

Net: event.c is X11-free except for DefaultRootWindow uses elsewhere
that will be cleaned up in subsequent tasks.
2026-05-24 08:37:50 +02:00
Window Maker f2e49a8b67 menu: fix infinite recursion in findMenuWalk via brother
A WMenu's brother is a parallel copy of the same menu used when the
menu is torn off / buttoned.  The brother shares cascade pointers
that reference back into the original tree, so recursing into both
m->brother and m->cascades[i] cycled (brother->cascades[i] == m's
own cascade entry, which has its own brother, etc.) and overflowed
the stack on any cascaded menu.

Inline the brother hit-test instead of recursing into it.  Cascades
themselves are walked recursively as before so sub-sub-menus remain
reachable.
2026-05-24 08:25:14 +02:00
Window Maker 3fb9f3925f menu: recursive findMenu so sub-sub-menus respond to mouse
The previous implementation only checked one level of cascades —
scr->root_menu and scr->root_menu->cascades[i].  Sub-sub-menus
(cascade->cascade->...) were never checked, so hovering over a
sub-sub-menu's entries did not return the menu, and selectEntry
therefore could not open the next-level cascade or react to clicks.

Replace with a recursive walk over each top-level menu's full
cascade tree.  Pick the deepest mapped menu that contains the
pointer (deeper cascades render on top in the scene graph and
should win the hit-test).

X11 sidesteps this with XQueryPointer + XFindContext, which finds
any menu window via the X server's hit-test regardless of nesting.
2026-05-24 08:23:42 +02:00
Window Maker 31576e4b25 wayland: use set_buffer_with_damage for all in-place paints
wlr_scene_buffer_set_buffer treats same-pointer assignment as a
no-op — pixel updates to fb->image are not picked up.  Every paint
function in the backend mutates fb->image (or s->wlr_buf) in place
and then commits with the same pointer, so wlroots never re-rendered
the changed contents.

Convert all 15 sites to wlr_scene_buffer_set_buffer_with_damage(...,
NULL) which forces a full rerender.  This restores the menu paint
fix to its proper general form and addresses the clip workspace
number/title not appearing at startup, as well as latent staleness
in dock/drawer icon and balloon paint paths.
2026-05-24 08:13:57 +02:00
Window Maker e973406d95 framewin: guard handleButtonExpose against unset descriptor parent
wFrameWindowUpdateBorders calls wFrameWindowResize at line 356,
which (since commit f88dfac) calls frame_paint.  On X11,
frame_paint dispatches to wFrameWindowPaint which iterates
button descriptors and calls handleButtonExpose.  But the
descriptors' parent field is set later in wFrameWindowUpdateBorders
(after the resize call) — so during this first paint, fwin
(desc->parent) is NULL and the function segfaults at the
left_button comparison.

The Wayland backend skips wFrameWindowPaint via wl_frame_paint
returning 1, so it never hit this path.
2026-05-23 22:12:53 +02:00
Window Maker a1d9fdf9f1 wayland: fix orphan menu titlebars at startup
Top-level frame trees were enabled by default at creation. When
framewin.c then called wm_backend->window_map_raised(titlebar) at
frame creation time (necessary for X11 decoration semantics), the
titlebar's scene_buf became enabled. Combined with the always-enabled
tree, this made the titlebar visually rendered at the frame's
default spawn position — even for menus and dialogs that had not
been logically mapped yet. The visible orphan reflected whichever
submenu titlebar was painted last (e.g. 'Multimedia').

Fix: top-level frame trees now start DISABLED. wl_window_map and
wl_window_map_raised explicitly enable the tree when called on a
top-level frame_buf. This matches X11 semantics where a child window
is only visible if its parent window is mapped. Decoration children
(titlebar, buttons) being individually 'mapped' no longer produces
orphan visibility because the parent frame's tree gates their
visibility.
2026-05-23 22:07:41 +02:00
Window Maker ce5cea8679 wayland: destroy fb->tree in wl_frame_destroy
Frame_bufs that owned a wlr_scene_tree (top-level frames and the
fake_leader for dialogs) leaked their tree on destroy.  The scene_buf
was destroyed but the tree remained in the scene graph as an orphan,
causing stale rendering — most visibly as ghost titlebars near the
clip after closing a menu, since the leaked menu frame trees stayed
in the scene.
2026-05-23 21:29:38 +02:00
Window Maker c7e2b7ba88 wayland: fix dialog/menu hit-testing and parenting
Several related fixes for WINGs dialogs and menus that depend on
correct scene graph parenting and hit-testing:

1. fake_leader_create: now creates a wlr_scene_tree (not just a
   scene_buf). When the fake_leader is reparented into a WMaker frame,
   any content inside it (e.g. WINGs panel) is reparented as part of
   the tree, so it follows the WMaker frame's position when moved.

2. wl_client_reparent (frame_buf path): if the source frame_buf has
   a tree, reparent the tree (with all its children) instead of the
   bare scene_buf.

3. frame_buf_update_children_abs: new recursive helper to walk the
   entire descendant tree updating fb->x/y absolute tracking. Used
   by wl_window_move, wl_frame_configure, and wl_client_reparent.
   Without this, grandchildren (e.g. WINGs panel inside a fake_leader
   inside a WMaker frame) had stale fb->x/y after the WMaker frame
   was moved, causing click coordinate translation to be wrong and
   buttons to stop responding after dragging the dialog.

4. frame_buf_button_at: now walks up the scene tree checking ancestor
   enabled state. A frame_buf's scene_buf may be flagged enabled even
   when an ancestor tree is disabled (e.g. menu unmapped). Without this
   check, clicks could be incorrectly routed to ghost frame_bufs from
   recently-unmapped menus, causing root-menu reopen to require
   multiple clicks.
2026-05-23 21:27:19 +02:00
Window Maker bc25aa4b8a wayland: fix click delay after shade and modal dialog parenting
After shading a window, clicks on the lower titlebar would be routed to
the resizebar handler, requiring multiple clicks before one landed in
a region where frame_buf_button_at didn't return the (disabled) resizebar.

Two related bugs:

1. frame_buf_button_at iterated all child frame_bufs without checking
   enabled state. The shaded resizebar's bounds still recorded in
   fb->x/y/width/height but its scene_buf was disabled. Since the
   shaded resizebar was repositioned ON TOP of the titlebar, clicks
   in the overlapping region returned the (smaller, disabled)
   resizebar instead of the titlebar. Added an enabled-state check.

2. wlroots scene graph caches buffer dimensions for hit-testing.
   Mutating fb->base.width/height directly leaves stale bounds. Use
   wlr_scene_buffer_set_dest_size() whenever the buffer is resized.

Also fixes:
- WINGs dialog content was placed in WL_LAYER_FLOATING instead of
  under the parent frame's tree, so the content didn't follow the
  WM-managed decorations on move. Now parented under the frame tree
  and positioned at relative offset.
- wl_window_map called wlr_scene_node_raise_to_top on the client
  scene_node, which raised it above the titlebar within the frame
  tree. After unshade this hid the titlebar. Removed.
- xdg_activation focus path: raise the frame tree, not the client
  scene_node, for the same reason.
2026-05-23 21:08:19 +02:00
Window Maker 13101c53c3 wayland: fix resize by refactoring scene graph to relative coordinates
The scene graph was using absolute coordinates for all nodes with the
frame tree at (0,0). This caused the resizebar to be detached from the
window frame and resize to break because child nodes (titlebar, client
surface, resizebar) had to be manually repositioned on every move/resize.

Refactor to the correct wlroots model:
- Frame tree positioned at (frame_x, frame_y)
- All children use local offsets relative to the tree
- Moving the tree moves everything automatically

Additionally fix interactive resize:
- handle_toplevel_commit now syncs the WM frame to the client's actual
  committed buffer size, ensuring frame and client stay in lockstep
- Ensure client scene_node is always parented under the frame tree
- Simplify wl_window_resize to just send xdg_toplevel.set_size without
  blocking event loop dispatch
- Properly free old pixman images and detach stale buffers on resize
2026-05-23 20:13:07 +02:00
Ollie 2d5c80f332 wl_backend: fix resizebar texture and client frame_rel update on resize
1. Resizebar: wl_frame_paint_resizebar was painting a flat color buffer
   over the textured resizebar rendered by wl_frame_paint. Make it a
   no-op since the parent frame buffer has the correct texture.

2. Resize gap: client_synth_configure updates the client scene_node
   position but was not updating frame_rel_x/y. When frame_configure
   ran next (e.g. on subsequent move), it would recompute the client
   position using stale frame_rel values, causing the surface to jump.
   Now updates frame_rel_x/y from the new absolute position.
2026-05-23 19:34:56 +02:00
Ollie f88dfac8b9 framewin: repaint frame after configure/resize
On X11, resizing a frame triggers an Expose event which repaints the
decorations. On Wayland, no such event is generated, so the frame
(titlebar, resizebar) was never repainted after resize — leaving
stale decorations at the old width.

Call frame_paint after reconfigure in both wFrameWindowConfigure
and wFrameWindowResize.
2026-05-23 19:22:56 +02:00
Ollie 4f70ab6df5 wl_backend: fix resizebar click detection
frame_buf_button_at had a size threshold (width>30 || height>30) that
skipped resizebar frame_bufs during hit-testing. The resizebar is wide
but short (~8px), so it was always skipped. Clicks in the resizebar
area fell through to the parent frame, preventing resize.

Remove the size threshold. The smallest-area heuristic already ensures
buttons (small) are preferred over resizebars (large) when both match.
2026-05-23 19:20:18 +02:00
Ollie 4b338d11d0 wl_backend: fix client surface rendering with proper scene output commit
Client surfaces (e.g. foot terminal) were not updating after initial
map. Two issues:

1. wlr_scene_output_commit(scene_output, NULL) in wlroots 0.19 may
   skip rendering if it determines no damage is pending, even when
   client surfaces have committed new buffers.

2. Frame scheduling was dependent on host compositor timing.

Fix: Replace wlr_scene_output_commit with explicit build_state +
commit_state cycle which properly tracks damage. Also schedule a
frame unconditionally every loop iteration to ensure continuous
rendering in nested mode.
2026-05-23 19:14:57 +02:00
Ollie 1c96a93ac8 menu: add dock/clip/dock-position menus to findMenu lookup
findMenu() only checked root_menu, switch_menu, and window_menu.
Dock and clip menus were never found, so pointer motion over them
could not highlight entries or activate on release.

Add CHECK_MENU calls for scr->dock->menu, scr->clip_menu, and
scr->dock_pos_menu.
2026-05-23 19:04:17 +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 4c5f07f9ec Phase C complete: balloon tooltips + window opacity
C1 (slide animations): already works - misc.c calls vtable window_move
C2 (menu scrolling): pure policy code, already works
C3 (balloon tooltips): pixman text render to wlr_scene_buffer overlay
C4 (cursor themes): wlr_xcursor_manager already in place
C5 (window opacity): read _NET_WM_WINDOW_OPACITY, apply to frame +
    child buffers + client surface via wlr_scene_buffer_set_opacity
2026-05-23 14:46:18 +02:00
lkn f3cb593d0f fix: button bevel colors derived from titlebar background
Hardcoded white/dark bevel looked wrong against colored titlebars.
Derive highlight and shadow colors from the actual titlebar background
color (+33% for highlight, -33% for shadow) to match the titlebar
bevel style.
2026-05-23 14:18:34 +02:00
lkn 5a4d989a78 fix: titlebar button rendering — proper colors and bevel
- Background: matches titlebar background (sampled)
- Foreground: uses title text color (the color parameter)
- Pressed state: swaps fg/bg (inverted colors)
- Border: raised bevel when normal, sunken when pushed
- Icon pixels rendered in fg color (not raw XPM colors)
2026-05-23 14:16:44 +02:00
lkn a34d8281b9 fix: raise button scene_bufs above titlebar after painting
Buttons and titlebar are siblings in the same scene tree. The titlebar
scene_buf is created after buttons, so it sits on top and occludes them.
Raise button nodes to top after enabling them in wl_frame_paint_button.
2026-05-23 14:12:34 +02:00
lkn 0cf867d548 fix: enable titlebar button scene_bufs for click and visibility
Buttons were rendered into the titlebar buffer with their own scene_buf
nodes disabled. This made them invisible to wlr_scene_node_at and
required a fragile coordinate-based hit-test (frame_buf_button_at).

Switch to rendering each button into its own frame_buf image and
enabling its scene_buf node. This makes buttons:
- Visible as independent scene nodes
- Directly hittable by wlr_scene_node_at
- Properly clickable via the normal frame_buf_at path

Update frame_buf_button_at to use a size threshold (<=30px) instead
of the disabled-node check to identify button sub-windows.
2026-05-23 14:08:34 +02:00
lkn 9ed1c19d6b B5: drawer icon renders directional arrow on Wayland
Replace the one-liner wl_drawer_icon_paint with a full implementation
that draws a filled triangle arrow pointing toward the drawer expansion
direction (left when on_right_side, right otherwise), matching X11.
2026-05-23 14:03:33 +02:00
lkn 3687ff0533 B4: clip icon renders workspace number and name on Wayland
Replace the one-liner wl_clip_icon_paint (which only painted the base
tile) with a full implementation that overlays the workspace number at
top-center and workspace name at bottom, matching the X11 behavior.

Also adds workspace.h and dock.h includes for WWorkspace/WDock types.
2026-05-23 14:02:28 +02:00
lkn 3d1008529b B2: create dock_shadow frame_buf for icon drag ghost overlay
The dock icon drag code (appicon.c, dock.c) uses scr->dock_shadow as a
visual ghost showing the target dock slot. On X11 this is an InputOutput
window; on Wayland it was never created, making all drag shadow
operations no-ops.

Create dock_shadow as a wl_frame_buf with a scene_buffer in the overlay
layer, starting disabled. All existing vtable ops (window_move, map,
unmap, set_background_pixmap, stacking_restack) already handle
frame_bufs, so no additional plumbing needed.
2026-05-23 13:58:23 +02:00
lkn 403ee93ec4 fix: WINGs dialog click-to-focus lookup
The WINGs view ID is not in the context table — only the fake leader
(parent frame_buf) is registered. Walk up to parent_id for the
context_find lookup so the WWindow is found correctly.

Also removed the ID >= 0x20000000 guard so any frame_buf click
(including WM frames without a toplevel surface) triggers focus.
2026-05-23 13:53:39 +02:00
lkn 7fe8121913 fix: clicking WINGs dialog surface now focuses the window
The click-to-focus code only checked wl_toplevel_view surfaces
(real Wayland/XWayland clients). WINGs dialogs are frame_bufs,
not toplevel views, so view_surface_at returned NULL and focus
was never set.

Add fallback: when no toplevel surface is under the pointer,
check if a WINGs dialog frame_buf (ID >= 0x20000000) was hit
and focus its associated WWindow.
2026-05-23 13:51:45 +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
lkn 68d4301b9f fix: modal dialogs not receiving mouse clicks on Wayland
frame_buf_at() could not find WINGs dialog frame_bufs because they
have no tree wrapper (only a bare scene_buf in WL_LAYER_FLOATING).
After the walk-up stops at the level_tree bucket, Step 4 only checks
fb->tree, missing tree-less frame_bufs entirely.

Add Step 5: match tree-less frame_bufs whose scene_buf node is a
direct child of a level_tree bucket. This resolves clicks on WINGs
modal dialogs (Run dialog, info panels, etc.).
2026-05-23 13:37:11 +02:00
lkn 8fb4083416 fix: titlebar buttons not responding to clicks on Wayland
frame_buf_button_at() used fb->scene_buf->buffer as the filter to
distinguish invisible button sub-windows from visible titlebar/resizebar
nodes. But wlr_scene_buffer_create() sets an initial buffer reference,
so scene_buf->buffer was never NULL for buttons — causing the hit-test
to skip all of them.

The correct distinguisher is node.enabled: buttons have their scene
node disabled (they are composited into the titlebar buffer by
wl_frame_paint_button), while titlebars/resizebars have enabled nodes.
2026-05-23 13:31:44 +02:00
lkn 57a6497137 B1: fix appicon_show for Wayland (was no-op, icons never placed)
The Wayland backend already had full wl_appicon_paint and wl_icon_paint
implementations (tile + image composite + text + scene commit), but
appicon_show was a no-op stub. This meant app icons were never initially
placed or mapped when applications launched.

Fix: wl_appicon_show now calls paint_app_icon() (pure policy code that
handles PlaceIcon + wAppIconMove + wLowerFrame + window_map via vtable),
identical to the X11 backend.

Also mark A7 (placement) as verified — pure policy, zero backend calls.
2026-05-23 13:29:12 +02:00
lkn de0300d0fe A4: workspace switching badge for Wayland backend
Workspace switching (map/unmap) already worked via the vtable.
This commit adds the workspace name badge overlay:

- Create badge frame_buf in WL_LAYER_OVERLAY during screen init
- Implement wl_workspace_badge_render (pixman text rendering)
- Implement wl_workspace_badge_update (scene buffer refresh)
- Add workspace_badge_get_background vtable slot
- X11 backend: captures root window background (RGetXImage)
- Wayland backend: returns solid dark background
- workspace.c: replace direct RGetXImage/RCreateImageFromXImage
  with vtable call (zero backend guards in policy code)
2026-05-23 13:24:58 +02:00
Window Maker cc9fc26817 fix: event.c compile error — remove _x11_raw dependency in unmap handler
Replace broken xev->u.unmap.send_event check (WMEvent has no unmap
member) with unconditional withdraw=True when event comes from root.
Also remove unused XEvent variable in handleExpose.
2026-05-23 13:01:37 +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
Window Maker a519435bfa x11 doc 2026-05-23 11:10:25 +02:00
Window Maker 8d963e79ac fix: native XDG client rendering — schedule frame on surface commit
Added permanent surface_commit_listener to wl_toplevel_view that calls wlr_output_schedule_frame on every client buffer commit.
Previously only the initial-commit listener existed, which removed itself after sending the first configure — subsequent buffer updates (typing in foot/xterm) were not triggering re-renders.
2026-05-17 20:59:31 +02:00
Window Maker 0950b228af feat: Wave 2 — eliminate direct Xlib calls and #ifdef guards
- R.5: usermenu.c: XStringToKeysym→xkb_keysym_from_name, XSendEvent guarded
- B.1: appicon.c: XClearArea→wm_backend->window_clear
- A4.1: workspace.c: remove 5 USE_XINERAMA guards, unified backend-neutral
- R.7: window.c: remove 4 USE_XSHAPE guards, vtable dispatch
2026-05-17 20:26:43 +02:00
ollie 6628d74d38 Wave 1 complete: XEvent* → WMEvent* signature changes + crash fixes
All 8 signature change tasks done:
  A5.1  wSwitchPanelHandleEvent: XEvent* → WMEvent*
  A5.2  Remove XEvent synthesis in cycling.c
  B.3   wDockReceiveDNDDrop: XEvent* → WMEvent*
  E.3   wRootMenuPerformShortcut: XEvent* → WMEvent*
  E.4   wClientConfigure/wClientCheckProperty: X11 types → WMEvent*
  R.1   framewin.c: _x11_raw → WMEvent
  R.2   icon.c: _x11_raw → WMEvent
  R.3   menu.c: _x11_raw → WMEvent

Results:
- _x11_raw sites in src/: 16 → 9 (7 eliminated in policy code)
- Build verified clean
- Crash regression (use-after-free on dialog close) fixed:
  W_IsValidView() validates stale _view_target against view_table
  Scene graph nodes destroyed when WINGs toplevels close

Update ACTION_PLAN.md and WAYLAND_ROADMAP.md to mark Wave 1 complete.
2026-05-17 19:43:58 +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 5c6fa776a9 wayland: implement alt-tab window cycling and switch panel (A5)
Vtable slots implemented in wl_backend.c:
- window_set_background_pixmap: composite pixman image into frame_buf/WINGs view
- window_clear: fill frame_buf/WINGs view with transparent black
- pixmap_free: pixman_image_unref
- shape_combine_mask: wlr_scene_buffer_set_opaque_region from mask pixman image
- switchpanel_send_enter: focus-guard flag to suppress spurious focus on panel destroy
- keyboard_grab/keyboard_ungrab: suppress client key forwarding during alt-tab loop

WINGs view backing: wl_window_clear and wl_window_set_background_pixmap
fall back to W_GetViewBacking() for WINGs window IDs when frame_buf_find fails.

cycling.c: synthesize XEvent when _x11_raw is NULL (Wayland native events)
to prevent segfault in switchpanel event handling.

Alt-tab cycling works. Switch panel rendering still needs investigation.
2026-05-16 00:49:29 +02:00
Window Maker 37ecea7c07 wayland: implement pointer grab for icon drag-and-move
Implement wl_pointer_grab (type 3 WM policy grab) that suppresses
client pointer focus delivery during WM-internal drags while letting
WME_MOTION events flow to WMMaskEvent. Implement wl_pointer_ungrab
and wl_pointer_change_cursor (maps WCUR_* to xcursor names).

Fix button release handler to not terminate type 3 grabs early —
the policy code calls pointer_ungrab itself.

Fix overlay surface blocking hit-testing: the iconify animation's
full-screen overlay (WL_LAYER_OVERLAY) was left enabled after the
animation completed, causing wlr_scene_node_at to hit it instead of
frame_bufs. Now server_ungrab disables the overlay node after flush.
2026-05-15 23:36:17 +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
Window Maker a961c86d4b wayland: fix click-through and focus-toggle on overlapping windows
view_surface_at iterated toplevel_list in reverse using geometry alone
to find the view under the cursor. toplevel_list order is maintained
separately from scene Z-order: handle_pointer_button updated it on click
but stacking operations (wl_stacking_restack, wl_stacking_raise/lower)
did not. After any stacking operation the list order and visual order
diverged, so successive clicks at the same position returned different
views, causing focus to toggle between overlapping windows.

Fix: use wlr_scene_node_at as the authority on what is visually topmost,
then walk up to the fb->tree / window-root level (stopping when the
parent is a level_trees[] bucket), and scan toplevel_list only for the
ID-to-surface mapping of the matched node. This is the same approach
already used by frame_buf_at after the level-tree rewrite.

The scene graph is the single source of truth for Z-order.
2026-05-15 09:14:18 +02:00
Window Maker 245d0077b5 wayland: implement correct stacking model with scene-graph level trees
Three interlocking problems were present in the Wayland stacking
implementation.

1. Wrong scene-graph nodes targeted by stacking operations

Each managed window groups its frame pixels and client surface under a
single wlr_scene_tree (fb->tree):

  fb->tree
    fb->scene_buf       (frame decoration pixels)
    child_frame_bufs    (titlebar / resizebar sub-frames)
    v->scene_node       (client surface, reparented in)

wl_stacking_restack was raising fb->scene_buf -- a child inside fb->tree
-- instead of fb->tree itself, a no-op for inter-window ordering. Three
redundant loops then tried to separately raise the client surface and child
frames, also to no effect. wl_stacking_lower had the same bug.

Fix: raise/lower fb->tree in both functions so the entire window assembly
moves as one atomic unit.

2. Flat scene graph -- no structural level ordering

All nodes were direct children of scene->tree, so creation order and
raise_to_top calls determined Z-order. A normal window could accidentally
render above a floating window after any CommitStacking call.

Fix: introduce 9 wlr_scene_tree level buckets created at scene init time
in bottom-to-top order:

  0 WL_LAYER_BACKGROUND  background rect / wallpaper
  1 WL_LAYER_DESKTOP     WMDesktopLevel
  2 WL_LAYER_SUNKEN      WMSunkenLevel
  3 WL_LAYER_NORMAL      WMNormalLevel  (default for new frames)
  4 WL_LAYER_FLOATING    WMFloatingLevel / WINGs dialogs
  5 WL_LAYER_MENU        WMMainMenuWindowLevel / OR-redirect windows
  6 WL_LAYER_DOCK        WMStatusWindowLevel / dock panel surface
  7 WL_LAYER_FULLSCREEN  WMFullscreenLevel
  8 WL_LAYER_OVERLAY     WMModalPanel / WMPopUp / XOR overlay

Every scene node is assigned to the correct bucket at creation.
A new stacking_set_level vtable slot called from AddToStackList moves
fb->tree to the right bucket whenever a window is added or its level
changes via ChangeStackingLevel. X11 backend implements it as a no-op.

3. XDG client surface not reparented into fb->tree

For XDG toplevels the map handler called wManageWindow before creating
view->scene_node, so the reparent inside wl_client_reparent was a no-op.
The client surface then lived as a flat sibling of fb->tree in
WL_LAYER_NORMAL, never moving with its frame during stacking operations.

Fix: after creating view->scene_node, check if frame_id is already set
and do the deferred reparent immediately.

4. Hit-testing broken by level-tree hierarchy

frame_buf_at walked up from the hit scene node to the first direct child
of scene->tree. With level buckets that stopped at the level_tree node
instead of fb->tree, making every window in the same bucket appear to be
the same window. Client surfaces were not blocking clicks on frames
beneath them, and titlebar sub-frames were not distinguished from the
top-level frame, breaking move and resize initiation.

Fix: rewrite frame_buf_at with a two-pass approach:
  Pass 1 -- exact match: check if the topmost node is a child frame_buf
    scene_buf such as titlebar, resizebar, or button; return it directly.
  Pass 2 -- walk up stopping when parent is a level_tree bucket, then
    match that window-root node to a top-level frame_buf tree.
  Return NULL if the hit was on a client surface.

ROADMAP: mark A1 done.
2026-05-15 09:11:46 +02:00