Hide convergence chrome in Overview

Track KWin Overview through the activeEffects DBus property and expose the state to Folio QML. Hide the workspace frame, dock overlay, and in-containment favourites scrim while Overview is active so the effect does not show Shift shell chrome in its desktop view.

Set the state before invoking the Overview shortcut from Folio so the chrome is already gone when KWin starts composing the effect. The convergence dock invariant now guards both the hide rules and this ordering.
This commit is contained in:
Marco Allegretti 2026-05-23 15:33:23 +02:00
parent 02170250f1
commit a3e6182086
5 changed files with 142 additions and 4 deletions

View file

@ -9,14 +9,48 @@
#include <KWindowSystem> #include <KWindowSystem>
#include <QDBusConnection> #include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusMessage> #include <QDBusMessage>
#include <QDBusReply>
#include <QDBusVariant>
#include <QDebug> #include <QDebug>
#include <QQmlEngine> #include <QQmlEngine>
#include <QQmlExtensionPlugin> #include <QQmlExtensionPlugin>
#include <QQuickItem> #include <QQuickItem>
#include <QTimer>
K_PLUGIN_CLASS_WITH_JSON(HomeScreen, "metadata.json") K_PLUGIN_CLASS_WITH_JSON(HomeScreen, "metadata.json")
namespace
{
const QString s_kwinService = QStringLiteral("org.kde.KWin");
const QString s_kwinEffectsPath = QStringLiteral("/Effects");
const QString s_kwinEffectsInterface = QStringLiteral("org.kde.kwin.Effects");
const QString s_dbusPropertiesInterface = QStringLiteral("org.freedesktop.DBus.Properties");
QStringList effectListFromVariant(const QVariant &value)
{
QVariant effectValue = value;
if (effectValue.canConvert<QDBusVariant>()) {
effectValue = effectValue.value<QDBusVariant>().variant();
}
if (effectValue.canConvert<QStringList>()) {
return effectValue.toStringList();
}
QStringList effects;
const QVariantList effectList = effectValue.toList();
effects.reserve(effectList.size());
for (const QVariant &effect : effectList) {
effects.append(effect.toString());
}
return effects;
}
}
HomeScreen::HomeScreen(QObject *parent, const KPluginMetaData &data, const QVariantList &args) HomeScreen::HomeScreen(QObject *parent, const KPluginMetaData &data, const QVariantList &args)
: Plasma::Containment{parent, data, args} : Plasma::Containment{parent, data, args}
, m_folioSettings{new FolioSettings{this}} , m_folioSettings{new FolioSettings{this}}
@ -34,6 +68,20 @@ HomeScreen::HomeScreen(QObject *parent, const KPluginMetaData &data, const QVari
connect(KWindowSystem::self(), &KWindowSystem::showingDesktopChanged, this, &HomeScreen::showingDesktopChanged); connect(KWindowSystem::self(), &KWindowSystem::showingDesktopChanged, this, &HomeScreen::showingDesktopChanged);
updateOverviewActive();
QDBusConnection::sessionBus().connect(s_kwinService,
s_kwinEffectsPath,
s_dbusPropertiesInterface,
QStringLiteral("PropertiesChanged"),
this,
SLOT(onOverviewEffectsChanged(QString, QVariantMap, QStringList)));
auto overviewRefreshTimer = new QTimer(this);
overviewRefreshTimer->setInterval(250);
overviewRefreshTimer->setTimerType(Qt::CoarseTimer);
connect(overviewRefreshTimer, &QTimer::timeout, this, &HomeScreen::updateOverviewActive);
overviewRefreshTimer->start();
connect(this, &Plasma::Containment::appletAdded, this, &HomeScreen::onAppletAdded); connect(this, &Plasma::Containment::appletAdded, this, &HomeScreen::onAppletAdded);
connect(this, &Plasma::Containment::appletAboutToBeRemoved, this, &HomeScreen::onAppletAboutToBeRemoved); connect(this, &Plasma::Containment::appletAboutToBeRemoved, this, &HomeScreen::onAppletAboutToBeRemoved);
} }
@ -91,8 +139,58 @@ PageListModel *HomeScreen::pageListModel()
return m_pageListModel; return m_pageListModel;
} }
void HomeScreen::triggerOverview() const bool HomeScreen::overviewActive() const
{ {
return m_overviewActive;
}
void HomeScreen::setOverviewActive(bool overviewActive)
{
if (m_overviewActive == overviewActive) {
return;
}
m_overviewActive = overviewActive;
Q_EMIT overviewActiveChanged();
}
void HomeScreen::updateOverviewActive()
{
QDBusInterface propIface(s_kwinService, s_kwinEffectsPath, s_dbusPropertiesInterface, QDBusConnection::sessionBus());
if (!propIface.isValid()) {
setOverviewActive(false);
return;
}
QDBusReply<QDBusVariant> activeEffectsReply = propIface.call(QStringLiteral("Get"), s_kwinEffectsInterface, QStringLiteral("activeEffects"));
if (!activeEffectsReply.isValid()) {
setOverviewActive(false);
return;
}
setOverviewActive(effectListFromVariant(activeEffectsReply.value().variant()).contains(QStringLiteral("overview")));
}
void HomeScreen::onOverviewEffectsChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated)
{
if (interface != s_kwinEffectsInterface) {
return;
}
if (changed.contains(QStringLiteral("activeEffects"))) {
setOverviewActive(effectListFromVariant(changed.value(QStringLiteral("activeEffects"))).contains(QStringLiteral("overview")));
return;
}
if (invalidated.contains(QStringLiteral("activeEffects"))) {
updateOverviewActive();
}
}
void HomeScreen::triggerOverview()
{
setOverviewActive(true);
QDBusMessage message = QDBusMessage::createMethodCall("org.kde.kglobalaccel", "/component/kwin", "org.kde.kglobalaccel.Component", "invokeShortcut"); QDBusMessage message = QDBusMessage::createMethodCall("org.kde.kglobalaccel", "/component/kwin", "org.kde.kglobalaccel.Component", "invokeShortcut");
message.setArguments({QStringLiteral("Overview")}); message.setArguments({QStringLiteral("Overview")});
QDBusConnection::sessionBus().send(message); QDBusConnection::sessionBus().send(message);

View file

@ -43,6 +43,7 @@ class HomeScreen : public Plasma::Containment
Q_PROPERTY(ApplicationListSearchModel *ApplicationListSearchModel READ applicationListSearchModel CONSTANT) Q_PROPERTY(ApplicationListSearchModel *ApplicationListSearchModel READ applicationListSearchModel CONSTANT)
Q_PROPERTY(FavouritesModel *FavouritesModel READ favouritesModel CONSTANT) Q_PROPERTY(FavouritesModel *FavouritesModel READ favouritesModel CONSTANT)
Q_PROPERTY(PageListModel *PageListModel READ pageListModel CONSTANT) Q_PROPERTY(PageListModel *PageListModel READ pageListModel CONSTANT)
Q_PROPERTY(bool overviewActive READ overviewActive NOTIFY overviewActiveChanged)
public: public:
HomeScreen(QObject *parent, const KPluginMetaData &data, const QVariantList &args); HomeScreen(QObject *parent, const KPluginMetaData &data, const QVariantList &args);
@ -50,7 +51,7 @@ public:
void configChanged() override; void configChanged() override;
Q_INVOKABLE void triggerOverview() const; Q_INVOKABLE void triggerOverview();
Q_INVOKABLE void triggerMinimizeAll() const; Q_INVOKABLE void triggerMinimizeAll() const;
Q_INVOKABLE void activateVirtualDesktop(const QVariant &desktop) const; Q_INVOKABLE void activateVirtualDesktop(const QVariant &desktop) const;
Q_INVOKABLE void createVirtualDesktop() const; Q_INVOKABLE void createVirtualDesktop() const;
@ -64,15 +65,21 @@ public:
ApplicationListSearchModel *applicationListSearchModel(); ApplicationListSearchModel *applicationListSearchModel();
FavouritesModel *favouritesModel(); FavouritesModel *favouritesModel();
PageListModel *pageListModel(); PageListModel *pageListModel();
bool overviewActive() const;
Q_SIGNALS: Q_SIGNALS:
void overviewActiveChanged();
void showingDesktopChanged(bool showingDesktop); void showingDesktopChanged(bool showingDesktop);
private Q_SLOTS: private Q_SLOTS:
void onOverviewEffectsChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated);
void onAppletAdded(Plasma::Applet *applet, const QRectF &geometryHint); void onAppletAdded(Plasma::Applet *applet, const QRectF &geometryHint);
void onAppletAboutToBeRemoved(Plasma::Applet *applet); void onAppletAboutToBeRemoved(Plasma::Applet *applet);
private: private:
void setOverviewActive(bool overviewActive);
void updateOverviewActive();
FolioSettings *m_folioSettings{nullptr}; FolioSettings *m_folioSettings{nullptr};
HomeScreenState *m_homeScreenState{nullptr}; HomeScreenState *m_homeScreenState{nullptr};
WidgetsManager *m_widgetsManager{nullptr}; WidgetsManager *m_widgetsManager{nullptr};
@ -80,4 +87,5 @@ private:
ApplicationListSearchModel *m_applicationListSearchModel{nullptr}; ApplicationListSearchModel *m_applicationListSearchModel{nullptr};
FavouritesModel *m_favouritesModel{nullptr}; FavouritesModel *m_favouritesModel{nullptr};
PageListModel *m_pageListModel{nullptr}; PageListModel *m_pageListModel{nullptr};
bool m_overviewActive{false};
}; };

