Commit Graph

303 Commits

Author SHA1 Message Date
Ollie 8a9e400fd5 session: remove debug prints from wl_prop_get_wm_class 2026-05-28 22:36:06 +02:00
Ollie a117a9e437 session: debug prints in wl_prop_get_wm_class to diagnose xterm save failure 2026-05-28 22:34:36 +02:00
Ollie 0a03ff03d7 wl_backend: fix prop_get_wm_class return value (0=fail, 1=success) — broke session save 2026-05-28 22:18:37 +02:00
Ollie 0abaf1fefa session: save/restore window state for Wayland native clients (match by app_id) 2026-05-28 22:14:32 +02:00
Ollie 1bcd815001 clipboard: make store idempotent to avoid re-init of in-use data source 2026-05-28 21:32:10 +02:00
Ollie adf79141b2 dnd: cross-client motion/drop handler with MIME type routing 2026-05-28 20:29:26 +02:00
Ollie 39b63a8184 DND: compositor-internal drag icon overlay + cursor feedback + cross-client wiring 2026-05-28 19:35:41 +02:00
Window Maker b714cb783d x11: fix menu rendering, balloon tooltips, clip arrows, and event handling
Menu entry painting:
- Add drawFrame() calls for 3D beveled entries (WTEX_SOLID)
- Add menu_text_clearance to text Y positioning
- Add left-side indicator drawing (radio/check/snap pixmaps)
- Add indicator X offset (MENU_INDICATOR_SPACE)
- Fix disabled+selected text color
- Fix texture-aware background clearing
- Add cascade arrow for submenu entries

Balloon tooltips:
- Implement x11_balloon_show() with text and mini-preview rendering
- Previously was a no-op stub

Clip arrows:
- Draw workspace-switching triangles on clip icon
- Previously stubbed out

Event handling:
- Add MapRequest, ConfigureRequest, ReparentNotify translation to
  xev_to_wme() in WINGs/wevent_x11.c
- These WM-critical events were silently dropped, preventing new X
  clients (e.g. xterm) from being managed
2026-05-25 17:04:30 +02:00
Window Maker fe2ec1fb9e wayland: pump client display in main loop for close button support
In-process WINGs clients have their own wl_display connection that
needs to be dispatched for xdg_toplevel.close to be received. Add
W_WLClientDispatchPending() and call it each main loop iteration
so protocol events reach the client-side handlers promptly.
2026-05-25 13:32:59 +02:00
Window Maker 94157394d7 wayland: fix close button for WINGs clients by flushing after send_close 2026-05-25 13:31:38 +02:00
Window Maker d5bc733842 wayland: directly synthesize close event for in-process WINGs clients
The xdg_toplevel.close protocol message requires the client to dispatch
its wl_display, but in-process WINGs clients may not do so promptly.
Directly enqueue the WME_CLIENT_MESSAGE/deleteWindowAtom event from
wl_client_close so the closeAction fires on the next WINGs event drain.
2026-05-25 13:05:42 +02:00
Window Maker 4442380d50 wayland: derive menu colors from appearance preferences
Menu background colors were hardcoded. Now uses:
- scr->select_color for selected item background
- scr->menu_item_texture->normal for unselected background
- scr->menu_item_texture->dim/light/dark for cascade arrow

Text colors already used scr->select_text_color, mtext_color, dtext_color.
2026-05-25 13:01:14 +02:00
Window Maker 40295223c6 wayland: match X11 cascade arrow style with 3D shaded lines
Replace the filled triangle with three lines matching the upstream X11
implementation: a dim top edge, light bottom edge, and dark left edge,
forming a 3D right-pointing triangle indicator for submenu entries.
2026-05-25 12:59:35 +02:00
Window Maker 95c4101ed3 wayland: fix submenu cascade arrow to point right
The triangle was drawn with increasing width from left to right,
making it point left. Reverse the vertical span so the widest part
is on the left and it tapers to a point on the right.
2026-05-25 12:58:39 +02:00
Window Maker b79f699a35 wayland: call W_CheckTimerHandlers in event loop for workspace fade
WINGs timers (used by workspace name fade animation) were never firing
because the compositor event loop never called W_CheckTimerHandlers.
This function is normally invoked by WMNextEvent, but the compositor
uses a custom loop. Add the call so timers fire each iteration.
2026-05-25 12:57:12 +02:00
Window Maker 7ea6a7ac88 wayland: workspace name badge with transparent background and fade
The workspace name display was rendering with an opaque black background
and never fading out. Fix by:
- Using transparent (alpha=0) background instead of black
- Returning RGBA images from badge_render and badge_get_background
- Preserving alpha channel in badge_update instead of hardcoding 0xFF

