diff --git a/src/interfaces/shell.cpp b/src/interfaces/shell.cpp index 6eb490c..89b42d7 100644 --- a/src/interfaces/shell.cpp +++ b/src/interfaces/shell.cpp @@ -6,8 +6,8 @@ #include "shell.h" #include -#include #include +#include using namespace LayerShellQt; diff --git a/src/interfaces/shell.h b/src/interfaces/shell.h index cccae17..c68017a 100644 --- a/src/interfaces/shell.h +++ b/src/interfaces/shell.h @@ -8,6 +8,8 @@ #define LAYERSHELLQTSHELL_H #include "layershellqt_export.h" +#include "window.h" +#include namespace LayerShellQt { diff --git a/src/interfaces/window.cpp b/src/interfaces/window.cpp index a1eaa99..4f3c5f2 100644 --- a/src/interfaces/window.cpp +++ b/src/interfaces/window.cpp @@ -15,58 +15,133 @@ using namespace LayerShellQt; class LayerShellQt::WindowPrivate { public: - WindowPrivate(QWaylandLayerSurface *surface) - : surface(surface) + WindowPrivate(QWindow *window) + : parentWindow(window) { } - QWaylandLayerSurface *const surface; + QWindow *parentWindow; + QString scope = QStringLiteral("qt"); + Window::Anchors anchor = {Window::AnchorTop | Window::AnchorBottom | Window::AnchorLeft | Window::AnchorRight}; + int32_t exclusionZone = 0; + bool keyboardInteractivity = false; + Window::Layer layer = Window::LayerTop; + QMargins margins; + QWaylandLayerSurface* getSurface() const; }; -Window::~Window() = default; +static QMap s_map; -void Window::setAnchor(Anchor anchor) +Window::~Window() { - d->surface->setAnchor(anchor); + s_map.remove(d->parentWindow); +} + +void Window::setAnchor(Anchors anchor) +{ + d->anchor = anchor; + if (auto surface = d->getSurface()) { + surface->setAnchor(anchor); + } +} + +Window::Anchors Window::anchor() const +{ + return d->anchor; } void Window::setExclusiveZone(int32_t zone) { - d->surface->setExclusiveZone(zone); + d->exclusionZone = zone; + if (auto surface= d->getSurface()) { + surface->setExclusiveZone(zone); + } +} + +int32_t Window::exclusionZone() const +{ + return d->exclusionZone; } void Window::setMargins(const QMargins &margins) { - d->surface->setMargins(margins); + d->margins = margins; + if (auto surface= d->getSurface()) { + surface->setMargins(margins); + } +} + +QMargins Window::margins() const +{ + return d->margins; } void Window::setKeyboardInteractivity(bool enabled) { - d->surface->setKeyboardInteractivity(enabled); + d->keyboardInteractivity = enabled; + if (auto surface= d->getSurface()) { + surface->setKeyboardInteractivity(enabled); + } +} + +bool Window::keyboardInteractivity() const +{ + return d->keyboardInteractivity; } void Window::setLayer(Layer layer) { - d->surface->setLayer(layer); + d->layer = layer; + if (auto surface= d->getSurface()) { + surface->setLayer(layer); + } +} + +void Window::setScope(const QString &scope) +{ + d->scope = scope; + //this is static and must be set before the platform window is created +} + +QString Window::scope() const +{ + return d->scope; +} + +Window::Layer Window::layer() const +{ + return d->layer; } Window::Window(WindowPrivate *d) - : d(d) + : QObject(d->parentWindow) + , d(d) { + s_map.insert(d->parentWindow, this); } -Window *Window::get(QWindow *window) +QWaylandLayerSurface *WindowPrivate::getSurface() const { - auto ww = dynamic_cast(window->handle()); + if (!parentWindow) { + return nullptr; + } + auto ww = dynamic_cast(parentWindow->handle()); if (!ww) { - qCDebug(LAYERSHELLQT) << "window not a wayland window" << window; + qCDebug(LAYERSHELLQT) << "window not a wayland window" << parentWindow; return nullptr; } QWaylandLayerSurface *s = qobject_cast(ww->shellSurface()); if (!s) { - qCDebug(LAYERSHELLQT) << "window not using wlr-layer-shell" << window << ww->shellSurface(); + qCDebug(LAYERSHELLQT) << "window not using wlr-layer-shell" << parentWindow << ww->shellSurface(); return nullptr; } - - return new Window(new WindowPrivate(s)); + return s; +} + +Window *Window::get(QWindow *window) +{ + if (s_map.contains(window)) { + return s_map[window]; + } + return new Window(new WindowPrivate(window)); } diff --git a/src/interfaces/window.h b/src/interfaces/window.h index 64fbbcb..c820d99 100644 --- a/src/interfaces/window.h +++ b/src/interfaces/window.h @@ -30,6 +30,7 @@ public: AnchorRight = 8, // the right edge of the anchor rectangle }; Q_ENUM(Anchor); + Q_DECLARE_FLAGS(Anchors, Anchor) /** * This enum type is used to specify the layer where a surface can be put in. @@ -42,12 +43,28 @@ public: }; Q_ENUM(Layer) - void setAnchor(Anchor anchor); - void setExclusiveZone(int32_t zone); - void setMargins(const QMargins &margins); - void setKeyboardInteractivity(bool enabled); - void setLayer(Layer layer); + void setAnchor(Anchors anchor); + Anchors anchor() const; + void setExclusiveZone(int32_t zone); + int32_t exclusionZone() const; + + void setMargins(const QMargins &margins); + QMargins margins() const; + + void setKeyboardInteractivity(bool enabled); + bool keyboardInteractivity() const; + + void setLayer(Layer layer); + Layer layer() const; + + void setScope(const QString &scope); + QString scope() const; + + /** + * Gets the LayerShell Window for a given Qt Window + * Ownership is not transferred + */ static Window *get(QWindow *window); private: diff --git a/src/qwaylandlayersurface.cpp b/src/qwaylandlayersurface.cpp index d1bcd3c..3a840e2 100644 --- a/src/qwaylandlayersurface.cpp +++ b/src/qwaylandlayersurface.cpp @@ -5,6 +5,7 @@ * SPDX-License-Identifier: LGPL-3.0-or-later */ +#include "interfaces/shell.h" #include "qwaylandlayershell_p.h" #include "qwaylandlayersurface_p.h" @@ -16,14 +17,38 @@ namespace LayerShellQt { QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShell *shell, QtWaylandClient::QWaylandWindow *window) : QtWaylandClient::QWaylandShellSurface(window) - , QtWayland::zwlr_layer_surface_v1( - // TODO: Specify namespace - shell->get_layer_surface(window->waylandSurface()->object(), - window->waylandScreen()->output(), - QtWayland::zwlr_layer_shell_v1::layer_top, - QStringLiteral("qt"))) + , QtWayland::zwlr_layer_surface_v1() { - set_anchor(anchor_top | anchor_bottom | anchor_left | anchor_right); + Window::Layer layer =Window::LayerTop; + QString scope =QStringLiteral( "qt"); + LayerShellQt::Window *interface = Window::get(window->window()); + Window::Anchors anchors = {Window::AnchorTop | Window::AnchorBottom | Window::AnchorLeft | Window::AnchorRight}; + + if (interface) { + anchors = interface->anchor(); + layer = interface->layer(); + scope = interface->scope(); + } + + init(shell->get_layer_surface(window->waylandSurface()->object(), window->waylandScreen()->output(), layer, scope)); + set_anchor(anchors); + + if (interface) { + setMargins(interface->margins()); + setKeyboardInteractivity(interface->keyboardInteractivity()); + setExclusiveZone(interface->exclusionZone()); + } + + QSize size = window->surfaceSize(); + if (anchors & Window::AnchorLeft && anchors & Window::AnchorRight) { + size.setWidth(0); + } + if (anchors & Window::AnchorTop && anchors & Window::AnchorBottom) { + size.setHeight(0); + } + if (size.isValid() && size != QSize(0,0)) { + set_size(size.width(), size.height()); + } } QWaylandLayerSurface::~QWaylandLayerSurface() diff --git a/tests/main.cpp b/tests/main.cpp index c3d4d3d..9c82ba7 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -4,35 +4,96 @@ * SPDX-License-Identifier: LGPL-3.0-or-later */ +#include + #include -#include +#include +#include +#include +#include + +#include + #include #include +using namespace LayerShellQt; + +QStringList enumsToStringList(QMetaEnum metaEnum) +{ + QStringList ret; + ret.reserve(metaEnum.keyCount()); + for (int i = 0; i < metaEnum.keyCount(); ++i) { + ret.append(metaEnum.key(i)); + } + return ret; +} + +template +T stringToEnum(QMetaEnum metaEnum, const QString &str) +{ + T ret = {}; + const auto splitted = str.split(QLatin1Char('|')); + for (const auto &value : splitted) { + ret |= T(metaEnum.keyToValue(qPrintable(value))); + } + return ret; +} + +class BasicWindow : public QRasterWindow +{ + void paintEvent(QPaintEvent *) { + QPainter p(this); + p.fillRect(QRect(0,0,width(), height()), Qt::red); + } +}; + int main(int argc, char **argv) { - LayerShellQt::Shell::useLayerShell(); + Shell::useLayerShell(); QGuiApplication app(argc, argv); - QQmlApplicationEngine engine; - engine.loadData( - "import QtQuick.Controls 2.10\n" - "import QtQuick 2.10\n" - "\n" - "ApplicationWindow {" - " width: 100; height: 100\n" - " visible: true\n" - " Rectangle { color: 'red'; anchors.fill: parent }" - "}" - , - QStringLiteral("bananaland:/potato.qml")); + const auto layerMetaEnum = QMetaEnum::fromType(); + const auto anchorMetaEnum = QMetaEnum::fromType(); - QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [](QObject *object) { - auto layerWindow = LayerShellQt::Window::get(qobject_cast(object)); - Q_ASSERT(layerWindow); - layerWindow->setMargins({50, 50, 50, 50}); - }); + QCommandLineParser parser; + QCommandLineOption marginsOption(QStringLiteral("margins"), QStringLiteral("Window margins"), QStringLiteral("pixels"), QStringLiteral("0")); + QCommandLineOption scopeOption(QStringLiteral("scope"), QStringLiteral("Window scope"), QStringLiteral("namespace"), QStringLiteral("normal")); + QCommandLineOption anchorsOption(QStringLiteral("anchors"), + QStringLiteral("Either ") + enumsToStringList(anchorMetaEnum).join(QLatin1String("|")), + QStringLiteral("anchors"), + QStringLiteral("AnchorTop|AnchorBottom|AnchorLeft|AnchorRight")); + QCommandLineOption layerOption(QStringLiteral("layer"), + QStringLiteral("One of ") + enumsToStringList(layerMetaEnum).join(QLatin1String("|")), + QStringLiteral("layer"), + QStringLiteral("LayerTop")); + parser.addOptions({marginsOption, scopeOption, anchorsOption, layerOption}); + parser.addHelpOption(); + parser.process(app); + + BasicWindow window; + + LayerShellQt::Window* layerShell = LayerShellQt::Window::get(&window); + if (parser.isSet(marginsOption)) { + int margins = parser.value(marginsOption).toInt(); + layerShell->setMargins({margins, margins, margins, margins}); + } + + if (parser.isSet(scopeOption)) { + layerShell->setScope(parser.value(scopeOption)); + } + if (parser.isSet(layerOption)) { + layerShell->setLayer(Window::Layer(layerMetaEnum.keyToValue(qPrintable(parser.value(layerOption))))); + } + if (parser.isSet(anchorsOption)) { + layerShell->setAnchor(stringToEnum(anchorMetaEnum, parser.value(anchorsOption))); + } + window.show(); + + + // just so you don't block yourself out whilst testing + QTimer::singleShot(5000, &app, &QGuiApplication::quit); return app.exec(); }