diff --git a/src/shell/switcher/window_switcher.cpp b/src/shell/switcher/window_switcher.cpp --- a/src/shell/switcher/window_switcher.cpp +++ b/src/shell/switcher/window_switcher.cpp @@ -286,12 +286,19 @@ indexLiveToplevelsByWindowId(const CompositorPlatform& platform, std::unordered_ continue; } - const auto mappedId = platform.compositorWindowIdForToplevelInfo(info); - if (!mappedId.has_value() || mappedId->empty()) { - continue; + std::string key; + if (const auto mappedId = platform.compositorWindowIdForToplevelInfo(info); + mappedId.has_value() && !mappedId->empty()) { + key = canonicalWindowId(*mappedId); } - const std::string key = canonicalWindowId(*mappedId); + + // Generic wlroots compositors such as labwc do not provide a + // compositor-specific window ID. The wlr toplevel handle is stable + // for the lifetime of the window and is sufficient for switcher identity. + if (key.empty() && wlrHandle != 0) { + key = "toplevel:" + std::to_string(wlrHandle); + } if (key.empty()) { continue; } diff --git a/src/shell/bar/widgets/taskbar_widget.cpp b/src/shell/bar/widgets/taskbar_widget.cpp --- a/src/shell/bar/widgets/taskbar_widget.cpp +++ b/src/shell/bar/widgets/taskbar_widget.cpp @@ -5,6 +5,7 @@ #include "compositors/workspace_backend.h" #include "config/config_service.h" #include "core/deferred_call.h" +#include "core/process/process.h" #include "i18n/i18n.h" #include "render/core/color.h" #include "render/core/renderer.h" @@ -36,6 +37,18 @@ namespace { + [[nodiscard]] bool launchTaskbarOverview(const std::string& appId) { + constexpr const char* command = "noctalia-taskbar-overview"; + if (appId.empty() || !process::commandExists(command)) { + return false; + } + return process::runAsync({ + command, + "--app-id", + appId.c_str(), + }); + } + // Integer centering; optional odd spare pixel on the end side (right/bottom). [[nodiscard]] float centeredOffset(float extent, float content, float inset = 0.0F, bool oddSpareOnEnd = true) { const float inner = std::max(0.0F, extent - inset * 2.0F); @@ -373,6 +386,12 @@ void TaskbarWidget::activateOrLaunchPinned(const TaskModel& task) { return; } + const std::string overviewAppId = + !task.appId.empty() ? task.appId : (!task.desktopEntryId.empty() ? task.desktopEntryId : task.idLower); + if (launchTaskbarOverview(overviewAppId)) { + return; + } + const std::string cycleKey = !task.desktopEntryId.empty() ? task.desktopEntryId : task.idLower; std::size_t& cursor = m_groupedAppCycleCursor[cycleKey]; if (cursor >= windows.size()) { @@ -792,6 +811,9 @@ void TaskbarWidget::create() { } if (data.button == BTN_LEFT) { if (!cycleCandidates.empty()) { + if (cycleCandidates.size() > 1 && launchTaskbarOverview(current->appId)) { + return; + } std::size_t& cursor = m_groupedAppCycleCursor[cycleKey]; if (cursor >= cycleCandidates.size()) { cursor = 0;