wayland: Phase 68 — placement.c: safe overlap calculation without frame

Guard all frame->core and frame->workspace dereferences in placement.c
against NULL frame pointers (Wayland windows have no WFrameWindow):

- calcSumOfCoveredAreas: skip windows without frame (no stacking level
  or geometry available via frame; Wayland window client geometry is
  tracked separately in wwin->client.* and wwin->frame_x/y).

- window_overlaps: add early-return path for frameless windows that uses
  wwin->client.{width,height} and wwin->frame_x/y for the overlap test,
  bypassing the frame->core stacking level check.

- getPlaceOrigin (icon-placement helper): guard frame->workspace reads
  for WCLASS_MINIWINDOW and WCLASS_WINDOW parent types using logical-OR
  with the wwin->workspace fallback.

Together these prevent NULL dereferences when smart/auto/cascade
placement iterates the managed-window list and encounters Wayland
windows alongside X11 windows.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-03-28 09:40:44 +01:00
parent e60dff8ffd
commit 2c55725bb6
2 changed files with 33 additions and 3 deletions

View File

@ -62,7 +62,9 @@ iconPosition(WCoreWindow *wcore, int sx1, int sy1, int sx2, int sy2,
ok = 1;
} else if (wcore->descriptor.parent_type == WCLASS_MINIWINDOW &&
(((WIcon *) parent)->owner->frame->workspace == workspace
((!((WIcon *) parent)->owner->frame ||
((WIcon *) parent)->owner->frame->workspace == workspace ||
((WIcon *) parent)->owner->workspace == workspace)
|| IS_OMNIPRESENT(((WIcon *) parent)->owner)
|| wPreferences.sticky_icons)
&& ((WIcon *) parent)->mapped) {
@ -73,7 +75,10 @@ iconPosition(WCoreWindow *wcore, int sx1, int sy1, int sx2, int sy2,
ok = 1;
} else if (wcore->descriptor.parent_type == WCLASS_WINDOW
&& ((WWindow *) parent)->flags.icon_moved
&& (((WWindow *) parent)->frame->workspace == workspace || IS_OMNIPRESENT((WWindow *) parent)
&& ((!((WWindow *) parent)->frame ||
((WWindow *) parent)->frame->workspace == workspace ||
((WWindow *) parent)->workspace == workspace)
|| IS_OMNIPRESENT((WWindow *) parent)
|| wPreferences.sticky_icons)) {
*retX = ((WWindow *) parent)->icon_x;
*retY = ((WWindow *) parent)->icon_y;
@ -268,6 +273,11 @@ static int calcSumOfCoveredAreas(WWindow *wwin, int x, int y, int w, int h)
test_window = test_window->prev;
for (; test_window != NULL; test_window = test_window->next) {
/* Phase 68: Wayland windows have no frame; skip them in the
* overlap calculation (their geometry is tracked in client.* but
* they have no X11 stacking level — treat as zero obstruction). */
if (!test_window->frame)
continue;
if (test_window->frame->core->stacking->window_level < WMNormalLevel) {
continue;
}
@ -277,8 +287,12 @@ static int calcSumOfCoveredAreas(WWindow *wwin, int x, int y, int w, int h)
tx = test_window->frame_x;
ty = test_window->frame_y;
/* Phase 68: guard frame->workspace with wwin->workspace fallback */
int tw_workspace = test_window->workspace;
if (test_window->frame)
tw_workspace = test_window->frame->workspace;
if (test_window->flags.mapped || (test_window->flags.shaded &&
test_window->frame->workspace == wwin->screen_ptr->current_workspace &&
tw_workspace == wwin->screen_ptr->current_workspace &&
!(test_window->flags.miniaturized || test_window->flags.hidden))) {
sum_isect += calcIntersectionArea(tx, ty, tw, th, x, y, w, h);
}
@ -308,6 +322,19 @@ window_overlaps(WWindow *win, int x, int y, int w, int h, Bool ignore_sunken)
{
int tw, th, tx, ty;
/* Phase 68: Wayland windows have no frame; use client geometry. */
if (!win->frame) {
tw = win->client.width;
th = win->client.height;
tx = win->frame_x;
ty = win->frame_y;
if ((tx < (x + w)) && ((tx + tw) > x) &&
(ty < (y + h)) && ((ty + th) > y) &&
win->flags.mapped)
return True;
return False;
}
if (ignore_sunken &&
win->frame->core->stacking->window_level < WMNormalLevel) {
return False;

View File

@ -58,6 +58,9 @@
# 25. (Phase 67) WWindow.workspace added; wWorkspaceForceChange uses it as
# fallback when frame==NULL so workspace switching is safe in Wayland
# (build-only check — workspace switch requires keyboard shortcuts).
# 26. (Phase 68) placement.c guards: calcSumOfCoveredAreas/window_overlaps
# skip frameless (Wayland) windows safely; frame->workspace accesses
# in icon-placement helpers use wwin->workspace fallback.
#
# This test grows as wl_backend vtable slots are implemented.
#