From 0775c561533d42cae692eda9be4cec6f92e90b45 Mon Sep 17 00:00:00 2001 From: Devin Lin Date: Tue, 14 Mar 2023 23:29:46 -0700 Subject: [PATCH] windowplugin: Extract out windowutil from mobileshell to separate plugin This allows us in the future to use mobileshell without having the WindowUtil singleton loaded (which does a bunch of wayland calls that aren't necessary for most applications). --- components/CMakeLists.txt | 1 + components/mobileshell/CMakeLists.txt | 1 - components/mobileshell/mobileshellplugin.cpp | 5 +--- .../mobileshell/qml/components/AppLaunch.qml | 21 ++++++++++++++++ components/mobileshell/qml/components/util.js | 10 ++++---- .../mobileshell/qml/homescreen/HomeScreen.qml | 25 ++++++++++--------- .../mobileshell/qml/statusbar/ClockText.qml | 6 ----- .../mediacontrols/MediaControlsWidget.qml | 2 +- components/mobileshell/resources.qrc | 1 + components/mobileshell/shellutil.cpp | 10 -------- components/mobileshell/shellutil.h | 2 +- components/windowplugin/CMakeLists.txt | 25 +++++++++++++++++++ components/windowplugin/qmldir | 7 ++++++ components/windowplugin/windowplugin.cpp | 17 +++++++++++++ components/windowplugin/windowplugin.h | 18 +++++++++++++ .../windowutil.cpp | 12 +++++++++ .../windowutil.h | 8 ++++++ .../package/contents/ui/HomeDelegate.qml | 2 +- .../ui/appdrawer/GridViewAppDrawer.qml | 2 +- .../ui/appdrawer/ListViewAppDrawer.qml | 2 +- .../contents/ui/FavoritesAppDelegate.qml | 2 +- .../package/contents/ui/GridAppList.qml | 2 +- .../contents/ui/NavigationPanelComponent.qml | 25 ++++++++++--------- 23 files changed, 149 insertions(+), 57 deletions(-) create mode 100644 components/mobileshell/qml/components/AppLaunch.qml create mode 100644 components/windowplugin/CMakeLists.txt create mode 100644 components/windowplugin/qmldir create mode 100644 components/windowplugin/windowplugin.cpp create mode 100644 components/windowplugin/windowplugin.h rename components/{mobileshell => windowplugin}/windowutil.cpp (97%) rename components/{mobileshell => windowplugin}/windowutil.h (93%) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 77824c32..de93503c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -5,3 +5,4 @@ add_subdirectory(mmplugin) add_subdirectory(mobileshell) add_subdirectory(mobileshellstate) +add_subdirectory(windowplugin) diff --git a/components/mobileshell/CMakeLists.txt b/components/mobileshell/CMakeLists.txt index 174895ce..ec203e26 100644 --- a/components/mobileshell/CMakeLists.txt +++ b/components/mobileshell/CMakeLists.txt @@ -8,7 +8,6 @@ set(mobileshellplugin_SRCS mobileshellplugin.cpp mobileshellsettings.cpp shellutil.cpp - windowutil.cpp components/direction.cpp quicksettings/quicksetting.cpp quicksettings/paginatemodel.cpp diff --git a/components/mobileshell/mobileshellplugin.cpp b/components/mobileshell/mobileshellplugin.cpp index 88b024d1..11c0bd98 100644 --- a/components/mobileshell/mobileshellplugin.cpp +++ b/components/mobileshell/mobileshellplugin.cpp @@ -22,7 +22,6 @@ #include "mobileshellsettings.h" #include "shellutil.h" -#include "windowutil.h" QUrl resolvePath(std::string str) { @@ -46,9 +45,6 @@ void MobileShellPlugin::registerTypes(const char *uri) qmlRegisterType(uri, 1, 0, "PaginateModel"); qmlRegisterType(uri, 1, 0, "SavedQuickSettings"); qmlRegisterType(uri, 1, 0, "SavedQuickSettingsModel"); - qmlRegisterSingletonType(uri, 1, 0, "WindowUtil", [](QQmlEngine *, QJSEngine *) -> QObject * { - return WindowUtil::instance(); - }); // components qmlRegisterType(uri, 1, 0, "Direction"); @@ -68,6 +64,7 @@ void MobileShellPlugin::registerTypes(const char *uri) qmlRegisterType(resolvePath("actiondrawer/ActionDrawerWindow.qml"), uri, 1, 0, "ActionDrawerWindow"); // /components + qmlRegisterSingletonType(resolvePath("components/AppLaunch.qml"), uri, 1, 0, "AppLaunch"); qmlRegisterType(resolvePath("components/BaseItem.qml"), uri, 1, 0, "BaseItem"); qmlRegisterType(resolvePath("components/ExtendedAbstractButton.qml"), uri, 1, 0, "ExtendedAbstractButton"); qmlRegisterType(resolvePath("components/Flickable.qml"), uri, 1, 0, "Flickable"); diff --git a/components/mobileshell/qml/components/AppLaunch.qml b/components/mobileshell/qml/components/AppLaunch.qml new file mode 100644 index 00000000..1cd5cc68 --- /dev/null +++ b/components/mobileshell/qml/components/AppLaunch.qml @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2023 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later + +import QtQuick +import org.kde.plasma.private.mobileshell as MobileShell +import org.kde.plasma.private.mobileshell.windowplugin as WindowPlugin + +pragma Singleton + +QtObject { + /** + * Activates an application by storage id if it is already running, or launch the application. + */ + function launchOrActivateApp(storageId) { + const launched = WindowPlugin.WindowUtil.activateWindowByStorageId(storageId); + + if (!launched) { + MobileShell.ShellUtil.launchApp(storageId); + } + } +} diff --git a/components/mobileshell/qml/components/util.js b/components/mobileshell/qml/components/util.js index cbf4523f..eca9b1b8 100644 --- a/components/mobileshell/qml/components/util.js +++ b/components/mobileshell/qml/components/util.js @@ -1,9 +1,9 @@ -/* - * SPDX-FileCopyrightText: 2021 Devin Lin - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ +// SPDX-FileCopyrightText: 2021 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later +/** + * Applies both the min and max functions to a value. + */ function applyMinMaxRange(min, max, num) { return Math.min(max, Math.max(min, num)); } diff --git a/components/mobileshell/qml/homescreen/HomeScreen.qml b/components/mobileshell/qml/homescreen/HomeScreen.qml index 9f4c973d..0dd939e2 100644 --- a/components/mobileshell/qml/homescreen/HomeScreen.qml +++ b/components/mobileshell/qml/homescreen/HomeScreen.qml @@ -3,15 +3,16 @@ * SPDX-License-Identifier: LGPL-2.0-or-later */ -import QtQuick 2.15 -import QtQuick.Window 2.15 +import QtQuick +import QtQuick.Window -import org.kde.plasma.core 2.0 as PlasmaCore -import org.kde.plasma.plasmoid 2.0 -import org.kde.taskmanager 0.1 as TaskManager +import org.kde.plasma.core as PlasmaCore +import org.kde.plasma.plasmoid +import org.kde.taskmanager as TaskManager -import org.kde.plasma.private.mobileshell 1.0 as MobileShell -import org.kde.plasma.private.mobileshell.state 1.0 as MobileShellState +import org.kde.plasma.private.mobileshell as MobileShell +import org.kde.plasma.private.mobileshell.state as MobileShellState +import org.kde.plasma.private.mobileshell.windowplugin as WindowPlugin /** * The base homescreen component, implementing features that simplify @@ -77,14 +78,14 @@ Item { target: MobileShellState.HomeScreenControls function onOpenHomeScreen() { - if (!MobileShell.WindowUtil.allWindowsMinimized) { + if (!WindowPlugin.WindowUtil.allWindowsMinimized) { itemContainer.zoomIn(); } MobileShellState.HomeScreenControls.resetHomeScreenPosition(); - MobileShell.WindowUtil.unsetAllMinimizedGeometries(root); - MobileShell.WindowUtil.minimizeAll(); + WindowPlugin.WindowUtil.unsetAllMinimizedGeometries(root); + WindowPlugin.WindowUtil.minimizeAll(); root.homeTriggered(); } @@ -202,7 +203,7 @@ Item { function evaluateAnimChange() { // only animate if homescreen is visible - if (!visibleMaximizedWindowsModel.isWindowMaximized || MobileShell.WindowUtil.activeWindowIsShell) { + if (!visibleMaximizedWindowsModel.isWindowMaximized || WindowPlugin.WindowUtil.activeWindowIsShell) { itemContainer.zoomIn(); } else { itemContainer.zoomOut(); @@ -210,7 +211,7 @@ Item { } Connections { - target: MobileShell.WindowUtil + target: WindowPlugin.WindowUtil function onActiveWindowIsShellChanged() { itemContainer.evaluateAnimChange(); } diff --git a/components/mobileshell/qml/statusbar/ClockText.qml b/components/mobileshell/qml/statusbar/ClockText.qml index 121fac63..b0d023e1 100644 --- a/components/mobileshell/qml/statusbar/ClockText.qml +++ b/components/mobileshell/qml/statusbar/ClockText.qml @@ -25,10 +25,4 @@ PlasmaComponents.Label { text: Qt.formatTime(source.data.Local.DateTime, is24HourTime ? "h:mm" : "h:mm ap") color: PlasmaCore.ColorScope.textColor verticalAlignment: Qt.AlignVCenter - - TapHandler { - onTapped: { - MobileShell.ShellUtil.launchApp("org.kde.kclock.desktop"); - } - } } diff --git a/components/mobileshell/qml/widgets/mediacontrols/MediaControlsWidget.qml b/components/mobileshell/qml/widgets/mediacontrols/MediaControlsWidget.qml index f030d57d..056cffc5 100644 --- a/components/mobileshell/qml/widgets/mediacontrols/MediaControlsWidget.qml +++ b/components/mobileshell/qml/widgets/mediacontrols/MediaControlsWidget.qml @@ -75,7 +75,7 @@ Item { implicitWidth: playerItem.implicitWidth onClicked: { - MobileShell.ShellUtil.launchApp(modelData.desktopEntry + ".desktop"); + Components.AppLaunch.launchOrActivateApp(modelData.desktopEntry + ".desktop"); MobileShellState.Shell.closeActionDrawer(); } diff --git a/components/mobileshell/resources.qrc b/components/mobileshell/resources.qrc index 97d868be..f67f6a6d 100644 --- a/components/mobileshell/resources.qrc +++ b/components/mobileshell/resources.qrc @@ -20,6 +20,7 @@ qml/actiondrawer/LandscapeContentContainer.qml qml/actiondrawer/PortraitContentContainer.qml + qml/components/AppLaunch.qml qml/components/BaseItem.qml qml/components/ExtendedAbstractButton.qml qml/components/Flickable.qml diff --git a/components/mobileshell/shellutil.cpp b/components/mobileshell/shellutil.cpp index e2090ccc..7487bf1a 100644 --- a/components/mobileshell/shellutil.cpp +++ b/components/mobileshell/shellutil.cpp @@ -8,7 +8,6 @@ #include "shellutil.h" #include "mobileshellsettings.h" -#include "windowutil.h" #include #include @@ -81,15 +80,6 @@ bool ShellUtil::isSystem24HourFormat() void ShellUtil::launchApp(const QString &storageId) { - // try to activate a running window first - auto windows = WindowUtil::instance()->windowsFromStorageId(storageId); - - if (!windows.empty()) { - windows[0]->requestActivate(); - return; - } - - // now try launching the window KService::Ptr service = KService::serviceByStorageId(storageId); if (!service) { qWarning() << "Could not find" << storageId; diff --git a/components/mobileshell/shellutil.h b/components/mobileshell/shellutil.h index bea5a8a0..608d7197 100644 --- a/components/mobileshell/shellutil.h +++ b/components/mobileshell/shellutil.h @@ -52,7 +52,7 @@ public: Q_INVOKABLE void executeCommand(const QString &command); /** - * Launch an application by name. Sets the internal "launched app" state. + * Launch an application by name. * * @param storageId The storage id of the application to launch. */ diff --git a/components/windowplugin/CMakeLists.txt b/components/windowplugin/CMakeLists.txt new file mode 100644 index 00000000..94926c0b --- /dev/null +++ b/components/windowplugin/CMakeLists.txt @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: 2023 Devin Lin +# SPDX-License-Identifier: GPL-2.0-or-later + +add_library(windowplugin) +target_sources(windowplugin PRIVATE + windowplugin.cpp + windowutil.cpp +) + +target_link_libraries(windowplugin + Qt::Qml + Qt::DBus + Qt::Gui + Qt::Quick + KF6::WaylandClient + KF6::Service + KF6::ConfigWidgets +) + +set_property(TARGET windowplugin PROPERTY LIBRARY_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/org/kde/plasma/private/mobileshell/windowplugin) +file(COPY qmldir DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/org/kde/plasma/private/mobileshell/windowplugin) + +install(TARGETS windowplugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/private/mobileshell/windowplugin) +install(FILES qmldir ${qml_SRC} DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/private/mobileshell/windowplugin) + diff --git a/components/windowplugin/qmldir b/components/windowplugin/qmldir new file mode 100644 index 00000000..9dd6b4ed --- /dev/null +++ b/components/windowplugin/qmldir @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: 2021-2022 Devin Lin +# SPDX-License-Identifier: GPL-2.0-or-later + +module org.kde.plasma.private.mobileshell.windowplugin + +plugin windowplugin + diff --git a/components/windowplugin/windowplugin.cpp b/components/windowplugin/windowplugin.cpp new file mode 100644 index 00000000..950de2e3 --- /dev/null +++ b/components/windowplugin/windowplugin.cpp @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "windowplugin.h" +#include "windowutil.h" + +#include +#include + +void WindowPlugin::registerTypes(const char *uri) +{ + Q_ASSERT(QLatin1String(uri) == QLatin1String("org.kde.plasma.private.mobileshell.windowplugin")); + + qmlRegisterSingletonType(uri, 1, 0, "WindowUtil", [](QQmlEngine *, QJSEngine *) -> QObject * { + return WindowUtil::instance(); + }); +} diff --git a/components/windowplugin/windowplugin.h b/components/windowplugin/windowplugin.h new file mode 100644 index 00000000..225d4647 --- /dev/null +++ b/components/windowplugin/windowplugin.h @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2023 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include +#include + +class WindowPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + +public: + void registerTypes(const char *uri) override; +}; diff --git a/components/mobileshell/windowutil.cpp b/components/windowplugin/windowutil.cpp similarity index 97% rename from components/mobileshell/windowutil.cpp rename to components/windowplugin/windowutil.cpp index f0a71872..a21c8fc4 100644 --- a/components/mobileshell/windowutil.cpp +++ b/components/windowplugin/windowutil.cpp @@ -137,6 +137,18 @@ bool WindowUtil::hasCloseableActiveWindow() const return m_activeWindow && m_activeWindow->isCloseable() /*&& !m_activeWindow->isMinimized()*/; } +bool WindowUtil::activateWindowByStorageId(const QString &storageId) +{ + auto windows = windowsFromStorageId(storageId); + + if (!windows.empty()) { + windows[0]->requestActivate(); + return true; + } + + return false; +} + void WindowUtil::closeActiveWindow() { if (m_activeWindow) { diff --git a/components/mobileshell/windowutil.h b/components/windowplugin/windowutil.h similarity index 93% rename from components/mobileshell/windowutil.h rename to components/windowplugin/windowutil.h index b4a7c175..ccb691d4 100644 --- a/components/mobileshell/windowutil.h +++ b/components/windowplugin/windowutil.h @@ -72,6 +72,14 @@ public: */ QList windowsFromStorageId(const QString &storageId) const; + /** + * Activates the first window by its associated storage id. + * + * @param storageId the window's storage id + * @returns whether a window was activated + */ + Q_INVOKABLE bool activateWindowByStorageId(const QString &storageId); + /** * Close the current active window. */ diff --git a/containments/homescreens/folio/package/contents/ui/HomeDelegate.qml b/containments/homescreens/folio/package/contents/ui/HomeDelegate.qml index 117d68b3..60766ea4 100644 --- a/containments/homescreens/folio/package/contents/ui/HomeDelegate.qml +++ b/containments/homescreens/folio/package/contents/ui/HomeDelegate.qml @@ -63,7 +63,7 @@ ContainmentLayoutManager.ItemContainer { } desktopModel.setMinimizedDelegate(index, delegate); - MobileShell.ShellUtil.launchApp(modelData.applicationStorageId); + MobileShell.AppLaunch.launchOrActivateApp(modelData.applicationStorageId); } readonly property bool applicationRunning: model.applicationRunning diff --git a/containments/homescreens/folio/package/contents/ui/appdrawer/GridViewAppDrawer.qml b/containments/homescreens/folio/package/contents/ui/appdrawer/GridViewAppDrawer.qml index 7f24aa09..451ea626 100644 --- a/containments/homescreens/folio/package/contents/ui/appdrawer/GridViewAppDrawer.qml +++ b/containments/homescreens/folio/package/contents/ui/appdrawer/GridViewAppDrawer.qml @@ -79,7 +79,7 @@ AbstractAppDrawer { } Folio.ApplicationListModel.setMinimizedDelegate(index, delegate); - MobileShell.ShellUtil.launchApp(storageId); + MobileShell.AppLaunch.launchOrActivateApp(storageId); root.launched(); } } diff --git a/containments/homescreens/folio/package/contents/ui/appdrawer/ListViewAppDrawer.qml b/containments/homescreens/folio/package/contents/ui/appdrawer/ListViewAppDrawer.qml index e2198571..f80a9f0c 100644 --- a/containments/homescreens/folio/package/contents/ui/appdrawer/ListViewAppDrawer.qml +++ b/containments/homescreens/folio/package/contents/ui/appdrawer/ListViewAppDrawer.qml @@ -65,7 +65,7 @@ AbstractAppDrawer { } Folio.ApplicationListModel.setMinimizedDelegate(index, delegate); - MobileShell.ShellUtil.launchApp(storageId); + MobileShell.AppLaunch.launchOrActivateApp(storageId); root.launched(); } } diff --git a/containments/homescreens/halcyon/package/contents/ui/FavoritesAppDelegate.qml b/containments/homescreens/halcyon/package/contents/ui/FavoritesAppDelegate.qml index dc0d41c9..a2ba0778 100644 --- a/containments/homescreens/halcyon/package/contents/ui/FavoritesAppDelegate.qml +++ b/containments/homescreens/halcyon/package/contents/ui/FavoritesAppDelegate.qml @@ -88,7 +88,7 @@ Item { } application.setMinimizedDelegate(delegate); - MobileShell.ShellUtil.launchApp(application.storageId); + MobileShell.AppLaunch.launchOrActivateApp(application.storageId); } Loader { diff --git a/containments/homescreens/halcyon/package/contents/ui/GridAppList.qml b/containments/homescreens/halcyon/package/contents/ui/GridAppList.qml index 723485d7..6717f559 100644 --- a/containments/homescreens/halcyon/package/contents/ui/GridAppList.qml +++ b/containments/homescreens/halcyon/package/contents/ui/GridAppList.qml @@ -100,7 +100,7 @@ MobileShell.GridView { } application.setMinimizedDelegate(delegate); - MobileShell.ShellUtil.launchApp(application.storageId); + MobileShell.AppLaunch.launchOrActivateApp(application.storageId); } } diff --git a/containments/taskpanel/package/contents/ui/NavigationPanelComponent.qml b/containments/taskpanel/package/contents/ui/NavigationPanelComponent.qml index 843bb0a4..52c72e17 100644 --- a/containments/taskpanel/package/contents/ui/NavigationPanelComponent.qml +++ b/containments/taskpanel/package/contents/ui/NavigationPanelComponent.qml @@ -1,17 +1,18 @@ // SPDX-FileCopyrightText: 2021-2023 Devin Lin // SPDX-License-Identifier: GPL-2.0-or-later -import QtQuick 2.4 -import QtQuick.Layouts 1.1 -import QtQuick.Window 2.15 +import QtQuick +import QtQuick.Layouts +import QtQuick.Window -import org.kde.plasma.plasmoid 2.0 -import org.kde.plasma.core 2.0 as PlasmaCore -import org.kde.plasma.workspace.keyboardlayout 1.0 as Keyboards +import org.kde.plasma.plasmoid +import org.kde.plasma.core as PlasmaCore +import org.kde.plasma.workspace.keyboardlayout as Keyboards -import org.kde.plasma.private.mobileshell 1.0 as MobileShell -import org.kde.plasma.private.mobileshell.state 1.0 as MobileShellState -import org.kde.taskmanager 0.1 as TaskManager +import org.kde.plasma.private.mobileshell as MobileShell +import org.kde.plasma.private.mobileshell.state as MobileShellState +import org.kde.taskmanager as TaskManager +import org.kde.plasma.private.mobileshell.windowplugin as WindowPlugin MobileShell.NavigationPanel { id: root @@ -77,7 +78,7 @@ MobileShell.NavigationPanel { onTriggered: { MobileShellState.HomeScreenControls.openHomeScreen(); - MobileShell.WindowUtil.allWindowsMinimizedChanged(); + WindowPlugin.WindowUtil.allWindowsMinimizedChanged(); } } @@ -85,7 +86,7 @@ MobileShell.NavigationPanel { rightAction: MobileShell.NavigationPanelAction { id: closeAppAction - enabled: Keyboards.KWinVirtualKeyboard.visible || MobileShell.WindowUtil.hasCloseableActiveWindow + enabled: Keyboards.KWinVirtualKeyboard.visible || WindowPlugin.WindowUtil.hasCloseableActiveWindow iconSource: Keyboards.KWinVirtualKeyboard.visible ? "go-down-symbolic" : "mobile-close-app" // mobile-close-app (from plasma-frameworks) seems to have less margins than icons from breeze-icons iconSizeFactor: Keyboards.KWinVirtualKeyboard.visible ? 1 : 0.75 @@ -94,7 +95,7 @@ MobileShell.NavigationPanel { if (Keyboards.KWinVirtualKeyboard.active) { // close keyboard if it is open Keyboards.KWinVirtualKeyboard.active = false; - } else if (MobileShell.WindowUtil.hasCloseableActiveWindow) { + } else if (WindowPlugin.WindowUtil.hasCloseableActiveWindow) { // if task switcher is closed, but there is an active window if (tasksModel.activeTask !== 0) { tasksModel.requestClose(tasksModel.activeTask);