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).
This commit is contained in:
Devin Lin 2023-03-14 23:29:46 -07:00
parent 0a640e9331
commit 0775c56153
23 changed files with 149 additions and 57 deletions

View file

@ -5,3 +5,4 @@
add_subdirectory(mmplugin) add_subdirectory(mmplugin)
add_subdirectory(mobileshell) add_subdirectory(mobileshell)
add_subdirectory(mobileshellstate) add_subdirectory(mobileshellstate)
add_subdirectory(windowplugin)

View file

@ -8,7 +8,6 @@ set(mobileshellplugin_SRCS
mobileshellplugin.cpp mobileshellplugin.cpp
mobileshellsettings.cpp mobileshellsettings.cpp
shellutil.cpp shellutil.cpp
windowutil.cpp
components/direction.cpp components/direction.cpp
quicksettings/quicksetting.cpp quicksettings/quicksetting.cpp
quicksettings/paginatemodel.cpp quicksettings/paginatemodel.cpp

View file

@ -22,7 +22,6 @@
#include "mobileshellsettings.h" #include "mobileshellsettings.h"
#include "shellutil.h" #include "shellutil.h"
#include "windowutil.h"
QUrl resolvePath(std::string str) QUrl resolvePath(std::string str)
{ {
@ -46,9 +45,6 @@ void MobileShellPlugin::registerTypes(const char *uri)
qmlRegisterType<PaginateModel>(uri, 1, 0, "PaginateModel"); qmlRegisterType<PaginateModel>(uri, 1, 0, "PaginateModel");
qmlRegisterType<SavedQuickSettings>(uri, 1, 0, "SavedQuickSettings"); qmlRegisterType<SavedQuickSettings>(uri, 1, 0, "SavedQuickSettings");
qmlRegisterType<SavedQuickSettingsModel>(uri, 1, 0, "SavedQuickSettingsModel"); qmlRegisterType<SavedQuickSettingsModel>(uri, 1, 0, "SavedQuickSettingsModel");
qmlRegisterSingletonType<WindowUtil>(uri, 1, 0, "WindowUtil", [](QQmlEngine *, QJSEngine *) -> QObject * {
return WindowUtil::instance();
});
// components // components
qmlRegisterType<Direction>(uri, 1, 0, "Direction"); qmlRegisterType<Direction>(uri, 1, 0, "Direction");
@ -68,6 +64,7 @@ void MobileShellPlugin::registerTypes(const char *uri)
qmlRegisterType(resolvePath("actiondrawer/ActionDrawerWindow.qml"), uri, 1, 0, "ActionDrawerWindow"); qmlRegisterType(resolvePath("actiondrawer/ActionDrawerWindow.qml"), uri, 1, 0, "ActionDrawerWindow");
// /components // /components
qmlRegisterSingletonType(resolvePath("components/AppLaunch.qml"), uri, 1, 0, "AppLaunch");
qmlRegisterType(resolvePath("components/BaseItem.qml"), uri, 1, 0, "BaseItem"); qmlRegisterType(resolvePath("components/BaseItem.qml"), uri, 1, 0, "BaseItem");
qmlRegisterType(resolvePath("components/ExtendedAbstractButton.qml"), uri, 1, 0, "ExtendedAbstractButton"); qmlRegisterType(resolvePath("components/ExtendedAbstractButton.qml"), uri, 1, 0, "ExtendedAbstractButton");
qmlRegisterType(resolvePath("components/Flickable.qml"), uri, 1, 0, "Flickable"); qmlRegisterType(resolvePath("components/Flickable.qml"), uri, 1, 0, "Flickable");

View file

@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
// 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);
}
}
}

View file

@ -1,9 +1,9 @@
/* // SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org> // SPDX-License-Identifier: GPL-2.0-or-later
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
/**
* Applies both the min and max functions to a value.
*/
function applyMinMaxRange(min, max, num) { function applyMinMaxRange(min, max, num) {
return Math.min(max, Math.max(min, num)); return Math.min(max, Math.max(min, num));
} }

View file

