From df1e8eb00878a0af287698f25288726417b51eea Mon Sep 17 00:00:00 2001 From: G7fya Date: Sun, 19 Apr 2026 15:48:12 +0000 Subject: [PATCH] desktop: refresh workspace appearance for workspace changes Fix workspace state updates so panels such as sfwbar can correctly track workspace-filtered taskbars under labwc. - remove restriction that skips workspace updates when the source is OSD - trigger output_update_workspace_appearance() after workspace change - return early when no view is present to avoid inconsistent updates This resolves incorrect behavior where sfwbar (filter = workspace) does not update properly under labwc, while it works correctly on sway. Related: https://github.com/LBCrion/sfwbar/issues/412 --- include/foreign-toplevel/foreign.h | 1 + src/foreign-toplevel/foreign.c | 59 ++++++++++++++++++++++++++++-- src/view.c | 8 ++++ src/workspaces.c | 15 +++++++- src/xdg.c | 9 +++++ src/xwayland.c | 9 +++++ 6 files changed, 97 insertions(+), 4 deletions(-) diff --git a/include/foreign-toplevel/foreign.h b/include/foreign-toplevel/foreign.h index bc226776..84d03620 100644 --- a/include/foreign-toplevel/foreign.h +++ b/include/foreign-toplevel/foreign.h @@ -8,6 +8,7 @@ struct foreign_toplevel; struct foreign_toplevel *foreign_toplevel_create(struct view *view); void foreign_toplevel_set_parent(struct foreign_toplevel *toplevel, struct foreign_toplevel *parent); +void foreign_toplevel_refresh(struct foreign_toplevel *toplevel); void foreign_toplevel_destroy(struct foreign_toplevel *toplevel); #endif /* LABWC_FOREIGN_TOPLEVEL_H */ diff --git a/src/foreign-toplevel/foreign.c b/src/foreign-toplevel/foreign.c index 4290ffd0..eca081c5 100644 --- a/src/foreign-toplevel/foreign.c +++ b/src/foreign-toplevel/foreign.c @@ -1,27 +1,75 @@ // SPDX-License-Identifier: GPL-2.0-only #include "foreign-toplevel/foreign.h" #include +#include #include "common/mem.h" #include "foreign-toplevel/ext-foreign.h" #include "foreign-toplevel/wlr-foreign.h" +#include "labwc.h" #include "view.h" struct foreign_toplevel { + struct view *view; + /* *-toplevel implementations */ struct wlr_foreign_toplevel wlr_toplevel; struct ext_foreign_toplevel ext_toplevel; - /* TODO: add struct xdg_x11_mapped_toplevel at some point */ }; +static bool +should_export_to_panels(struct foreign_toplevel *toplevel) +{ + struct view *view = toplevel->view; + + if (!view || !view->mapped) { + return false; + } + + if (view->visible_on_all_workspaces) { + return true; + } + + return view->workspace == server.workspaces.current; +} + +static bool +is_exported(struct foreign_toplevel *toplevel) +{ + return !!toplevel->wlr_toplevel.handle || !!toplevel->ext_toplevel.handle; +} + +void +foreign_toplevel_refresh(struct foreign_toplevel *toplevel) +{ + bool want, have; + + assert(toplevel); + + want = should_export_to_panels(toplevel); + have = is_exported(toplevel); + + if (want == have) { + return; + } + + if (want) { + wlr_foreign_toplevel_init(&toplevel->wlr_toplevel, toplevel->view); + ext_foreign_toplevel_init(&toplevel->ext_toplevel, toplevel->view); + } else { + wlr_foreign_toplevel_finish(&toplevel->wlr_toplevel); + ext_foreign_toplevel_finish(&toplevel->ext_toplevel); + } +} + struct foreign_toplevel * foreign_toplevel_create(struct view *view) { assert(view); struct foreign_toplevel *toplevel = znew(*toplevel); - wlr_foreign_toplevel_init(&toplevel->wlr_toplevel, view); - ext_foreign_toplevel_init(&toplevel->ext_toplevel, view); + toplevel->view = view; + foreign_toplevel_refresh(toplevel); return toplevel; } @@ -30,6 +78,11 @@ void foreign_toplevel_set_parent(struct foreign_toplevel *toplevel, struct foreign_toplevel *parent) { assert(toplevel); + + if (!toplevel->wlr_toplevel.handle) { + return; + } + wlr_foreign_toplevel_set_parent(&toplevel->wlr_toplevel, parent ? &parent->wlr_toplevel : NULL); } diff --git a/src/view.c b/src/view.c index 1d43fcfa..1e5a37bf 100644 --- a/src/view.c +++ b/src/view.c @@ -1581,6 +1581,10 @@ view_toggle_visible_on_all_workspaces(struct view *view) assert(view); view->visible_on_all_workspaces = !view->visible_on_all_workspaces; ssd_update_geometry(view->ssd); + + if (view->foreign_toplevel) { + foreign_toplevel_refresh(view->foreign_toplevel); + } } void @@ -1592,6 +1596,10 @@ view_move_to_workspace(struct view *view, struct workspace *workspace) view->workspace = workspace; wlr_scene_node_reparent(&view->scene_tree->node, workspace->view_trees[view->layer]); + + if (view->foreign_toplevel) { + foreign_toplevel_refresh(view->foreign_toplevel); + } } } diff --git a/src/workspaces.c b/src/workspaces.c index a1ed9112..6d89e631 100644 --- a/src/workspaces.c +++ b/src/workspaces.c @@ -24,6 +24,12 @@ #include "show-desktop.h" #include "theme.h" #include "view.h" +#include "common/macros.h" +//#include "desktop.h" +#include "foreign-toplevel/foreign.h" +#include "input/keyboard.h" +#include "labwc.h" +#include "menu/menu.h" #define EXT_WORKSPACES_VERSION 1 @@ -464,9 +470,16 @@ workspaces_switch_to(struct workspace *target, bool update_focus) /* Save the last visited workspace */ server.workspaces.last = server.workspaces.current; - /* Make sure new views will spawn on the new workspace */ + /* Make sure new views will spawn on the new workspace */ server.workspaces.current = target; + struct view *it; + wl_list_for_each(it, &server.views, link) { + if (it->foreign_toplevel) { + foreign_toplevel_refresh(it->foreign_toplevel); + } + } + struct view *grabbed_view = server.grabbed_view; if (grabbed_view) { view_move_to_workspace(grabbed_view, target); diff --git a/src/xdg.c b/src/xdg.c index 211a340d..b00958df 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -846,6 +846,11 @@ handle_map(struct wl_listener *listener, void *data) } view_impl_map(view); + + if (view->foreign_toplevel) { + foreign_toplevel_refresh(view->foreign_toplevel); + } + view->been_mapped = true; } @@ -856,6 +861,10 @@ handle_unmap(struct wl_listener *listener, void *data) if (view->mapped) { view->mapped = false; view_impl_unmap(view); + + if (view->foreign_toplevel) { + foreign_toplevel_refresh(view->foreign_toplevel); + } } } diff --git a/src/xwayland.c b/src/xwayland.c index 967364c5..47bc0779 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -823,6 +823,11 @@ handle_map(struct wl_listener *listener, void *data) } view_impl_map(view); + + if (view->foreign_toplevel) { + foreign_toplevel_refresh(view->foreign_toplevel); + } + view->been_mapped = true; } @@ -836,6 +841,10 @@ handle_unmap(struct wl_listener *listener, void *data) view->mapped = false; view_impl_unmap(view); + if (view->foreign_toplevel) { + foreign_toplevel_refresh(view->foreign_toplevel); + } + /* * Destroy the content_tree at unmap. Alternatively, we could * let wlr_scene manage its lifetime automatically, but this