diff --git a/src/window.c b/src/window.c index 8e65ae0..1ca8490 100644 --- a/src/window.c +++ b/src/window.c @@ -1171,13 +1171,17 @@ WWindow *wManageWindow(WScreen *scr, WNativeWindow window) /* to make sure the window receives it's new position after reparenting */ wWindowSynthConfigureNotify(wwin); } else { - /* Wayland: record geometry from normal hints; frame stays NULL */ + /* Wayland: record geometry from normal hints; frame stays NULL. + * Phase 67: store workspace in wwin->workspace since there is no + * frame->workspace slot; wWorkspaceForceChange uses this field + * when frame is NULL to avoid NULL dereferences on WS switch. */ wwin->client.x = x; wwin->client.y = y; wwin->client.width = width; wwin->client.height = height; wwin->frame_x = x; wwin->frame_y = y; + wwin->workspace = workspace; } /* Setup descriptors and save window to internal lists */ diff --git a/src/window.h b/src/window.h index 96a6bc4..42c74c0 100644 --- a/src/window.h +++ b/src/window.h @@ -294,6 +294,10 @@ typedef struct WWindow { int icon_w, icon_h; RImage *net_icon_image; /* Window Image */ WNETWindowType window_type; /* _NET_WM_WINDOW_TYPE (WNW_TYPE_*) */ + /* Phase 67: workspace slot for Wayland path (frame is NULL, so + * frame->workspace is unavailable; workspace operations use this + * field instead when !frame). */ + int workspace; } WWindow; #define HAS_TITLEBAR(w) (!(WFLAGP((w), no_titlebar) || (w)->flags.fullscreen)) diff --git a/src/workspace.c b/src/workspace.c index 39b3669..dfe333e 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -467,7 +467,10 @@ void wWorkspaceForceChange(WScreen * scr, int workspace) * but will create annoyance for every other application */ while (tmp) { - if (tmp->frame->workspace != workspace && !tmp->flags.selected) { + /* Phase 67: Wayland windows have no frame; use wwin->workspace + * as the workspace slot when frame is NULL. */ + int tmp_workspace = tmp->frame ? tmp->frame->workspace : tmp->workspace; + if (tmp_workspace != workspace && !tmp->flags.selected) { /* unmap windows not on this workspace */ if ((tmp->flags.mapped || tmp->flags.shaded) && !IS_OMNIPRESENT(tmp) && !tmp->flags.changing_workspace) { @@ -480,7 +483,7 @@ void wWorkspaceForceChange(WScreen * scr, int workspace) } /* also unmap miniwindows not on this workspace */ if (!wPreferences.sticky_icons && tmp->flags.miniaturized && - tmp->icon && !IS_OMNIPRESENT(tmp)) { + tmp->icon && !IS_OMNIPRESENT(tmp) && tmp->icon->core) { wm_backend->window_unmap(tmp->icon->core->window); tmp->icon->mapped = 0; } @@ -488,7 +491,10 @@ void wWorkspaceForceChange(WScreen * scr, int workspace) if (IS_OMNIPRESENT(tmp)) { WApplication *wapp = wApplicationOf(tmp->main_window); - tmp->frame->workspace = workspace; + if (tmp->frame) + tmp->frame->workspace = workspace; + else + tmp->workspace = workspace; if (wapp) { wapp->last_workspace = workspace; diff --git a/tests/wl-smoke-test.sh b/tests/wl-smoke-test.sh index ca81d56..a5b4783 100755 --- a/tests/wl-smoke-test.sh +++ b/tests/wl-smoke-test.sh @@ -55,6 +55,9 @@ # 24. (Phase 66) XDG popup initial configure scheduled so context menus and # autocomplete dropdowns can commit first buffer without stalling # (build-only check — weston-simple-shm creates no popups). +# 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). # # This test grows as wl_backend vtable slots are implemented. #