@ -3,15 +3,16 @@
* SPDX-License-Identifier: LGPL-2.0-or-later * SPDX-License-Identifier: LGPL-2.0-or-later
*/ */
import QtQuick 2.15 import QtQuick
import QtQuick.Window 2.15 import QtQuick.Window
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.plasmoid
import org.kde.taskmanager 0.1 as TaskManager import org.kde.taskmanager as TaskManager
import org.kde.plasma.private.mobileshell 1.0 as MobileShell import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.state 1.0 as MobileShellState 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 * The base homescreen component, implementing features that simplify
@ -77,14 +78,14 @@ Item {
target: MobileShellState.HomeScreenControls target: MobileShellState.HomeScreenControls
function onOpenHomeScreen() { function onOpenHomeScreen() {
if (!MobileShell.WindowUtil.allWindowsMinimized) { if (!WindowPlugin.WindowUtil.allWindowsMinimized) {
itemContainer.zoomIn(); itemContainer.zoomIn();
} }
MobileShellState.HomeScreenControls.resetHomeScreenPosition(); MobileShellState.HomeScreenControls.resetHomeScreenPosition();
MobileShell.WindowUtil.unsetAllMinimizedGeometries(root); WindowPlugin.WindowUtil.unsetAllMinimizedGeometries(root);
MobileShell.WindowUtil.minimizeAll(); WindowPlugin.WindowUtil.minimizeAll();
root.homeTriggered(); root.homeTriggered();
} }
@ -202,7 +203,7 @@ Item {
function evaluateAnimChange() { function evaluateAnimChange() {
// only animate if homescreen is visible // only animate if homescreen is visible
if (!visibleMaximizedWindowsModel.isWindowMaximized || MobileShell.WindowUtil.activeWindowIsShell) { if (!visibleMaximizedWindowsModel.isWindowMaximized || WindowPlugin.WindowUtil.activeWindowIsShell) {
itemContainer.zoomIn(); itemContainer.zoomIn();
} else { } else {
itemContainer.zoomOut(); itemContainer.zoomOut();
@ -210,7 +211,7 @@ Item {
} }
Connections { Connections {
target: MobileShell.WindowUtil target: WindowPlugin.WindowUtil
function onActiveWindowIsShellChanged() { function onActiveWindowIsShellChanged() {
itemContainer.evaluateAnimChange(); itemContainer.evaluateAnimChange();
} }

View file

@ -25,10 +25,4 @@ PlasmaComponents.Label {
text: Qt.formatTime(source.data.Local.DateTime, is24HourTime ? "h:mm" : "h:mm ap") text: Qt.formatTime(source.data.Local.DateTime, is24HourTime ? "h:mm" : "h:mm ap")
color: PlasmaCore.ColorScope.textColor color: PlasmaCore.ColorScope.textColor
verticalAlignment: Qt.AlignVCenter verticalAlignment: Qt.AlignVCenter
TapHandler {
onTapped: {
MobileShell.ShellUtil.launchApp("org.kde.kclock.desktop");
}
}
} }

View file

@ -75,7 +75,7 @@ Item {
implicitWidth: playerItem.implicitWidth implicitWidth: playerItem.implicitWidth
onClicked: { onClicked: {
MobileShell.ShellUtil.launchApp(modelData.desktopEntry + ".desktop"); Components.AppLaunch.launchOrActivateApp(modelData.desktopEntry + ".desktop");
MobileShellState.Shell.closeActionDrawer(); MobileShellState.Shell.closeActionDrawer();
} }

View file

@ -20,6 +20,7 @@
<file>qml/actiondrawer/LandscapeContentContainer.qml</file> <file>qml/actiondrawer/LandscapeContentContainer.qml</file>
<file>qml/actiondrawer/PortraitContentContainer.qml</file> <file>qml/actiondrawer/PortraitContentContainer.qml</file>
<file>qml/components/AppLaunch.qml</file>
<file>qml/components/BaseItem.qml</file> <file>qml/components/BaseItem.qml</file>
<file>qml/components/ExtendedAbstractButton.qml</file> <file>qml/components/ExtendedAbstractButton.qml</file>
<file>qml/components/Flickable.qml</file> <file>qml/components/Flickable.qml</file>

View file

@ -8,7 +8,6 @@
#include "shellutil.h" #include "shellutil.h"
#include "mobileshellsettings.h" #include "mobileshellsettings.h"
#include "windowutil.h"
#include <KConfigGroup> #include <KConfigGroup>
#include <KFileUtils> #include <KFileUtils>
@ -81,15 +80,6 @@ bool ShellUtil::isSystem24HourFormat()
void ShellUtil::launchApp(const QString &storageId) 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); KService::Ptr service = KService::serviceByStorageId(storageId);
if (!service) { if (!service) {
qWarning() << "Could not find" << storageId; qWarning() << "Could not find" << storageId;

View file

@ -52,7 +52,7 @@ public:
Q_INVOKABLE void executeCommand(const QString &command); 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. * @param storageId The storage id of the application to launch.
*/ */

View file

@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
# 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)

View file

@ -0,0 +1,7 @@
# SPDX-FileCopyrightText: 2021-2022 Devin Lin <devin@kde.org>
# SPDX-License-Identifier: GPL-2.0-or-later
module org.kde.plasma.private.mobileshell.windowplugin
plugin windowplugin

View file

@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "windowplugin.h"
#include "windowutil.h"
#include <QQmlContext>
#include <QQuickItem>
void WindowPlugin::registerTypes(const char *uri)
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("org.kde.plasma.private.mobileshell.windowplugin"));
qmlRegisterSingletonType<WindowUtil>(uri, 1, 0, "WindowUtil", [](QQmlEngine *, QJSEngine *) -> QObject * {
return WindowUtil::instance();
});
}

View file

@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QUrl>
#include <QQmlEngine>
#include <QQmlExtensionPlugin>
class WindowPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
public:
void registerTypes(const char *uri) override;
};

View file

@ -137,6 +137,18 @@ bool WindowUtil::hasCloseableActiveWindow() const
return m_activeWindow && m_activeWindow->isCloseable() /*&& !m_activeWindow->isMinimized()*/; 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() void WindowUtil::closeActiveWindow()
{ {
if (m_activeWindow) { if (m_activeWindow) {

View file

@ -72,6 +72,14 @@ public:
*/ */
QList<KWayland::Client::PlasmaWindow *> windowsFromStorageId(const QString &storageId) const; QList<KWayland::Client::PlasmaWindow *> 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. * Close the current active window.
*/ */

View file

@ -63,7 +63,7 @@ ContainmentLayoutManager.ItemContainer {
} }
desktopModel.setMinimizedDelegate(index, delegate); desktopModel.setMinimizedDelegate(index, delegate);
MobileShell.ShellUtil.launchApp(modelData.applicationStorageId); MobileShell.AppLaunch.launchOrActivateApp(modelData.applicationStorageId);
} }
readonly property bool applicationRunning: model.applicationRunning readonly property bool applicationRunning: model.applicationRunning

View file

@ -79,7 +79,7 @@ AbstractAppDrawer {
} }
Folio.ApplicationListModel.setMinimizedDelegate(index, delegate); Folio.ApplicationListModel.setMinimizedDelegate(index, delegate);
MobileShell.ShellUtil.launchApp(storageId); MobileShell.AppLaunch.launchOrActivateApp(storageId);
root.launched(); root.launched();
} }
} }

View file

@ -65,7 +65,7 @@ AbstractAppDrawer {
} }
Folio.ApplicationListModel.setMinimizedDelegate(index, delegate); Folio.ApplicationListModel.setMinimizedDelegate(index, delegate);
MobileShell.ShellUtil.launchApp(storageId); MobileShell.AppLaunch.launchOrActivateApp(storageId);
root.launched(); root.launched();
} }
} }

