From 5dfae0c45c08c2ee0649c96503296cfb52d09cf3 Mon Sep 17 00:00:00 2001 From: Marco Allegretti Date: Wed, 8 Apr 2026 19:07:37 +0200 Subject: [PATCH] Add task strip and Overview to navigation panel In convergence mode, show a running-app icon strip in the navigation panel using the existing TaskManager.TasksModel. Each icon activates its window on click, with an indicator dot for the active window. Replace the mobile task switcher button with a KWin Overview trigger: add triggerOverview() to TaskPanel (D-Bus call to kglobalaccel), swap the button icon to view-grid-symbolic, and enable the Overview effect in the envmanager KWin config when convergence mode is active. Wire convergenceMode and taskModel properties from NavigationPanelComponent through to NavigationPanel so the task strip populates from the existing TasksModel instance. --- .../qml/navigationpanel/NavigationPanel.qml | 90 +++++++++++++++++++ .../qml/NavigationPanelComponent.qml | 16 +++- containments/taskpanel/taskpanel.cpp | 7 ++ containments/taskpanel/taskpanel.h | 1 + envmanager/config.h | 3 +- 5 files changed, 112 insertions(+), 5 deletions(-) diff --git a/components/mobileshell/qml/navigationpanel/NavigationPanel.qml b/components/mobileshell/qml/navigationpanel/NavigationPanel.qml index fcac9bbe..242a58d8 100644 --- a/components/mobileshell/qml/navigationpanel/NavigationPanel.qml +++ b/components/mobileshell/qml/navigationpanel/NavigationPanel.qml @@ -9,6 +9,7 @@ import QtQuick import QtQuick.Layouts import QtQuick.Window import QtQuick.Effects +import QtQuick.Controls as Controls import org.kde.kirigami as Kirigami import org.kde.taskmanager 0.1 as TaskManager @@ -34,6 +35,10 @@ Item { property bool isVertical: false + // Convergence mode: show running-app task strip + property bool convergenceMode: false + property var taskModel: null + // drop shadow for icons MultiEffect { anchors.fill: icons @@ -133,6 +138,63 @@ Item { } } } + + // Running-app task strip for convergence (desktop) mode + ListView { + id: taskStrip + visible: root.convergenceMode && root.taskModel !== null && root.taskModel.count > 0 + orientation: root.isVertical ? ListView.Vertical : ListView.Horizontal + spacing: Kirigami.Units.smallSpacing + clip: true + interactive: contentWidth > width + model: root.taskModel + + delegate: NavigationPanelButton { + id: taskDelegate + required property int index + required property var model + width: taskStrip.orientation === ListView.Horizontal ? height : taskStrip.width + height: taskStrip.orientation === ListView.Horizontal ? taskStrip.height : taskStrip.width + + Kirigami.Theme.colorSet: root.foregroundColorGroup + Kirigami.Theme.inherit: false + iconSource: taskDelegate.model.decoration + enabled: true + shrinkSize: 0 + + onClicked: { + root.taskModel.requestActivate(root.taskModel.makeModelIndex(taskDelegate.index)); + } + + // Right-click context menu + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: taskContextMenu.popup() + } + + Controls.Menu { + id: taskContextMenu + Controls.MenuItem { + text: i18n("Close") + icon.name: "window-close" + onTriggered: root.taskModel.requestClose(root.taskModel.makeModelIndex(taskDelegate.index)) + } + } + + // Active-window indicator dot + Rectangle { + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottomMargin: Kirigami.Units.smallSpacing / 2 + width: Kirigami.Units.smallSpacing * 2 + height: width + radius: width / 2 + color: Kirigami.Theme.highlightColor + visible: taskDelegate.model.IsActive === true + } + } + } } states: [ @@ -200,6 +262,21 @@ Item { height: Kirigami.Units.gridUnit * 2 width: icons.width } + // Task strip: vertical layout — positioned between leftCornerButton (bottom) and leftButton (above middle) + AnchorChanges { + target: taskStrip + anchors { + horizontalCenter: parent.horizontalCenter + bottom: leftButton.top + top: undefined + } + } + PropertyChanges { + target: taskStrip + width: parent.width + // Fill space between leftCorner (bottom) and the nav button group + height: taskStrip.visible ? (leftButton.y - leftCornerButton.y - leftCornerButton.height - Kirigami.Units.smallSpacing * 2) : 0 + } }, State { name: "horizontal" when: !root.isVertical @@ -264,6 +341,19 @@ Item { height: parent.height width: Kirigami.Units.gridUnit * 2 } + // Task strip: horizontal layout — positioned between leftCornerButton (left) and leftButton (near center) + AnchorChanges { + target: taskStrip + anchors { + verticalCenter: parent.verticalCenter + left: leftCornerButton.right + right: leftButton.left + } + } + PropertyChanges { + target: taskStrip + height: parent.height + } } ] } diff --git a/containments/taskpanel/qml/NavigationPanelComponent.qml b/containments/taskpanel/qml/NavigationPanelComponent.qml index 76346045..6ec5e6fd 100644 --- a/containments/taskpanel/qml/NavigationPanelComponent.qml +++ b/containments/taskpanel/qml/NavigationPanelComponent.qml @@ -35,6 +35,10 @@ MobileShell.NavigationPanel { foregroundColorGroup: forcedComplementary ? Kirigami.Theme.Complementary : Kirigami.Theme.Window shadow: forcedComplementary + // Convergence mode: expose running-app task strip + convergenceMode: ShellSettings.Settings.convergenceModeEnabled + taskModel: tasksModel + MobileShellState.PanelSettingsDBusClient { id: panelSettings screenName: Screen.name @@ -68,16 +72,20 @@ MobileShell.NavigationPanel { // ~~~~ // navigation panel actions - // toggle task switcher button + // toggle task switcher button (KWin Overview in convergence mode, mobile task switcher otherwise) leftAction: MobileShell.NavigationPanelAction { id: taskSwitcherAction enabled: true - iconSource: "mobile-task-switcher" - shrinkSize: 4 + iconSource: ShellSettings.Settings.convergenceModeEnabled ? "view-grid-symbolic" : "mobile-task-switcher" + shrinkSize: ShellSettings.Settings.convergenceModeEnabled ? 0 : 4 onTriggered: { - Plasmoid.triggerTaskSwitcher(); + if (ShellSettings.Settings.convergenceModeEnabled) { + Plasmoid.triggerOverview(); + } else { + Plasmoid.triggerTaskSwitcher(); + } } } diff --git a/containments/taskpanel/taskpanel.cpp b/containments/taskpanel/taskpanel.cpp index 385a4e3a..fd17e650 100644 --- a/containments/taskpanel/taskpanel.cpp +++ b/containments/taskpanel/taskpanel.cpp @@ -31,4 +31,11 @@ void TaskPanel::triggerTaskSwitcher() const QDBusConnection::sessionBus().send(message); } +void TaskPanel::triggerOverview() const +{ + QDBusMessage message = QDBusMessage::createMethodCall("org.kde.kglobalaccel", "/component/kwin", "org.kde.kglobalaccel.Component", "invokeShortcut"); + message.setArguments({QStringLiteral("Overview")}); + QDBusConnection::sessionBus().send(message); +} + #include "taskpanel.moc" diff --git a/containments/taskpanel/taskpanel.h b/containments/taskpanel/taskpanel.h index 6bf4552a..da764c54 100644 --- a/containments/taskpanel/taskpanel.h +++ b/containments/taskpanel/taskpanel.h @@ -15,4 +15,5 @@ class TaskPanel : public Plasma::Containment public: TaskPanel(QObject *parent, const KPluginMetaData &data, const QVariantList &args); Q_INVOKABLE void triggerTaskSwitcher() const; + Q_INVOKABLE void triggerOverview() const; }; diff --git a/envmanager/config.h b/envmanager/config.h index c2c967dd..9db358cf 100644 --- a/envmanager/config.h +++ b/envmanager/config.h @@ -56,6 +56,7 @@ QMap> getKwinrcSettings(KSharedConfig::Ptr m_mo {"blurEnabled", false}, // disable blur for performance reasons, we could reconsider in the future for more powerful devices {"convergentwindowsEnabled", true}, // enable our convergent window plugin {"mobiletaskswitcherEnabled", true}, // ensure the mobile task switcher plugin is enabled + {"overviewEnabled", convergenceModeEnabled}, // enable KWin Overview effect in convergence mode for desktop-style task switching {"screenedgeEnabled", false} // disable the blue highlighting of screen edge effects. TODO would be nice if we could only deactivate it on // touchscreen gestures and not mouse as well }}, @@ -76,7 +77,7 @@ QMap> getKwinrcSettings(KSharedConfig::Ptr m_mo // Have a separate list here because we need to trigger DBus calls to load/unload each effect/script. // Make sure that the effect/script is added to the kwinrc "Plugins" section above! -const QList KWIN_EFFECTS = {"blur", "mobiletaskswitcher", "screenedge"}; +const QList KWIN_EFFECTS = {"blur", "mobiletaskswitcher", "overview", "screenedge"}; const QList KWIN_SCRIPTS = {"convergentwindows"}; // .config/plasma-mobile/ksmserver - immutable settings: