The geometry view was sized using "%+05i, %+05i" but painted with
"%+5i , %+5i " (wider due to trailing spaces). This caused the
rendered text to exceed the view width. Use the same format for both
so the backing pixman image is correctly sized.
When switching VTs and returning, the DRM output may be destroyed and
recreated. Two issues caused the background to revert:
1. pending_background was freed after first application, so subsequent
output creation had nothing to reapply.
2. A new bg_rect (default purple) was created for each new output and
rendered on top of the existing bg_image scene buffer.
Fix: keep pending_background permanently, and disable the new bg_rect
when a background image is already active in the scene graph.
Native Wayland clients (e.g. plan9port acme/devdraw) warp the pointer
by locking it via zwp_pointer_constraints_v1, setting a
cursor_position_hint, then immediately destroying the lock. The
compositor is expected to warp the cursor to the hint on unlock.
Our handler just activated the constraint and ignored the hint. Now we
listen for the constraint destroy event and warp the cursor to the
hint position (converted from surface-local to global coordinates).
wlr_cursor_warp with NULL device silently fails (returns false) if the
target coordinates fall outside the output layout bounds. This made
pointer warping appear completely broken.
Switch to wlr_cursor_warp_closest which clamps to the nearest valid
point on the output layout, ensuring the cursor always moves.
The close button on internal windows (dock app settings, etc.) did
nothing because:
1. wwin->protocols.DELETE_WINDOW was never set for internal windows,
so windowCloseClick skipped the wClientSendProtocol call.
2. Even if it were called, wl_client_send_protocol just called
client_close which looks for an XDG/XWayland surface. Internal
windows have synthetic WINGs view IDs, not real surfaces.
Fix: set DELETE_WINDOW protocol flag in wManageInternalWindow, and
handle internal windows in wl_client_send_protocol by calling
wUnmanageWindow directly.
Add runtime bounds check before the titlebar texture blit. If the
destination pixman image is smaller than the blit dimensions, log a
diagnostic warning with the exact sizes and skip the blit instead of
corrupting the heap. This will help identify the conditions that
trigger the remaining heap overflow.
The titlebar child frame_buf can have a height smaller than tb_h
(fwin->top_width clamped to total_h). The existing bounds check only
verified width, not height. The blit loop wrote tb_h rows into a
shorter pixman image, overflowing into adjacent heap allocations.
This caused 100%% reproducible SIGSEGV in malloc (heap corruption
detected by glibc) on any operation following a frame paint where the
titlebar child was shorter than expected — e.g. opening the Run dialog
after a menu frame was painted.
Fix: check both width AND height before using the titlebar child buffer.
Fall back to drawing into the parent frame buffer (which is correctly
sized) when either dimension is insufficient.
wl_frame_configure and wl_window_resize reallocate fb->image (unref
old pixman image, create new one) but never updated the WINGs backing
table. W_GetViewBacking() continued returning the freed pointer.
Any subsequent draw into that backing (e.g. WMDrawString for titlebar
text) wrote into freed memory, corrupting the heap. The corruption
manifested as SIGSEGV/SIGABRT at the next malloc or free — in
fontconfig, Mesa, RReleaseImage, etc. depending on timing.
Fix: call W_RegisterBacking(fb->id, fb->image) after reallocation in
both resize paths.
Two issues with window shading:
1. wShadeWindow resizes the frame to top_width-1 tall. wl_frame_paint
used the unclamped fwin->top_width as titlebar blit height, writing
one row past the pixman buffer. Heap corruption detected by glibc on
next free (RReleaseImage) caused SIGABRT. Fix: clamp tb_h to total_h.
2. The parent frame scene_buf was only enabled when show_resizebar was
true. When the titlebar child buffer is too narrow (falls back to
drawing into the parent), the shaded frame had its scene_buf disabled
and the titlebar was invisible. Fix: also enable the parent scene_buf
when the titlebar was drawn into it (no titlebar child found).
wipe_desktop: iterate windows sending DELETE_WINDOW or killing (needed for
proper compositor shutdown).
get_shortcut_string, icon_select, icon_change_title: delegate to pure
WM functions that have no X11 dependency.
These were noops hiding calls to pure functions with no X11 deps:
- get_shortcut_string: calls GetShortcutKey (fixes missing menu shortcuts)
- icon_select: calls wIconSelect
- icon_change_title: calls wIconChangeTitle
Core code must not call backend directly. misc.c:slide_windows and
move_window now delegate to wm_backend->slide_windows/move_window.
Wayland backend implements both using scene node moves + event_flush.
wl_frame_paint is expensive (pixman blit per motion event).
Decorations content does not change during resize, only geometry.
Skip repaint while grab_type==2; repaint once on grab release.
Without schedule_frame, drag/resize updates sit in the scene graph
until the next natural vsync. At 144Hz this is 7ms max. Scheduling
after each motion ensures the next frame picks up the move/resize.
The 16ms dispatch timeout added up to 16ms of input latency.
4ms reduces this to ~4ms maximum.
Removing unconditional wlr_output_schedule_frame from the main loop
stops flooding the swapchain. The output frame callback in
handle_output_frame drives rendering at vsync naturally.
Two issues with window shading:
1. wShadeWindow resizes the frame to top_width-1 tall. wl_frame_paint
used the unclamped fwin->top_width as titlebar blit height, writing
one row past the pixman buffer. Heap corruption detected by glibc on
next free (RReleaseImage) caused SIGABRT. Fix: clamp tb_h to total_h.
2. The parent frame scene_buf was only enabled when show_resizebar was
true. When the titlebar child buffer is too narrow (falls back to
drawing into the parent), the shaded frame had its scene_buf disabled
and the titlebar was invisible. Fix: always commit and enable the
parent scene_buf (cleared to transparent, so unused areas are safe).
W_ViewDestroyedFn hook clears last_hovered_view when the pointed-to
view is destroyed. Prevents use-after-free in motion handler when
the hovering over a view inside a dialog that is then closed.
wl_update_pointer_focus reset cursor to left_ptr on every motion
event when no Wayland surface was under the pointer. WINGs compositor
views are pixman scene nodes, not Wayland surfaces, so surface was
always NULL over dialogs. Now preserve cursor when over frame_bufs.
Text fields set view->cursor = textCursor ("xterm") at creation.
When the pointer moves into a different WINGs child view, apply
the view cursor via W_SetCursorImageFn instead of waiting for
WME_MOTION with pointerGrabbed.
Motion events in dialogs (fake_leader frame_bufs with low IDs) were
not resolving the WINGs child view, so WME_ENTER was never sent to
the text field. Now look up the WINGs panel via client_leader.
When a dialog is closed, its views are freed but last_hovered_view
may still point to them. Use W_IsValidView() guard before accessing
the stale pointer.
When the pointer moves between WINGs child views (e.g. into a text
field), synthesize WME_ENTER/LEAVE events. This triggers the i-beam
cursor change in wtextfield.c which fires on WME_ENTER.
- Track current_buttons bitmask on press/release
- Set u.motion.state = current_mods | current_buttons so WINGs
text fields see WM_BUTTON1_MASK during click-drag selection
- Implement wl_set_cursor via W_SetCursorImageFn hook for i-beam
Implement wl_set_cursor() to forward cursor name strings to the
compositor via a function pointer. Initialize textCursor/defaultCursor/
invisibleCursor in wl_screen_init with xcursor name strings.
wApplicationDestroy needs main_window_desc (the wwin) to clean up
the appicon and remove the app from the screen list. Call it before
wUnmanageWindow which frees wwin. This restores the appicon to
"not running" state when a Wayland client closes.
wApplicationOf must be called before wUnmanageWindow because the
latter frees the WWindow struct. Accessing app->main_window_desc
afterward is a use-after-free.
Enables screen locker clients (swaylock, waylock) to lock the
session. On lock: confirms locked state to client. On new_surface:
configures lock surface to cover the output and adds it to the
scene overlay layer. On unlock: clears locked state.
After removing frame_bufs from the view_table, policy code like
update_icon_title still passes frame_buf IDs to WMDrawString.
These IDs (0x10000000 range) were being treated as raw pointers,
causing a segfault. Add W_GetFrameBufImageFn hook that resolves
frame_buf IDs to pixman images via frame_buf_find().
WMGetColorRGBDescription() returns wmalloc strings that were passed
directly to allocFrameBorderPixel without freeing. get_default_image()
and get_icon_image() leaked path strings from FindImage/get_icon_filename.
When destroying a frame_buf tree, any other frame_bufs whose trees
were reparented into it (e.g. fake_leaders) would have their
tree_destroy_handler fire on already-freed memory during cascade.
Detach their listeners and NULL their tree pointers before
destroying the parent tree.
When destroying child frame_bufs, the tree node was not destroyed
before wlr_buffer_drop freed the struct. Later, cascade destruction
of the parent tree would fire fb_tree_destroy_handler on the freed
child, corrupting the heap. Destroy the child tree explicitly first.
Call wlr_scene_buffer_set_buffer(NULL) before freeing the old pixman
image in every resize path (client configure, frame configure,
workspace badge, balloon). This ensures the scene graph never holds
a dangling reference to freed pixel data.
The in-place resize of titlebar pixman images continues to cause heap
corruption regardless of scene buffer detach order. Fall back to
drawing into the parent frame buffer when the titlebar is too narrow,
which is always safe since fb->image is already the correct size.
Frame_buf IDs (0x10000000-0x1FFFFFFF) were registered in the 256-entry
view_table alongside WINGs views, filling it with tombstones until
lookups failed. Now frame_buf IDs are excluded from the table; the 3
callers that passed frame_buf IDs to WMDrawString pass raw pixman
pointers instead.
Draw white text at 5x5 offsets to build a shape mask (like the
original XShape-based approach), then draw centered text at (2,2)
and apply the mask as alpha. This gives the same outlined text
appearance as the X11 version.
Add client_set_fullscreen backend vtable entry. Call
wlr_xdg_toplevel_set_fullscreen on enter/leave so clients
(e.g. Firefox) know to render content at full size.
Call wlr_scene_buffer_set_buffer(NULL) before freeing the old pixman
image so the scene graph cannot access freed data. Re-register the
backing table entry after creating the new image.
Call wlr_scene_buffer_set_buffer(NULL) before destroying the tree
and freeing the pixman images to prevent the scene graph from
accessing freed memory during its next render pass.
Use fixed-point x positions, strong upward initial velocity (-15 to
-21), gravity of 1 pixel/frame², only ~50%% of tiles, and run until
all pieces leave the screen. Full-screen scene buffer so pieces
can fly freely.
wl_frame_paint replaced the titlebar pixman image while the scene
graph could still hold a wlr_buffer reference to the old data.
Falling back to the parent frame buffer when the titlebar is too
narrow avoids the use-after-free.