From 23eb4251814abbf2392933576f2409101c8ef081 Mon Sep 17 00:00:00 2001 From: Mikhail Zolotukhin Date: Mon, 21 Mar 2022 15:36:10 +0300 Subject: [PATCH] refactor: wrap clientArea workspace method --- src/core/plasma-api/utils.hpp | 19 +++++++++++++++++++ src/core/plasma-api/workspace.cpp | 5 +++++ src/core/plasma-api/workspace.hpp | 26 +++++++++++++++++++++++++- src/core/qml-plugin.cpp | 3 +-- src/core/ts-proxy.cpp | 12 +++++++++++- src/core/ts-proxy.hpp | 9 ++++++++- src/kwinscript/controller/index.ts | 4 ++-- src/kwinscript/driver/index.ts | 20 +++++++++++++------- src/kwinscript/driver/surface.ts | 15 ++++++++------- src/kwinscript/driver/window.ts | 19 ++++++++++++------- src/kwinscript/extern/proxy.d.ts | 1 + 11 files changed, 105 insertions(+), 28 deletions(-) diff --git a/src/core/plasma-api/utils.hpp b/src/core/plasma-api/utils.hpp index 70d82871..fb822e0b 100644 --- a/src/core/plasma-api/utils.hpp +++ b/src/core/plasma-api/utils.hpp @@ -16,3 +16,22 @@ { \ m_kwinImpl->setProperty(#NAME, QVariant::fromValue(value)); \ } + +/** + * Wrap QML API method + * + * @param RET_TYPE return type of a method + * @param SIGNATURE method signature, that consists of method name (without + * object association) and arguments types. Constness is not needed! + */ +#define BI_METHOD_IMPL_WRAP(RET_TYPE, SIGNATURE, ...) \ + { \ + auto implMeta = m_kwinImpl->metaObject(); \ + /* Signature must not contain return value and cost status*/ \ + auto normSignature = QMetaObject::normalizedSignature(SIGNATURE); \ + auto methodIndex = implMeta->indexOfMethod(normSignature); \ + auto method = implMeta->method(methodIndex); \ + auto result = RET_TYPE(); \ + method.invoke(m_kwinImpl, Qt::DirectConnection, Q_RETURN_ARG(RET_TYPE, result), __VA_ARGS__); \ + return result; \ + } diff --git a/src/core/plasma-api/workspace.cpp b/src/core/plasma-api/workspace.cpp index a6c78aa6..90cc8cac 100644 --- a/src/core/plasma-api/workspace.cpp +++ b/src/core/plasma-api/workspace.cpp @@ -44,6 +44,11 @@ void Workspace::wrapSignals() wrapComplexSignal(SIGNAL(currentDesktopChanged(int, KWin::AbstractClient *)), SLOT(currentDesktopChangedTransformer(int, KWin::AbstractClient *))); }; +QRect Workspace::clientArea(ClientAreaOption option, int screen, int desktop) +{ + BI_METHOD_IMPL_WRAP(QRect, "clientArea(ClientAreaOption, int, int)", Q_ARG(ClientAreaOption, option), Q_ARG(int, screen), Q_ARG(int, desktop)); +}; + void Workspace::currentDesktopChangedTransformer(int desktop, KWin::AbstractClient *kwinClient) { // Since we don't know the KWin internal implementation we have to use reinterpret_cast diff --git a/src/core/plasma-api/workspace.hpp b/src/core/plasma-api/workspace.hpp index bf2de70b..763f8ee5 100644 --- a/src/core/plasma-api/workspace.hpp +++ b/src/core/plasma-api/workspace.hpp @@ -22,12 +22,36 @@ class Workspace : public QObject { Q_OBJECT public: + enum ClientAreaOption { + PlacementArea, // Geometry where a window will be initially placed after being mapped + MovementArea, // Window movement snapping area? Ignore struts + MaximizeArea, // Geometry to which a window will be maximized + MaximizeFullArea, // Like MaximizeArea, but ignore struts + FullScreenArea, // Area for fullscreen windows + WorkArea, // Whole workarea (all screens together) + FullArea, // Whole area (all screens together), ignore struts + ScreenArea, // One whole screen, ignore struts + }; + Q_ENUM(ClientAreaOption) + Workspace(QQmlEngine *engine); Workspace(const Workspace &); BI_PROPERTY(int, currentDesktop, setCurrentDesktop); -public Q_SLOTS: + /** + * Returns the geometry a Client can use with the specified option. + * This method should be preferred over other methods providing screen sizes as the + * various options take constraints such as struts set on panels into account. + * This method is also multi screen aware, but there are also options to get full areas. + * @param option The type of area which should be considered + * @param screen The screen for which the area should be considered + * @param desktop The desktop for which the area should be considered, in general there should not be a difference + * @returns The specified screen geometry + */ + Q_INVOKABLE QRect clientArea(ClientAreaOption, int screen, int desktop); + +private Q_SLOTS: void currentDesktopChangedTransformer(int desktop, KWin::AbstractClient *kwinClient); Q_SIGNALS: diff --git a/src/core/qml-plugin.cpp b/src/core/qml-plugin.cpp index a9b00fde..db27ccf5 100644 --- a/src/core/qml-plugin.cpp +++ b/src/core/qml-plugin.cpp @@ -42,10 +42,9 @@ void Core::init() { m_config = std::make_unique(); m_engine = qmlEngine(this); - qDebug(Bi) << "Core QmlEngine ptr: " << m_engine; m_controller = std::make_unique(); m_plasmaApi = std::make_unique(m_engine); - m_tsProxy = std::make_unique(m_engine, *m_controller, *m_config); + m_tsProxy = std::make_unique(m_engine, *m_controller, *m_plasmaApi, *m_config); } TSProxy *Core::tsProxy() const diff --git a/src/core/ts-proxy.cpp b/src/core/ts-proxy.cpp index 4cbba9d8..8b3193e2 100644 --- a/src/core/ts-proxy.cpp +++ b/src/core/ts-proxy.cpp @@ -10,12 +10,14 @@ #include "controller.hpp" #include "logger.hpp" +#include "plasma-api/plasma-api.hpp" -TSProxy::TSProxy(QQmlEngine *engine, Bismuth::Controller &controller, Bismuth::Config &config) +TSProxy::TSProxy(QQmlEngine *engine, Bismuth::Controller &controller, PlasmaApi::PlasmaApi &plasmaApi, Bismuth::Config &config) : QObject() , m_engine(engine) , m_config(config) , m_controller(controller) + , m_plasmaApi(plasmaApi) { } @@ -107,6 +109,14 @@ QJSValue TSProxy::jsConfig() return configJSObject; } +QJSValue TSProxy::workspace() +{ + auto &workspace = m_plasmaApi.workspace(); + auto jsValue = m_engine->newQObject(&workspace); + QQmlEngine::setObjectOwnership(&workspace, QQmlEngine::CppOwnership); + return jsValue; +} + void TSProxy::registerShortcut(const QJSValue &tsAction) { auto id = tsAction.property("key").toString(); diff --git a/src/core/ts-proxy.hpp b/src/core/ts-proxy.hpp index 1bec0d5f..53b3c98e 100644 --- a/src/core/ts-proxy.hpp +++ b/src/core/ts-proxy.hpp @@ -9,6 +9,7 @@ #include "config.hpp" #include "controller.hpp" +#include "plasma-api/plasma-api.hpp" /** * Proxy object for the legacy TS backend. @@ -17,13 +18,18 @@ class TSProxy : public QObject { Q_OBJECT public: - explicit TSProxy(QQmlEngine *, Bismuth::Controller &, Bismuth::Config &); + TSProxy(QQmlEngine *, Bismuth::Controller &, PlasmaApi::PlasmaApi &, Bismuth::Config &); /** * Returns the config usable in the legacy TypeScript logic */ Q_INVOKABLE QJSValue jsConfig(); + /** + * Returns the workspace instance + */ + Q_INVOKABLE QJSValue workspace(); + /** * Register the actions from the legacy backend * @param tsaction @@ -39,4 +45,5 @@ private: QQmlEngine *m_engine; Bismuth::Config &m_config; Bismuth::Controller &m_controller; + PlasmaApi::PlasmaApi &m_plasmaApi; }; diff --git a/src/kwinscript/controller/index.ts b/src/kwinscript/controller/index.ts index a69b1850..6451f08d 100644 --- a/src/kwinscript/controller/index.ts +++ b/src/kwinscript/controller/index.ts @@ -159,14 +159,14 @@ export class ControllerImpl implements Controller { private engine: Engine; private driver: Driver; public constructor( - private qmlObjects: Bismuth.Qml.Main, + qmlObjects: Bismuth.Qml.Main, kwinApi: KWin.Api, private config: Config, private log: Log, private proxy: TSProxy ) { this.engine = new EngineImpl(this, config, log); - this.driver = new DriverImpl(qmlObjects, kwinApi, this, config, log); + this.driver = new DriverImpl(qmlObjects, kwinApi, this, config, log, proxy); } /** diff --git a/src/kwinscript/driver/index.ts b/src/kwinscript/driver/index.ts index 6e01a4fa..cb7f24b7 100644 --- a/src/kwinscript/driver/index.ts +++ b/src/kwinscript/driver/index.ts @@ -15,6 +15,7 @@ import { WindowState } from "../engine/window"; import { Config } from "../config"; import { Log } from "../util/log"; +import { TSProxy } from "../extern/proxy"; /** * Provides convenient interface to KWin functions. @@ -70,7 +71,8 @@ export class DriverImpl implements Driver { this.kwinApi.workspace.currentDesktop, this.qml.activityInfo, this.kwinApi, - this.config + this.config, + this.proxy ); } @@ -109,7 +111,8 @@ export class DriverImpl implements Driver { this.kwinApi.workspace.currentDesktop, this.qml.activityInfo, this.kwinApi, - this.config + this.config, + this.proxy ) ); } @@ -135,7 +138,8 @@ export class DriverImpl implements Driver { kwinApi: KWin.Api, controller: Controller, private config: Config, - private log: Log + private log: Log, + private proxy: TSProxy ) { this.registeredConnections = []; @@ -155,7 +159,8 @@ export class DriverImpl implements Driver { this.qml, this.kwinApi, this.config, - this.log + this.log, + this.proxy ), this.config, this.log @@ -178,7 +183,8 @@ export class DriverImpl implements Driver { this.kwinApi.workspace.currentDesktop, this.qml.activityInfo, this.kwinApi, - this.config + this.config, + this.proxy ); this.controller.onSurfaceUpdate("resized " + srf.toString()); }; @@ -365,8 +371,8 @@ export class DriverImpl implements Driver { try { callback(); } catch (e: any) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - this.log.log(e); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access + this.log.log(`Oops! ${e.name}: ${e.message}. `); } finally { this.entered = false; } diff --git a/src/kwinscript/driver/surface.ts b/src/kwinscript/driver/surface.ts index fa247a37..b14a9521 100644 --- a/src/kwinscript/driver/surface.ts +++ b/src/kwinscript/driver/surface.ts @@ -4,6 +4,7 @@ // SPDX-License-Identifier: MIT import { Config } from "../config"; +import { TSProxy } from "../extern/proxy"; import { Rect } from "../util/rect"; /** @@ -44,7 +45,8 @@ export class DriverSurfaceImpl implements DriverSurface { public readonly desktop: number, private activityInfo: Plasma.TaskManager.ActivityInfo, private kwinApi: KWin.Api, - private config: Config + private config: Config, + private proxy: TSProxy ) { this.id = this.generateId(); @@ -54,11 +56,9 @@ export class DriverSurfaceImpl implements DriverSurface { this.config.ignoreScreen.indexOf(screen) >= 0; this.workingArea = Rect.fromQRect( - this.kwinApi.workspace.clientArea( - this.kwinApi.KWin.PlacementArea, - screen, - desktop - ) + this.proxy + .workspace() + .clientArea(this.kwinApi.KWin.PlacementArea, screen, desktop) ); } @@ -74,7 +74,8 @@ export class DriverSurfaceImpl implements DriverSurface { this.desktop + 1, this.activityInfo, this.kwinApi, - this.config + this.config, + this.proxy ); } diff --git a/src/kwinscript/driver/window.ts b/src/kwinscript/driver/window.ts index 705c8a8e..06d726bf 100644 --- a/src/kwinscript/driver/window.ts +++ b/src/kwinscript/driver/window.ts @@ -9,6 +9,7 @@ import { Rect } from "../util/rect"; import { clip, matchWords } from "../util/func"; import { Config } from "../config"; import { Log } from "../util/log"; +import { TSProxy } from "../extern/proxy"; /** * KWin window representation. @@ -181,7 +182,8 @@ export class DriverWindowImpl implements DriverWindow { desktop, this.qml.activityInfo, this.kwinApi, - this.config + this.config, + this.proxy ); } @@ -212,7 +214,8 @@ export class DriverWindowImpl implements DriverWindow { private qml: Bismuth.Qml.Main, private kwinApi: KWin.Api, private config: Config, - private log: Log + private log: Log, + private proxy: TSProxy ) { this.id = DriverWindowImpl.generateID(client); this.maximized = false; @@ -273,11 +276,13 @@ export class DriverWindowImpl implements DriverWindow { geometry = this.adjustGeometry(geometry); if (this.config.preventProtrusion) { const area = Rect.fromQRect( - this.kwinApi.workspace.clientArea( - this.kwinApi.KWin.PlacementArea, - this.client.screen, - this.kwinApi.workspace.currentDesktop - ) + this.proxy + .workspace() + .clientArea( + this.kwinApi.KWin.PlacementArea, + this.client.screen, + this.kwinApi.workspace.currentDesktop + ) ); if (!area.includes(geometry)) { /* assume windows will extrude only through right and bottom edges */ diff --git a/src/kwinscript/extern/proxy.d.ts b/src/kwinscript/extern/proxy.d.ts index 949dee4a..b8c6c795 100644 --- a/src/kwinscript/extern/proxy.d.ts +++ b/src/kwinscript/extern/proxy.d.ts @@ -5,6 +5,7 @@ import { Config } from "../config"; import { Action } from "../controller/action"; export interface TSProxy { + workspace(): KWin.WorkspaceWrapper; jsConfig(): Config; registerShortcut(data: Action): void; log(value: any): void;