From 53c485aef7e5eb4b8141d4a01d27ef59024c3ac0 Mon Sep 17 00:00:00 2001 From: Aleix Pol Gonzalez Date: Fri, 7 Jul 2023 18:27:52 +0200 Subject: [PATCH] Expose the Window interface to QML If we are designing our UI's windows from QML, it makes sense that we might want to configure how they're placed from the same place. Everything was already in place but for a few technical bits which this change adds. Signed-off-by: Victoria Fischer --- CMakeLists.txt | 1 + src/CMakeLists.txt | 5 +- src/declarative/CMakeLists.txt | 8 ++ src/declarative/layershellqtplugin.cpp | 24 ++++++ src/interfaces/window.cpp | 9 ++ src/interfaces/window.h | 10 +++ tests/quicktest.qml | 110 +++++++++++++++++++++++++ 7 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 src/declarative/CMakeLists.txt create mode 100644 src/declarative/layershellqtplugin.cpp create mode 100644 tests/quicktest.qml diff --git a/CMakeLists.txt b/CMakeLists.txt index fd3b95f..6b3826d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ include(CMakePackageConfigHelpers) include(FeatureSummary) include(GenerateExportHeader) include(KDEClangFormat) +include(ECMQmlModule) include(ECMQtDeclareLoggingCategory) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0b9877c..1605134 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,7 +19,8 @@ ecm_qt_declare_logging_category(LAYER_SHELL_SOURCES ) target_sources(LayerShellQtInterface PRIVATE qwaylandlayersurface.cpp interfaces/window.cpp interfaces/shell.cpp qwaylandlayershellintegration.cpp ${LAYER_SHELL_SOURCES}) -target_link_libraries(LayerShellQtInterface PRIVATE Qt::Gui Qt::WaylandClientPrivate Wayland::Client PkgConfig::XKBCOMMON) +target_link_libraries(LayerShellQtInterface PUBLIC Qt::Gui) +target_link_libraries(LayerShellQtInterface PRIVATE Qt::WaylandClientPrivate Wayland::Client PkgConfig::XKBCOMMON) if (TARGET Qt::XkbCommonSupportPrivate) target_link_libraries(LayerShellQtInterface PRIVATE Qt::XkbCommonSupportPrivate) endif() @@ -63,3 +64,5 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/LayerShellQt/layershellqt_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/LayerShellQt COMPONENT Devel ) + +add_subdirectory(declarative) diff --git a/src/declarative/CMakeLists.txt b/src/declarative/CMakeLists.txt new file mode 100644 index 0000000..8e804b9 --- /dev/null +++ b/src/declarative/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez +# SPDX-License-Identifier: BSD-3-Clause + +ecm_add_qml_module(LayerShellQtQml URI "org.kde.layershell") +target_sources(LayerShellQtQml PRIVATE layershellqtplugin.cpp) +target_link_libraries(LayerShellQtQml PRIVATE Qt::Qml LayerShellQtInterface) + +ecm_finalize_qml_module(LayerShellQtQml DESTINATION ${KDE_INSTALL_QMLDIR}) diff --git a/src/declarative/layershellqtplugin.cpp b/src/declarative/layershellqtplugin.cpp new file mode 100644 index 0000000..4c89ae4 --- /dev/null +++ b/src/declarative/layershellqtplugin.cpp @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2023 Aleix Pol Gonzalez + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +#include +#include "../interfaces/window.h" +#include + +QML_DECLARE_TYPEINFO(LayerShellQt::Window, QML_HAS_ATTACHED_PROPERTIES) + +class Plugin : public QQmlExtensionPlugin +{ + Q_PLUGIN_METADATA(IID "org.kde.layershellqt") + Q_OBJECT +public: + void registerTypes(const char *uri) override { + Q_ASSERT(QLatin1String(uri) == QLatin1String("org.kde.layershell")); + qmlRegisterType(uri, 1, 0, "Window"); + } +}; + +#include "layershellqtplugin.moc" diff --git a/src/interfaces/window.cpp b/src/interfaces/window.cpp index 1c92956..97233e6 100644 --- a/src/interfaces/window.cpp +++ b/src/interfaces/window.cpp @@ -186,9 +186,18 @@ Window::Window(QWindow *window) Window *Window::get(QWindow *window) { + if (!window) { + return nullptr; + } + auto layerShellWindow = s_map.value(window); if (layerShellWindow) { return layerShellWindow; } return new Window(window); } + +Window *Window::qmlAttachedProperties(QObject *object) +{ + return get(qobject_cast(object)); +} diff --git a/src/interfaces/window.h b/src/interfaces/window.h index 7eff583..3f3ae80 100644 --- a/src/interfaces/window.h +++ b/src/interfaces/window.h @@ -25,6 +25,14 @@ class WindowPrivate; class LAYERSHELLQT_EXPORT Window : public QObject { Q_OBJECT + Q_PROPERTY(Anchors anchors READ anchors WRITE setAnchors NOTIFY anchorsChanged) + Q_PROPERTY(QString scope READ scope WRITE setScope) + Q_PROPERTY(QMargins margins READ margins WRITE setMargins NOTIFY marginsChanged) + Q_PROPERTY(qint32 exclusionZone READ exclusionZone WRITE setExclusiveZone NOTIFY exclusionZoneChanged) + Q_PROPERTY(Layer layer READ layer WRITE setLayer NOTIFY layerChanged) + Q_PROPERTY(KeyboardInteractivity keyboardInteractivity READ keyboardInteractivity WRITE setKeyboardInteractivity NOTIFY keyboardInteractivityChanged) + Q_PROPERTY(ScreenConfiguration screenConfiguration READ screenConfiguration WRITE setScreenConfiguration) + public: ~Window() override; @@ -116,6 +124,8 @@ public: static void attachPopup(QWindow *window, xdg_popup *popup); #endif + static Window *qmlAttachedProperties(QObject *object); + Q_SIGNALS: void anchorsChanged(); void exclusionZoneChanged(); diff --git a/tests/quicktest.qml b/tests/quicktest.qml new file mode 100644 index 0000000..83f99bd --- /dev/null +++ b/tests/quicktest.qml @@ -0,0 +1,110 @@ +/* + * SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez + * + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +import QtQuick 2.15 +import org.kde.layershell 1.0 as LayerShell + +Item +{ + Text { + text: "A normal Window" + anchors.centerIn: parent + } + + Window { + LayerShell.Window.anchors: LayerShell.Window.AnchorLeft + LayerShell.Window.layer: LayerShell.Window.LayerBackground + LayerShell.Window.exclusionZone: -1 + + width: 200 + height: 150 + Rectangle { + anchors.fill: parent + color: "green" + + Text { + anchors.centerIn: parent + text: "left bg" + } + } + visible: true + } + + + Window { + LayerShell.Window.scope: "dock" + LayerShell.Window.anchors: LayerShell.Window.AnchorLeft + LayerShell.Window.layer: LayerShell.Window.LayerTop + LayerShell.Window.exclusionZone: width + + width: 100 + height: 100 + Rectangle { + anchors.fill: parent + color: "red" + + Text { + anchors.centerIn: parent + text: "left" + } + } + visible: true + } + + Window { + LayerShell.Window.scope: "normal" + LayerShell.Window.anchors: LayerShell.Window.AnchorRight + + width: 100 + height: 100 + Rectangle { + anchors.fill: parent + color: "red" + + Text { + anchors.centerIn: parent + text: "right" + } + } + visible: true + } + + Window { + LayerShell.Window.scope: "normal" + LayerShell.Window.anchors: LayerShell.Window.AnchorTop + + width: 100 + height: 100 + Rectangle { + anchors.fill: parent + color: "red" + + Text { + anchors.centerIn: parent + text: "top" + } + } + visible: true + } + + Window { + LayerShell.Window.scope: "normal" + LayerShell.Window.anchors: LayerShell.Window.AnchorBottom + + width: 100 + height: 100 + Rectangle { + anchors.fill: parent + color: "red" + + Text { + anchors.centerIn: parent + text: "bottom" + } + } + visible: true + } +}