This allows the fade animation (RCombineImagesWithOpaqueness) to work
correctly, blending text with decreasing opacity over a transparent
background until the badge disappears.
2026-05-25 12:55:38 +02:00
Window Maker 172e226947 wayland: fix NULL dereference in wl_pointer_query_full
wWorkspaceForceChange passes NULL for root_x/root_y when it only needs
the child window. Add NULL checks before dereferencing these pointers.
2026-05-25 12:51:47 +02:00
Window Maker f1ded24294 WPrefs/wayland: fix icon preview one-click-behind with extra dispatch
WINGs button callbacks trigger wl_redisplay which commits the client
surface, but the compositor only processes that commit on the next
wl_event_loop_dispatch. Add a zero-timeout dispatch after handling
WINGs events so client commits are processed immediately, making
the next scheduled frame render the updated content.

Also revert posF redisplay back to posVF (posF caused gray flash).
2026-05-25 12:49:00 +02:00
Window Maker 69db74b3a6 wayland: fix frame pacing regression, schedule frame after dispatch
The extra wlr_scene_output_commit broke frame pacing in nested mode by
consuming the host frame callback. Instead, move wlr_output_schedule_frame
to after wl_event_loop_dispatch so client commits processed during
dispatch are rendered on the next frame event.
2026-05-25 12:45:25 +02:00
Window Maker ee434b024a wayland: commit scene after dispatch to fix one-frame-behind rendering
Client surface commits arrive during wl_event_loop_dispatch but may be
processed after the frame event has already rendered the old state. Add
an additional wlr_scene_output_commit after dispatch to immediately
pick up any new client content, fixing the one-interaction-behind
visual update issue in WINGs clients like WPrefs.
2026-05-25 12:43:55 +02:00
Window Maker b94bc2ce95 WPrefs: drop SIGUSR2, rely on inotify for defaults reload
SIGUSR2 is fundamentally unsafe in a multi-threaded compositor: library
threads (pango fontconfig) created after pthread_sigmask receive the
signal and crash. The Wayland event loop already has inotify watching
the defaults directory, so file changes are detected automatically
without any explicit signaling.

The early pthread_sigmask(SIG_BLOCK, SIGUSR2) is retained as a safety
measure to prevent stray SIGUSR2 from terminating the compositor.
2026-05-25 12:02:26 +02:00
Window Maker d8592f3b57 wayland: block SIGUSR2 early so library threads inherit the mask
SIGUSR2 was being delivered to pango fontconfig threads instead of the
signalfd because those threads were created before the signal mask was
set in wl_event_loop_run. Block SIGUSR2 at the very start of real_main
so all threads (including library-spawned ones) inherit the blocked
mask and the signalfd is the sole recipient.
2026-05-25 12:00:13 +02:00
Window Maker 8630a5ce95 wayland: handle SIGUSR2 via signalfd to reload defaults without dying
SIGUSR2 was not in the signalfd set, so it was delivered asynchronously
to the old signal handler which set WSTATE_NEED_REREAD. But the Wayland
event loop never checked that state flag, and the signal delivery itself
could crash the compositor.

Add SIGUSR2 to the signalfd set and handle it synchronously within the
event loop by calling wDefaultsCheckDomains directly.
2026-05-25 11:58:14 +02:00
Window Maker 9dee4f7a65 WPrefs: fix SIGUSR2 targeting wmaker instead of parent shell
The previous getppid() approach sent SIGUSR2 to the terminal process
(foot) rather than wmaker, killing the shell. Now wmaker exports
WMAKER_PID at startup and wl_send_wm_command reads it to signal the
correct process.
2026-05-25 11:55:14 +02:00
Window Maker 9a4438fb65 cursor: respect XCURSOR_THEME and XCURSOR_SIZE environment variables
The xcursor manager was hardcoded to NULL theme with size 24. Now reads
XCURSOR_THEME and XCURSOR_SIZE from the environment, matching the
behavior of other Wayland compositors like Sway.
2026-05-25 11:48:23 +02:00
Window Maker 703872bcca xwayland: route keyboard events via wlr_seat_keyboard_notify_enter
The XWayland focus path only called wlr_xwayland_surface_activate (X11
focus) but did not notify the wlr_seat about keyboard focus. Without
wlr_seat_keyboard_notify_enter, key events were never forwarded to the
XWayland surface via the Wayland transport.

Now wl_focus_set for XWayland surfaces sets the seat keyboard and calls
wlr_seat_keyboard_notify_enter, matching the XDG toplevel path.
2026-05-25 11:45:47 +02:00
Window Maker 5bff28efcd xwayland: fix rendering by switching from map_request to associate+surface.map
The map_request signal was never firing for managed XWayland surfaces,
preventing scene node creation and window management. Switch to the
standard wlroots 0.19 lifecycle: listen for associate (surface attached),
then hook surface->events.map (content committed) before creating the
scene node and calling wManageWindow.

Also fix wl_window_get_client_attrs to report VIEWABLE based on surface
existence rather than surface->mapped, since X11 geometry (xw->width/height)
is available before the wlr_surface maps.
2026-05-25 11:43:18 +02:00
Window Maker 9bb2d02254 debug: trace xwayland scene node creation 2026-05-25 10:35:07 +02:00
Window Maker b67d3a04fb wl_backend: send 640x480 configure for xwayland surfaces with tiny initial size
xterm starts with a 10x17 pixel window. The initial configure was
sending that size back (since > 0), so xterm rendered at 10x17.
Now use 640x480 default when the initial size is < 64px.
2026-05-25 10:33:18 +02:00
Window Maker d4d5240426 wl_backend: raise xwayland minimum size threshold to 64px
xterm's initial xw_surface size is 10x17 which passed the > 1 check.
Use >= 64 as the threshold for falling back to 640x480 default.
2026-05-25 10:09:49 +02:00
Window Maker 1733e3449c wl_backend: use map_request signal instead of associate for xwayland
The associate signal fires when a wlr_surface is linked to the
xwayland surface, but this can happen before or during new_surface
processing. map_request fires when the X11 client actually sends
MapRequest — at which point WM_CLASS is set and the client is ready
to be managed and shown.
2026-05-25 09:53:19 +02:00
Window Maker 72a592a402 wl_backend: handle already-associated xwayland surfaces
If the xwayland surface already has a wlr_surface when we register
listeners (associate event already fired), trigger the map handler
directly. This fixes xterm and other X11 clients that associate
their surface before the new_surface handler runs.
2026-05-25 09:48:42 +02:00
Window Maker 044a5b3486 wl_backend: use minimum 640x480 for xwayland surfaces with tiny initial size
xterm and other X11 clients create a small initial window then resize.
At map time, xw_surface->width/height may still be the initial tiny
value (e.g. 10x17). wManageWindow reads this and creates a tiny frame.
Use 640x480 as fallback when width/height <= 1.
2026-05-25 09:13:42 +02:00
Window Maker c243ac22ab wl_backend: don't skip XWayland surfaces without initial class/title
X11 clients (like xterm) create their window first, then set WM_CLASS
before mapping. The previous code skipped surfaces that had no class
AND no title at new_surface time, marking them override_redirect. This
prevented xterm and other well-behaved X11 apps from ever being managed.

Fix: log a warning but continue registering listeners. The surface will
be managed when it maps (associate signal) at which point WM_CLASS is
typically set.
2026-05-25 09:06:25 +02:00
Window Maker 8c8293acc9 debug: trace Z-order in wmaker_popup_apply; remove noisy debug 2026-05-24 19:23:43 +02:00
Window Maker b040b5c7fe wmaker-popup-v1: raise popup above parent and track parent moves
Two issues:
1. Popups rendered behind their parent toplevel because the scene node
   wasn't raised on apply. Add wlr_scene_node_raise_to_top so popups
   appear above the parent.
2. When the parent toplevel moved, popups stayed at their old screen
   position. In wl_window_move (compositor-side), after a regular
   toplevel's position changes, iterate all popups and re-apply those
   whose popup_parent is this toplevel so they track the parent.
2026-05-24 18:58:07 +02:00
Window Maker 27802e6d43 wmaker-popup-v1: add set_parent for parent-relative positioning
The previous version had set_position(x, y) in compositor-global
coordinates, but Wayland clients don't know their toplevel's screen
position — the editmenu and popup button code naturally compute
positions relative to the parent toplevel via accumulated view->pos.

Add set_parent(xdg_toplevel) request. When a parent is set,
set_position(x, y) is interpreted as offsets from the parent
toplevel's top-left corner.

Compositor side resolves the parent's wl_toplevel_view via
wlr_xdg_toplevel_from_resource → wl_find_view_by_xdg_surface,
then adds parent->x and parent->y to the requested offsets.