View file

@ -358,6 +358,7 @@ Item {
// don't show in settings mode // don't show in settings mode
opacity: 1 - folio.HomeScreenState.settingsOpenProgress opacity: 1 - folio.HomeScreenState.settingsOpenProgress
visible: folio.FolioSettings.showFavouritesBarBackground visible: folio.FolioSettings.showFavouritesBarBackground
&& !ShellSettings.Settings.convergenceModeEnabled
anchors.top: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom ? favouritesBar.top : parent.top anchors.top: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom ? favouritesBar.top : parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom

View file

@ -278,7 +278,9 @@ ContainmentItem {
// task panel containment; this window only provides the visible dock. // task panel containment; this window only provides the visible dock.
Window { Window {
id: dockOverlay id: dockOverlay
readonly property bool active: ShellSettings.Settings.convergenceModeEnabled && !ShellSettings.Settings.gamingModeEnabled readonly property bool active: ShellSettings.Settings.convergenceModeEnabled
&& !ShellSettings.Settings.gamingModeEnabled
&& !folio.overviewActive
visible: active visible: active
opacity: active ? 1 : 0 opacity: active ? 1 : 0
@ -882,7 +884,9 @@ ContainmentItem {
Item { Item {
id: workspaceFrame id: workspaceFrame
anchors.fill: parent anchors.fill: parent
visible: ShellSettings.Settings.convergenceModeEnabled && !ShellSettings.Settings.gamingModeEnabled visible: ShellSettings.Settings.convergenceModeEnabled
&& !ShellSettings.Settings.gamingModeEnabled
&& !folio.overviewActive
z: -1 z: -1
readonly property real frameThickness: MobileShell.Constants.convergenceWorkspaceFrameThickness readonly property real frameThickness: MobileShell.Constants.convergenceWorkspaceFrameThickness

View file

@ -11,6 +11,8 @@ panel="$repo_root/containments/panel/qml/main.qml"
taskpanel="$repo_root/containments/taskpanel/qml/main.qml" taskpanel="$repo_root/containments/taskpanel/qml/main.qml"
folio_main="$repo_root/containments/homescreens/folio/qml/main.qml" folio_main="$repo_root/containments/homescreens/folio/qml/main.qml"
folio_home="$repo_root/containments/homescreens/folio/qml/FolioHomeScreen.qml" folio_home="$repo_root/containments/homescreens/folio/qml/FolioHomeScreen.qml"
folio_backend="$repo_root/containments/homescreens/folio/homescreen.h"
folio_backend_cpp="$repo_root/containments/homescreens/folio/homescreen.cpp"
action_content="$repo_root/components/mobileshell/qml/actiondrawer/private/ContentContainer.qml" action_content="$repo_root/components/mobileshell/qml/actiondrawer/private/ContentContainer.qml"
action_landscape="$repo_root/components/mobileshell/qml/actiondrawer/private/LandscapeContentContainer.qml" action_landscape="$repo_root/components/mobileshell/qml/actiondrawer/private/LandscapeContentContainer.qml"
quick_settings="$repo_root/components/mobileshell/qml/actiondrawer/private/QuickSettings.qml" quick_settings="$repo_root/components/mobileshell/qml/actiondrawer/private/QuickSettings.qml"
@ -64,6 +66,31 @@ require_line "$folio_main" "- MobileShell.Constants.convergenceWorkspaceFrameThi
require_line "$folio_main" "readonly property real popupHeight: Math.max(0, popupBottomY - popupTopY)" require_line "$folio_main" "readonly property real popupHeight: Math.max(0, popupBottomY - popupTopY)"
require_line "$folio_main" "? popupTopY + animationY" require_line "$folio_main" "? popupTopY + animationY"
require_line "$folio_home" "height: ShellSettings.Settings.convergenceModeEnabled ? MobileShell.Constants.convergenceDockHeight : Kirigami.Units.gridUnit * 6" require_line "$folio_home" "height: ShellSettings.Settings.convergenceModeEnabled ? MobileShell.Constants.convergenceDockHeight : Kirigami.Units.gridUnit * 6"
require_line "$folio_home" "&& !ShellSettings.Settings.convergenceModeEnabled"
require_line "$folio_backend" "Q_PROPERTY(bool overviewActive READ overviewActive NOTIFY overviewActiveChanged)"
overview_hide_guards="$(grep -F "&& !folio.overviewActive" "$folio_main" | wc -l)"
if [[ "$overview_hide_guards" -ne 2 ]]; then
echo "Expected the Folio convergence workspace frame and dock overlay to hide during KWin Overview; found $overview_hide_guards overview guards" >&2
exit 1
fi
if ! awk '
/void HomeScreen::triggerOverview\(\)/ { in_trigger = 1; next }
in_trigger && /setOverviewActive\(true\);/ { saw_pre_hide = 1; next }
in_trigger && /createMethodCall/ {
if (saw_pre_hide) {
found = 1
exit 0
}
exit 1
}
in_trigger && /^}/ { exit 1 }
END { if (!found) exit 1 }
' "$folio_backend_cpp"; then
echo "Expected Folio to hide convergence chrome before invoking KWin Overview" >&2
exit 1
fi
require_line "$action_content" "readonly property real convergenceSurfaceTopInset: MobileShell.Constants.topPanelHeight" require_line "$action_content" "readonly property real convergenceSurfaceTopInset: MobileShell.Constants.topPanelHeight"
require_line "$action_content" "readonly property real convergenceSurfaceBottomInset: MobileShell.Constants.convergenceDockHeight + convergenceFrameThickness" require_line "$action_content" "readonly property real convergenceSurfaceBottomInset: MobileShell.Constants.convergenceDockHeight + convergenceFrameThickness"