Previously wm_instance was set to the window title, but docked icons
store app_id as their wm_instance. This mismatch caused
wDockTrackWindowLaunch to fail matching the new window to the docked
icon, resulting in a duplicate free-floating appicon being created.
Add the solid colored title background rectangle with light/dim bevel
edges that X11 draws via drawIconTitleBackground. This gives miniwindow
icons their characteristic "flat" title bar appearance, distinguishing
them from appicons which lack this bar.
wIconPaint already handles dock dots/stipple for docked appicons.
wAppIconPaint was redundantly calling appicon_paint_dock_dots again.
Reduce it to just wIconPaint(aicon->icon). Remove dead WS_INDICATOR
code (was #undef in wconfig.h).
Same pattern as 7530f1a: application.c, actions.c, client.c, and
defaults.c all called the raw backend paint, missing dock dots.
Now all go through wAppIconPaint for consistent indicator rendering.
Multiple places in dock.c and dockedapp.c called
wm_backend->appicon_paint directly, bypassing wAppIconPaint which
adds dock dots and launching stipple. Replace all with wAppIconPaint
so indicators are always drawn.
The dock_shadow was rendering above the dragged icon because:
1. It was in WL_LAYER_OVERLAY/DOCK, above the dock icons in WL_LAYER_FLOATING
2. wl_stacking_restack could not order nodes across different parent trees
3. wl_window_map auto-raised on map, undoing any prior restack
Fixes:
- Place dock_shadow in WL_LAYER_FLOATING (where WMDockLevel=5 maps)
- Rewrite wl_stacking_restack to reparent nodes into the same tree
and use wlr_scene_node_place_below for guaranteed ordering
- Remove auto-raise from wl_window_map (explicit wRaiseFrame handles it)
The dock ghost shadow was in WL_LAYER_OVERLAY rendering above dock icons.
Move to WL_LAYER_NORMAL and lower to bottom so it renders beneath the
dock icons (WL_LAYER_DOCK) during icon drag, matching X11 behavior
where the ghost shows as a position marker below the real icon.
Move the appicon_paint_dock_dots call into wIconPaint itself (after
icon_paint), so that ANY repaint of a docked appicon includes dots
and launching stipple. Previously, the dots were only drawn from
wAppIconPaint and the observers, but other repaint paths (pointer
events, window_clear) would erase them.
Remove the now-redundant calls from appearanceObserver and
tileObserver since wIconPaint handles it.
dockIconPaint was calling wm_backend->appicon_paint directly, which
bypasses wAppIconPaint and its appicon_paint_dock_dots call. This meant
docked icons never got their dots drawn at startup.
Call wAppIconPaint instead so the full paint path (tile + dots + stipple)
executes for all docked appicons.
On Wayland there are no Expose events, so when tileObserver or
appearanceObserver repaints an icon (via update_icon_pixmap or
window_clear), the dock dots drawn by appicon_paint_dock_dots
were lost. Explicitly re-trigger dock dots painting for docked
appicons after the observer repaint.
Replace the no-op wl_noop_appicon_paint_dock_dots with a real
implementation that draws:
- 3 white dots with black shadow for docked+not-running icons
- Checkerboard dimming (stipple) for launching icons
Dot geometry matches the X11 backend: positioned at 4m/9m/14m
horizontally, icon_size-6m vertically (m = icon_size/64, min 1).
wl_create_rimage_from_drawable only looked up frame_buf IDs, but
icon->pixmap on Wayland is a raw pixman_image_t* from RConvertImage,
not a frame_buf ID. When frame_buf_find fails, fall back to treating
the drawable pointer as a pixman_image_t* directly.
This fixes the ghost dock shadow (semi-transparent overlay shown
during icon drag) which was silently failing because MakeGhostIcon
returned WM_NATIVE_NONE.
The clip icon was not rendering properly because:
1. An early return prevented painting when workspaces were not yet
initialized (moved the check so base tile always paints)
2. The filled triangle arrows (top-right and bottom-left) drawn by
X11 paintClipButtons were missing entirely
Add pixel-level triangle drawing matching the X11 implementation
geometry: CLIP_BUTTON_SIZE-based sizing with 5px margins.
The upward compositing walk in render_wl_pixmap_copy, render_wl_fill_rect,
and wl_draw_string traverses from the repainted widget to the root view.
Previously, the commit at the end targeted the root view or searched its
direct children for a topLevel — this found the main window instead of
the dialog containing the widget that actually changed.
Fix: track the topLevel ancestor during the upward walk and commit that
specific view. This ensures dialog widgets (buttons, lists) have their
visual feedback rendered to the correct scene_buf.
frame_buf_hit now walks children recursively (up to 4 levels) instead
of only checking immediate children of top-level frames. This resolves
WINGs views nested inside fake_leader frames (icon chooser, message
dialogs), enabling event delivery to the correct WINGs widget.
When main_window_desc is the real WWindow (found via wWindowFor rather
than created by makeMainWindow), wApplicationDestroy must not call
wWindowDestroy on it — the window is still managed and will be destroyed
by wUnmanageWindow. Add shared_main_desc flag to track ownership.
- application.c: wApplicationCreate now tries wWindowFor(main_window)
before creating a new frameless WWindow via makeMainWindow. For
Wayland native clients where main_window == client_win, this returns
the real WWindow with its frame, title, and updated wm_class/instance.
- window.c: Disable shared_appicon for Wayland native clients (no
client_leader or group_id). The shared_appicon logic replaces
main_window with a fake group leader ID, which breaks the
wWindowFor lookup and produces a frameless duplicate WWindow.
Fixes the kill dialog showing "application" instead of the window title
for Wayland clients.
For Wayland clients, wm_instance is the window title (often long and
non-descriptive for identification) while wm_class is the app_id which
is the application identifier. Prefer wm_class for the kill confirmation
dialog, falling back to basename(wm_instance) then "application".
- findMenu(): add icon_menu to the walk list so the appicon right-click
menu responds to pointer motion during its modal drag loop.
- dragScrollMenuCallback: remove the scrollable_menus gate so menus
scroll at screen edges during drag-select regardless of the
scrollable_menus preference (that preference controls the non-modal
scroll path in handleMotionNotify which does not run during the
menu modal loop).
view_surface_at() was double-subtracting the frame_rel offset. Since
v->x/v->y already represents the client content position (frame origin
+ frame_rel), the surface-local coordinates are simply px - v->x. The
bounds check now correctly tests against 0..width/height.
Call wApplicationDestroy after wUnmanageWindow in the XWayland unmap
handler, matching the XDG and X11 handleDestroyNotify paths. Fixes
XWayland appicons persisting after the application closes.
- wl_pointer_focus.c: In view_surface_at(), check frame bounds for
XWayland views before returning the surface. When pointer is over
frame decorations (titlebar, buttons, resizebar), continue the loop
so the frame_buf handles the event. Fixes titlebar buttons (close,
iconify, shade) not responding for XWayland applications.
- wl_xwayland.c: Set left_ptr cursor on the XWayland root window at
startup via XDefineCursor. Fixes the default X cursor (big X) showing
for X11 applications that do not set their own cursor.
Enable the full appicon drag-to-dock/clip workflow for native Wayland
clients:
- window.c: Set main_window = client_win for Wayland clients that lack
client_leader and window_group, so wApplicationCreate runs and
produces a WAppIcon.
- wl_xdg.c: Call wApplicationDestroy after wUnmanageWindow on toplevel
unmap, mirroring the X11 handleDestroyNotify path. Fixes appicons
persisting after app close.
- wl_event.c: Commit the wlroots scene in wl_event_flush so
slide_windows animation renders intermediate frames.
- backend.h, x11_backend.c, wl_icon.c, superfluous.c: Add
create_rimage_from_drawable vtable method so MakeGhostIcon can read
frame_buf pixels on Wayland for the dock shadow overlay.
- wl_icon.c, wl_stubs.c: Implement wl_icon_update_pixmap with
shadowed (dimmed) overlay for attracted icons.
- wl_dock.c: Disable the placeholder shm_surface dock panel now that
the real wmaker dock framework operates via frame_bufs.
Three changes to fix press-drag-release vs simple click semantics:
1. WME_ENTER no longer sets insideMenu. On Wayland, the enter event for
the menu surface fires too early (menu overlaps button), incorrectly
marking simple clicks as drag interactions.
2. WME_MOTION on menuView sets insideMenu=1 on the first motion,
initiating drag interaction. This matches the desired semantics:
moving the pointer into the menu after press establishes intent.
3. BUTTON_RELEASE close/select guard checks insideMenu only, not
event->window == menuView. A release on the menu surface without
prior motion (simple click on button where menu happens to be under
the pointer) no longer triggers selection.
popDownMenu() resets insideMenu=0 and highlightedItem=-1. When called before
the selection logic, the guard (insideMenu && highlightedItem >= 0) is always
false, so WMSetPopUpButtonSelectedItem is never called and the closed-button
display never updates.
Fix: capture the selection state (insideMenu, highlightedItem, enabled item)
into local variables BEFORE calling popDownMenu. Apply the selection
(WMSetPopUpButtonSelectedItem + action callback) AFTER popDownMenu.
Two concrete bugs fixed:
1. Popup reopen with 1x1 buffer: W_ResizeView returns early when view size
matches requested size. After 1x1 unmap, view->size.width/height was still the
original correct size, so resizeMenu never triggered wl_client_toplevel_resize.
Fix: set view size to 1x1 after replacing the buffer.
2. Selected item not updating button display: render_wl_pixmap_copy cascade
walks up to rootView (no WLClientToplevel) and commits it (no-op). After
paintPopUpButton, the mainAppView backing is updated but never committed.
Fix: when the cascade reaches rootView, fall back to committing the first
topLevel child that has a client backing.
NULL-buffer unmap requires a configure/ack cycle before the next real buffer
commit. The compositor may not send a configure event for a NULL unmap,
leaving the surface stuck at configured=0 on reopen.
Fix: replace the popup buffer with a 1x1 transparent buffer on close.
This hides the popup visually without triggering an xdg unmap. The surface
stays configured and alive. On reopen, resizeMenu (now always called in
popUpMenu) creates a correct-size buffer via wl_client_toplevel_resize.
wl_redisplay then paints into the new buffer and commits immediately.
No configure/ack cycle needed.
Revert the 1x1-buffer approach which caused pointer focus issues. Return
to NULL-buffer unmap which correctly hides the popup. The configure event
from the NULL unmap is dispatched in wl_map via W_WLClientDispatchPending
after wl_redisplay and before returning, ensuring the surface is
configured before the user can interact with the popup.
NULL-buffer unmap triggers a wlroots xdg_surface unmap, which requires a
configure/ack cycle before the next buffer attach. This creates a race
window where the popup reopen cannot commit its real buffer yet, causing
the click to hit the main window instead of the popup.
Fix: replace the popup buffer with a 1x1 transparent ARGB buffer instead
of attaching NULL. This hides the popup visually (the tiny buffer is
invisible) without unmapping the xdg_surface. The surface stays configured
and alive, so the next popup open can commit a real buffer immediately
without waiting for a configure event.
Also: always call resizeMenu() in popUpMenu to ensure the backing buffer
is recreated at the correct dimensions after the 1x1 replacement.
In WINGs client mode (e.g. WPrefs), W_ViewSceneNodeSetEnabledFn was never
set because the compositor-side wl_backend.c does not run in the client
process. When popup close calls wl_unmap, the function pointer was NULL,
so the scene node was never disabled and the popup remained visible.
Fix: during W_WLClientInit, if W_ViewSceneNodeSetEnabledFn is still NULL
(unset by compositor), set it to wl_client_scene_node_set_enabled which
calls recycle (destroy xdg_toplevel + wl_surface) on disable and remap
(recreate from scratch) on enable. This ensures the client-side popup
lifecycle correctly removes and recreates the surface, eliminating stale
pixels without depending on compositor-side function pointers.