Client side (wclient_wl.c) tracks the first non-popup toplevel as
ctx->main_toplevel and calls set_parent on every popup wrapper to
anchor it to the application's main window.
2026-05-24 18:37:48 +02:00
Window Maker 1cf271932a debug: trace wmaker-popup-v1 protocol flow 2026-05-24 18:31:37 +02:00
Window Maker b5cc53a8a8 .gitignore: exclude generated wmaker-popup-v1 files; keep protocols/
Generated *-protocol.c and *-server-protocol.h files were accidentally
committed in the previous commit. The .gitignore was also excluding
the protocols/ source directory (where the XML lives). Fix both.
2026-05-24 18:28:51 +02:00
Window Maker 60348da411 Implement wmaker-popup-v1 Wayland protocol for client-driven popup positioning
Standard xdg_shell does not allow Wayland clients to position toplevels —
the compositor decides placement.  WINGs UI patterns require client-driven
positioning (e.g., a dropdown popup must appear directly below its trigger
button; menu editor items must be placed by the client at specific screen
coordinates).

This protocol lets the client wrap an xdg_toplevel with a wmaker_popup
object and call set_position(x, y) before the surface is mapped.  The
compositor honours the requested position when the surface becomes visible
and on subsequent set_position calls.

Files:
- protocols/wmaker-popup-v1.xml: protocol definition
- src/Makefile.am, src/Makefile: server-protocol.h + protocol.c generation
- WINGs/Makefile.am, WINGs/Makefile: client-protocol.h + protocol.c generation
- src/backend/wayland/wl_backend.c: wmaker_popup_manager global, get_popup
  handler that wraps an xdg_toplevel; set_position handler that updates
  view->popup_x/y and calls wmaker_popup_apply to move the frame_buf
  scene tree.  Apply runs at toplevel_map time too for pre-map positions.
- WINGs/wclient_wl.c: bind manager in registry, wrap popup toplevels with
  wmaker_popup, expose W_WLClientPopupSetPosition.
- WINGs/wview_wl.c: wl_move calls W_WLClientPopupSetPosition for popup
  toplevels so WMMoveWidget propagates to the compositor.
- WINGs/wevent_wl.c: wl_move_window also routes to popup positioning.
2026-05-24 18:27:55 +02:00
Window Maker 04e6b348b2 Implement popup-style toplevels for menu editor on Wayland
The WPrefs menu editor creates standalone draggable windows for each
menu item via W_CreateTopView. On X11 these are override-redirect
windows. On Wayland they were becoming framed XDG toplevels with
taskbar entries, cluttering the desktop with phantom 'WINGs...' tabs.

Implementation:
1. New W_View flags.popup field, set by editmenu's standalone mode
2. wclient_wl: when realizing a popup view, set xdg_toplevel app_id
   to 'wings-popup' as a hint to the compositor
3. wmaker compositor: detect 'wings-popup' app_id in toplevel_map,
   set borderless + skip-taskbar + skip-switchpanel flags, then call
   wWindowConfigureBorders to rebuild the frame without decorations
4. New W_EventBackend->window_begin_move vtable method:
   - X11: returns False (caller runs manual drag loop)
   - Wayland: calls xdg_toplevel_move, returns True (compositor drives drag)
5. editmenu's dragMenu calls window_begin_move first; on Wayland the
   compositor handles the entire drag, so the manual loop is skipped
2026-05-24 17:58:58 +02:00
Window Maker 777a5229eb wl_backend: fix shadowed sx/sy in wl_update_pointer_focus
The inner 'double sx, sy' declaration shadowed the outer one. When
view_surface_at succeeded inside the frame_buf check, the surface-local
coordinates were written to the inner variables and lost. The outer
sx/sy (used by wlr_seat_pointer_notify_enter/motion) remained
uninitialized, causing the client to receive garbage coordinates.

Also removed debug print from wclient_wl.c.
2026-05-24 16:14:10 +02:00
Window Maker 1d1f5bdc71 wl_backend: forward pointer events to client surface in client area
frame_buf_at() matches the entire window frame tree including the
client content area. This caused wl_update_pointer_focus to never
set seat pointer focus on the client surface, so Wayland clients
(like WPrefs) never received pointer enter/motion/button events.

Fix: when frame_buf_at returns a hit, also check view_surface_at.
If a client surface is found at the pointer position, use it instead
of treating the area as WM-internal decorations.
2026-05-24 16:04:25 +02:00
Window Maker 7a422330f6 defaults: use nanosecond mtime precision to detect rapid file writes
The user-facing root menu's 'Background → Images → Tiled' menu item runs
'wmsetbg -u -t image.jpg', which internally invokes wdwrite TWICE in
rapid succession:
  1. wdwrite WindowMaker SmoothWorkspaceBack NO
  2. wdwrite WindowMaker WorkspaceBack '(tpixmap, ...)'

