diff --git a/containments/homescreens/folio/homescreen.cpp b/containments/homescreens/folio/homescreen.cpp index 56b33360..3069c326 100644 --- a/containments/homescreens/folio/homescreen.cpp +++ b/containments/homescreens/folio/homescreen.cpp @@ -9,14 +9,48 @@ #include #include +#include #include +#include +#include #include #include #include #include +#include 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()) { + effectValue = effectValue.value().variant(); + } + + if (effectValue.canConvert()) { + 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) : Plasma::Containment{parent, data, args} , 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); + 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::appletAboutToBeRemoved, this, &HomeScreen::onAppletAboutToBeRemoved); } @@ -91,8 +139,58 @@ PageListModel *HomeScreen::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 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"); message.setArguments({QStringLiteral("Overview")}); QDBusConnection::sessionBus().send(message); diff --git a/containments/homescreens/folio/homescreen.h b/containments/homescreens/folio/homescreen.h index 0161b62e..f8d1acd9 100644 --- a/containments/homescreens/folio/homescreen.h +++ b/containments/homescreens/folio/homescreen.h @@ -43,6 +43,7 @@ class HomeScreen : public Plasma::Containment Q_PROPERTY(ApplicationListSearchModel *ApplicationListSearchModel READ applicationListSearchModel CONSTANT) Q_PROPERTY(FavouritesModel *FavouritesModel READ favouritesModel CONSTANT) Q_PROPERTY(PageListModel *PageListModel READ pageListModel CONSTANT) + Q_PROPERTY(bool overviewActive READ overviewActive NOTIFY overviewActiveChanged) public: HomeScreen(QObject *parent, const KPluginMetaData &data, const QVariantList &args); @@ -50,7 +51,7 @@ public: void configChanged() override; - Q_INVOKABLE void triggerOverview() const; + Q_INVOKABLE void triggerOverview(); Q_INVOKABLE void triggerMinimizeAll() const; Q_INVOKABLE void activateVirtualDesktop(const QVariant &desktop) const; Q_INVOKABLE void createVirtualDesktop() const; @@ -64,15 +65,21 @@ public: ApplicationListSearchModel *applicationListSearchModel(); FavouritesModel *favouritesModel(); PageListModel *pageListModel(); + bool overviewActive() const; Q_SIGNALS: + void overviewActiveChanged(); void showingDesktopChanged(bool showingDesktop); private Q_SLOTS: + void onOverviewEffectsChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated); void onAppletAdded(Plasma::Applet *applet, const QRectF &geometryHint); void onAppletAboutToBeRemoved(Plasma::Applet *applet); private: + void setOverviewActive(bool overviewActive); + void updateOverviewActive(); + FolioSettings *m_folioSettings{nullptr}; HomeScreenState *m_homeScreenState{nullptr}; WidgetsManager *m_widgetsManager{nullptr}; @@ -80,4 +87,5 @@ private: ApplicationListSearchModel *m_applicationListSearchModel{nullptr}; FavouritesModel *m_favouritesModel{nullptr}; PageListModel *m_pageListModel{nullptr}; + bool m_overviewActive{false}; }; diff --git a/containments/homescreens/folio/qml/FolioHomeScreen.qml b/containments/homescreens/folio/qml/FolioHomeScreen.qml index 299fa833..7fb662fd 100644 --- a/containments/homescreens/folio/qml/FolioHomeScreen.qml +++ b/containments/homescreens/folio/qml/FolioHomeScreen.qml @@ -358,6 +358,7 @@ Item { // don't show in settings mode opacity: 1 - folio.HomeScreenState.settingsOpenProgress visible: folio.FolioSettings.showFavouritesBarBackground + && !ShellSettings.Settings.convergenceModeEnabled anchors.top: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom ? favouritesBar.top : parent.top anchors.bottom: parent.bottom diff --git a/containments/homescreens/folio/qml/main.qml b/containments/homescreens/folio/qml/main.qml index a34ccc3b..5840497d 100644 --- a/containments/homescreens/folio/qml/main.qml +++ b/containments/homescreens/folio/qml/main.qml @@ -278,7 +278,9 @@ ContainmentItem { // task panel containment; this window only provides the visible dock. Window { 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 opacity: active ? 1 : 0 @@ -882,7 +884,9 @@ ContainmentItem { Item { id: workspaceFrame anchors.fill: parent - visible: ShellSettings.Settings.convergenceModeEnabled && !ShellSettings.Settings.gamingModeEnabled + visible: ShellSettings.Settings.convergenceModeEnabled + && !ShellSettings.Settings.gamingModeEnabled + && !folio.overviewActive z: -1 readonly property real frameThickness: MobileShell.Constants.convergenceWorkspaceFrameThickness diff --git a/tests/check-convergence-dock-invariant.sh b/tests/check-convergence-dock-invariant.sh index be1dc876..94a5c653 100644 --- a/tests/check-convergence-dock-invariant.sh +++ b/tests/check-convergence-dock-invariant.sh @@ -11,6 +11,8 @@ panel="$repo_root/containments/panel/qml/main.qml" taskpanel="$repo_root/containments/taskpanel/qml/main.qml" folio_main="$repo_root/containments/homescreens/folio/qml/main.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_landscape="$repo_root/components/mobileshell/qml/actiondrawer/private/LandscapeContentContainer.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" "? popupTopY + animationY" 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 convergenceSurfaceBottomInset: MobileShell.Constants.convergenceDockHeight + convergenceFrameThickness"