View file

@ -88,7 +88,7 @@ Item {
} }
application.setMinimizedDelegate(delegate); application.setMinimizedDelegate(delegate);
MobileShell.ShellUtil.launchApp(application.storageId); MobileShell.AppLaunch.launchOrActivateApp(application.storageId);
} }
Loader { Loader {

View file

@ -100,7 +100,7 @@ MobileShell.GridView {
} }
application.setMinimizedDelegate(delegate); application.setMinimizedDelegate(delegate);
MobileShell.ShellUtil.launchApp(application.storageId); MobileShell.AppLaunch.launchOrActivateApp(application.storageId);
} }
} }

View file

@ -1,17 +1,18 @@
// SPDX-FileCopyrightText: 2021-2023 Devin Lin <devin@kde.org> // SPDX-FileCopyrightText: 2021-2023 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick 2.4 import QtQuick
import QtQuick.Layouts 1.1 import QtQuick.Layouts
import QtQuick.Window 2.15 import QtQuick.Window
import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.plasmoid
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.workspace.keyboardlayout 1.0 as Keyboards import org.kde.plasma.workspace.keyboardlayout as Keyboards
import org.kde.plasma.private.mobileshell 1.0 as MobileShell import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.state 1.0 as MobileShellState import org.kde.plasma.private.mobileshell.state as MobileShellState
import org.kde.taskmanager 0.1 as TaskManager import org.kde.taskmanager as TaskManager
import org.kde.plasma.private.mobileshell.windowplugin as WindowPlugin
MobileShell.NavigationPanel { MobileShell.NavigationPanel {
id: root id: root
@ -77,7 +78,7 @@ MobileShell.NavigationPanel {
onTriggered: { onTriggered: {
MobileShellState.HomeScreenControls.openHomeScreen(); MobileShellState.HomeScreenControls.openHomeScreen();
MobileShell.WindowUtil.allWindowsMinimizedChanged(); WindowPlugin.WindowUtil.allWindowsMinimizedChanged();
} }
} }
@ -85,7 +86,7 @@ MobileShell.NavigationPanel {
rightAction: MobileShell.NavigationPanelAction { rightAction: MobileShell.NavigationPanelAction {
id: closeAppAction 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" 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 // mobile-close-app (from plasma-frameworks) seems to have less margins than icons from breeze-icons
iconSizeFactor: Keyboards.KWinVirtualKeyboard.visible ? 1 : 0.75 iconSizeFactor: Keyboards.KWinVirtualKeyboard.visible ? 1 : 0.75
@ -94,7 +95,7 @@ MobileShell.NavigationPanel {
if (Keyboards.KWinVirtualKeyboard.active) { if (Keyboards.KWinVirtualKeyboard.active) {
// close keyboard if it is open // close keyboard if it is open
Keyboards.KWinVirtualKeyboard.active = false; 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 task switcher is closed, but there is an active window
if (tasksModel.activeTask !== 0) { if (tasksModel.activeTask !== 0) {
tasksModel.requestClose(tasksModel.activeTask); tasksModel.requestClose(tasksModel.activeTask);