Both writes complete within the same wall-clock second. The previous
mtime check used time_t (1-second precision):
  if (timestamp < stbuf.st_mtime)

After the first write, wmaker reads the file (only SmoothWorkspaceBack
changed; WorkspaceBack still old) and sets timestamp = current second.
The second write happens in the same second, so st_mtime equals
timestamp exactly — the check fails and the second write is silently
ignored. The user has to invoke the menu twice for the change to apply.

Fix: WDDomain.timestamp is now struct timespec (nanosecond precision).
New MTIME_NEWER() macro compares full timespec values. Two writes within
the same second now have distinct nanosecond components so both are
detected.

Also removed all debug logging.
2026-05-24 15:24:03 +02:00
Window Maker 861082f1ad wl_backend: react to IN_MOVED_TO, skip temp files
The atomic-rename pattern (mkstemp + rename) generates two relevant
events per save: IN_CLOSE_WRITE on the temp file (e.g.
WindowMaker.AjuyyW), then IN_MOVED_TO on the destination (WindowMaker).

Previously we reacted to IN_CLOSE_WRITE first and set oneShotFlag,
which then suppressed the IN_MOVED_TO. But at the time of
IN_CLOSE_WRITE, the rename hadn't happened yet — stat(WindowMaker)
returned the OLD mtime — so we'd skip and never re-check on the
subsequent IN_MOVED_TO either.

Fix: skip events on temp files (filenames containing a dot) and
react on IN_MOVED_TO for the actual destination filename. Direct
in-place writes (rare) are still handled via IN_CLOSE_WRITE for
non-temp filenames.

Also removed debug logging.
2026-05-24 15:03:46 +02:00
Window Maker c9a0fe8654 wl_backend: handle IN_MOVED_TO for atomic file replacement
WMWritePropListToFile uses an atomic write pattern: write to a temp
file, fsync, fclose, then rename to the destination. The inotify
directory watch sees:
  1. IN_CLOSE_WRITE on the temp file (WindowMaker.XXXXXX)
  2. IN_MOVED_TO on WindowMaker (the rename)

We were only handling IN_CLOSE_WRITE, but at that point the rename
hadn't happened yet, so stat(WindowMaker) returned the OLD mtime
and we skipped. The NEXT save's IN_CLOSE_WRITE would then catch
the PREVIOUS save's mtime change — hence the 'one click behind'
pattern users observed.

Now handles IN_MOVED_TO too, catching the actual atomic replacement.

Also removed debug logging.
2026-05-24 14:55:10 +02:00
Window Maker e97c76b582 wl_backend: use IN_CLOSE_WRITE instead of IN_MODIFY for inotify
IN_MODIFY fires during the write, before the file is fully written.
The Wayland event loop's 16ms dispatch catches this almost instantly,
reading stale/partial content. IN_CLOSE_WRITE fires after the writer
closes the file, guaranteeing the content is complete.

This fixes the 'one step behind' issue where background changes only
appeared on the second apply.
2026-05-24 14:45:45 +02:00
Window Maker 6ecdeca3fc wl_backend: fix background not updating on first apply
Two issues:
1. bg_image scene node wasn't re-enabled when switching from solid
   color back to an image background
2. No frame was scheduled after background change, so the compositor
   wouldn't repaint until the next natural frame tick

Now explicitly enables the bg_image node and calls
wlr_output_schedule_frame() after any background change.
2026-05-24 14:44:26 +02:00
Window Maker 94054aeec8 wl_backend: implement all background image fill modes
- tpixmap (Tiled): repeat image across screen
- spixmap (Scaled): stretch to exact screen dimensions
- cpixmap (Centered): place at center with background color fill
- mpixmap (Maximized): scale preserving aspect ratio, letterbox
- fpixmap (Filled): scale preserving aspect ratio, crop to fill

All modes now use RSmoothScaleImage for quality, respect the
background color (3rd texture argument) for uncovered areas, and
handle transparent images via RCombineImageWithColor.
2026-05-24 14:41:57 +02:00
Window Maker 07022840ac wl_backend: add X11 rgb.txt color name lookup
The named color table only had basic colors (black, white, red, etc.)
but Window Maker backgrounds use extended X11 color names like
deepskyblue4, tomato4, blue4. Now falls back to parsing
/usr/share/X11/rgb.txt for any unrecognized color name.

Fixes Sunset and other multi-color gradient backgrounds that use
X11 named colors.
2026-05-24 14:38:14 +02:00