When a WINGs client popup is unmapped (popDownMenu), the scene node is
disabled via W_ViewSceneNodeSetEnabledFn. But for WINGs client toplevels
(which have their own wl_surface + xdg_toplevel via libwayland-client),
the surface still holds its last committed buffer. Disabling the scene
node is not enough - the compositor still sees the surface as mapped.
Fix: add wl_client_toplevel_unmap which attaches NULL to the wl_surface
and commits, properly unmapping it from the compositor. Wire through
W_WLClientUnmapFn function pointer in wview_wl.c, called from wl_unmap
for topLevel views.
When a topLevel popup is unmapped, wl_redisplay(view-parent) clears stale popup pixels from the parent backing. But for rootView (common parent), the commit at the end of wl_redisplay is a no-op because rootView has no WLClientToplevel. The cleared backing was never pushed to any surface. Fix: iterate parent child list and force-commit every topLevel sibling, pushing the cleared backing to their wl_buffers.
When a WINGs popup is unmapped (popDownMenu) and remapped (popUpMenu),
the scene node is re-enabled via W_ViewSceneNodeSetEnabledFn, but its
Z-order position stays at its original insertion point. Other surfaces
mapped while the popup was disabled may now sit above it, making the
popup invisible when it reappears.
handle_toplevel_map (which calls wmaker_popup_apply to raise the
popup) only fires on the initial xdg_surface map event, not on
scene-node re-enable. Fix by calling W_WLClientPopupSetPosition on
every topLevel popup map, which triggers wmaker_popup_v1_set_position
→ wmaker_popup_apply → wlr_scene_node_raise_to_top.
When the pointer leaves the main button view to enter the popup surface,
the WME_LEAVE event fires for bPtr->view (which shares the same
handleActionEvents handler). This unconditionally cleared insideMenu=0
and highlightedItem=-1, causing the subsequent button release to fail
the selection check and not fire the action.
Fix: guard the leave handler with event->window == bPtr->menuView->window
so that clearing only happens when the pointer actually leaves the menu
view, not when it just leaves the main button on its way to the popup.
pointer_handle_enter always sent WME_ENTER to the toplevel root view
with _view_target=NULL, so child views (e.g. menuView) never received
proper WME_ENTER with correct local coordinates when the pointer entered
the popup surface during a held drag.
Fix: hit-test against the newly-focused toplevel on enter, find the
deepest child at the pointer position, and deliver WME_ENTER to that
child view with proper local coordinates and _view_target set.
Also fix pointer_handle_leave to deliver WME_LEAVE to the deepest
child (via wlc_ptr_child_focus) instead of the toplevel root view,
matching the enter side.
When a popup menu is opened during a button-held drag, the compositor
changes pointer focus to the popup surface as the pointer enters it.
But pointer_handle_motion always delivered events to the originally
grabbed view (wlc_ptr_grab), never hit-testing inside the popup.
This meant wpopupbutton.c received motion events targeted at the
main button view with coordinates relative to that view, not the menu.
Fix: in both pointer_handle_motion and pointer_handle_button (release),
check whether the grab target is within the currently focused toplevel.
If not (the pointer entered a different surface), use wlc_hit_test
against wlc_ptr_focused to find the correct child view with proper
local coordinates.
Also enable enter/leave synthesis during grabs when target changes,
so child views receive proper WME_ENTER/WME_LEAVE as the pointer
moves between them across the cross-surface boundary.
When the popup opens via ButtonPress on the main button, compute the
highlighted item from the pointer position relative to the menu view,
matching upstream WINGs semantics. Previously highlightedItem was set
to selectedItemIndex, which might be -1 (no prior selection), causing
the popup to open with no visible highlight until the first motion event.
The fix uses event->u.button.y_root - menuView->pos.y divided by item
height to determine which item the pointer is over when the menu appears.
This item is painted as highlighted immediately on open.
The WINGs view backend wl_pointer_grab was a no-op, meaning the
press-drag-release sequence for popup menus had no effect on compositor
state. On X11 this would call XGrabPointer to redirect events to the
menu window; the equivalent on Wayland is to activate the compositor
wl_pointer_grab which sets wl_state.grab_type and suppresses unwanted
cursor resets and axis leaks during the interactive drag.
Implementation: add function pointers W_WLPointerGrabFn and
W_WLPointerUngrabFn in wview_wl.c, initialized to NULL. The compositor
wires them to wl_pointer_grab / wl_pointer_ungrab at startup.
The WINGs view backend now delegates to the compositor instead of
silently returning.
The non-highlight path in paintMenuEntry only filled the row with gray
and returned early, erasing the item text, relief border, and indicator
pixmap. On Wayland this was immediately visible because the cascade+commit
on fill_rect commits every draw operation to the wl_surface.
Fix: after filling the gray background, redraw the relief border, the
item text (in black or darkGray depending on enabled state), and the
indicator pixmap for the selected item — matching what the highlight path
and makeMenuPixmap do.
Bug 1: Clicks on menu items did not select the correct item.
The WME_BUTTON_PRESS handler always called popUpMenu() which re-mapped
the already-open menu and reset highlightedItem to selectedItemIndex,
ignoring the click position. Since no motion event follows a
click-without-drag, the highlight was never corrected.
Fix: distinguish menuView vs main button events via event->window.
For menuView clicks, compute highlightedItem from click.y directly
without re-opening the menu.
Bug 2: Second popup open showed a blank gray box.
wl_unmap disabled the compositor scene node via W_ViewSceneNodeSetEnabledFn
but wl_map never re-enabled it. On re-map, the buffer was committed
to the wl_surface but the scene node stayed disabled.
Fix: re-enable scene node in wl_map before redisplay.
Reorder popUpMenu to:
1. Resize menuView before map (correct backing dimensions)
2. W_MapView first (wl_map calls wl_redisplay which fills background
and dispatches WME_EXPOSE — the old redisplay() before map was a
no-op on Wayland because wl_redisplay returns early when !mapped)
3. Copy makeMenuPixmap() output into menuView->window backing as a
safety net, ensuring the buffer has complete menu content
independent of expose-timing correctness
4. paintMenuEntry for initial highlighted item
This ensures the first visible popup buffer has all menu items
rendered regardless of the order in which the Wayland configure
and commit events arrive.
Three related fixes for WINGs popup menus on Wayland:
1. wl_client_toplevel_resize: update pending_w/h after resize
(wclient_wl.c:545-546). Without this, the configure handler sees
stale pending dimensions and creates a wrong-sized buffer,
discarding the one containing the menu text.
2. Export wl_redisplay_depth (wview_wl.c:288) so render and font
backends can detect when they are called from within a full
redisplay cycle vs. from an event handler.
3. Add cascade+commit to render_wl_fill_rect (wrender_wl.c:162-183)
and wl_draw_string (wfont_wl.c:183-208) when not inside a
redisplay cycle. This makes motion-driven highlight changes
(text color, background fill) immediately visible by compositing
up the view tree and committing the toplevel wl_surface.
WMEButton and WMEMotion are separate structs in the WMEvent union with different field layouts — u.motion.x is at a different memory offset than u.button.x. The WME_BUTTON_PRESS handler in wslider.c was calling valueForMousePoint(sPtr, event->u.motion.x, event->u.motion.y) which reads uninitialized memory on Wayland (memset zero = 0). On X11 this happened to work because the X11 event translator writes to both union members. Fix: changed all event->u.motion.x/y references to event->u.button.x/y in the WME_BUTTON_PRESS case.
Slider value changes (from click, drag, or programmatic set) call paintSlider to draw the new knob position into the pixman backing buffer, but the backing was never committed to the scene graph on Wayland. Added W_RedisplayView(slider->view) after each paintSlider call in: WMSetSliderValue, WMSetSliderMinValue, WMSetSliderMaxValue, and handleActionEvents (WME_MOTION/WME_BUTTON_RELEASE). The expose handler path does NOT get W_RedisplayView to avoid recursion.
The blue position indicator (gview — geometry view with blue-gray background,
white coordinate text) was visible during window move, but never disappeared
when the move ended.
Root cause: W_ViewSceneNodeSetEnabledFn was declared in wview_wl.c and
called by wl_unmap() to disable the view's scene buffer node, but
wl_backend.c never wired it up — the pointer was NULL.
Also: add auto-create of frame_buf for WINGs toplevel views not explicitly
reparented (switch panel, menus, gview), sync position from WINGs view on
commit, auto-realize children in wl_map/wl_map_subviews, and guard scene
node enablement against unmapped views.
Three issues prevented WPrefs from being managed by wmaker in X11:
1. W_X11OpenDisplay: XOpenDisplay("") fails; treat empty string as NULL
so it falls back to DISPLAY env var.
2. wevent_x11.c/wevent.c: MapRequest and ConfigureRequest events must
bypass WINGs view lookup (both _view_target in x11_fetch and
W_GetViewForWindow in WMHandleEvent) to reach DispatchEvent via
extraEventHandler.
3. wview_x11.c: x11_create_root must use RootWindow() not
scr->rootWin (which may be an intermediate window created by
RCreateContext for non-default visuals). Otherwise toplevel
WINGs windows are created as children of the wrong parent and
their MapRequest never reaches the WM.
WPrefs.app/main.c defaults display_name to "" (empty string).
W_X11OpenDisplay passed this directly to XOpenDisplay, but
XOpenDisplay("") is not equivalent to XOpenDisplay(NULL) — the
former fails while the latter uses the DISPLAY environment variable.
Treat empty display string as NULL so XOpenDisplay falls back to
the environment variable.
Also remove debug traces from event.c and x11_backend.c.
SubstructureRedirect events (MapRequest, ConfigureRequest) are delivered
to the root window. Since the root window has a WINGs view registered
(the WMScreen root view), W_GetViewForXWindow resolves it and
WMHandleEvent dispatches to the view handlers instead of falling through
to extraEventHandler (DispatchEvent).
This caused WINGs-based apps like WPrefs to never have their windows
managed by the WM - the MapRequest was silently consumed.
Fix: skip the view lookup for MapRequest and ConfigureRequest events so
they always reach DispatchEvent via extraEventHandler.
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
Selection and mapping events have mask 0 in the type table (matching
X11 semantics where they bypass event masks). Change the dispatch
check to deliver events with mask==0 to all registered handlers,
so these events are not silently dropped.
The wmeMaskForType table had WME_CLIENT_MESSAGE mapped to 0, so
WMHandleEvent never dispatched client messages to registered handlers.
The window close handler (registered with ClientMessageMask) was never
called. Set the correct mask so the deleteWindow protocol works.
The poll-based wlclient_dispatch with timeout 0 missed events that
were already buffered. Use prepare_read/read_events/dispatch_pending
which reads whatever is available on the socket without polling.
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.
During W_RealizeView, child views with mapWhenRealized triggered
wl_map which called wl_redisplay on the toplevel. This ran expose
handlers on a partially-realized widget tree, causing backing image
corruption from resizes during redisplay.
Fix: track realization depth with W_WL_Realizing counter. wl_map
skips redisplay when realization is in progress. After the outermost
W_RealizeView completes, trigger a single redisplay of the toplevel
to paint everything correctly.
The fill_rectangles call used view->size which can exceed the backing
image dimensions when a view is resized during realization without its
backing being reallocated. This wrote past the allocated buffer,
corrupting the heap and causing later pixman_image_composite32 crashes.
Use pixman_image_get_width/height of the actual backing instead.
Remove the verbose COMPOSITE fprintf and BAD composite warning that
were used for debugging. Keep the source/destination bounds clipping
as it correctly handles the case where view->size diverges from the
backing image dimensions during realization.
The font prefs panel crashed because wl_resize called wl_redisplay
while already inside a redisplay. This caused expose handlers to
trigger more resizes, creating unbounded recursion and memory growth
(backing images growing to 1024+ pixels wide). Skip the redisplay
from wl_resize when wl_redisplay_depth > 0 — the ongoing parent
redisplay will composite the resized child at its new size.
The previous source-only clamp was insufficient. Also check that both
src and dst have non-NULL pixel data, and clip the composite region to
the destination image dimensions to prevent out-of-bounds writes.
During W_RealizeView the WME_EXPOSE handler can trigger child resizes
that make view->size exceed the backing image dimensions. Clamp the
composite width/height to the source image actual size to prevent
out-of-bounds reads in pixman_image_composite32.
Font prefs panel crashed in pixman_image_composite32 during W_MapView
because a child view had zero width/height. Skip compositing for
zero-sized views.