refactor(wayland): start factoring wayland out of ShellWindow

This commit is contained in:
outfoxxed 2024-02-19 00:36:51 -08:00
parent 55bcae4d62
commit 5bbd0333ef
Signed by: outfoxxed
GPG key ID: 4C88A185FB89301E
5 changed files with 257 additions and 186 deletions

View file

@ -40,6 +40,7 @@ qt_add_executable(quickshell
src/cpp/watcher.cpp src/cpp/watcher.cpp
src/cpp/region.cpp src/cpp/region.cpp
src/cpp/persistentprops.cpp src/cpp/persistentprops.cpp
src/cpp/shellwindow.cpp
) )
qt_add_qml_module(quickshell URI QuickShell) qt_add_qml_module(quickshell URI QuickShell)

View file

@ -12,56 +12,67 @@
#include <qwindow.h> #include <qwindow.h>
#include "proxywindow.hpp" #include "proxywindow.hpp"
#include "shellwindow.hpp"
void ProxyShellWindow::setupWindow() { WaylandShellWindow::WaylandShellWindow(QObject* parent):
ProxyShellWindow(parent), mWayland(new WaylandShellWindowExtensions(this)) {}
void WaylandShellWindow::setupWindow() {
this->shellWindow = LayerShellQt::Window::get(this->window); this->shellWindow = LayerShellQt::Window::get(this->window);
this->ProxyWindowBase::setupWindow(); this->ProxyShellWindow::setupWindow();
// clang-format off // clang-format off
QObject::connect(this->shellWindow, &LayerShellQt::Window::anchorsChanged, this, &ProxyShellWindow::anchorsChanged); QObject::connect(this->shellWindow, &LayerShellQt::Window::anchorsChanged, this, &ProxyShellWindow::anchorsChanged);
QObject::connect(this->shellWindow, &LayerShellQt::Window::marginsChanged, this, &ProxyShellWindow::marginsChanged); QObject::connect(this->shellWindow, &LayerShellQt::Window::marginsChanged, this, &ProxyShellWindow::marginsChanged);
QObject::connect(this->shellWindow, &LayerShellQt::Window::layerChanged, this, &ProxyShellWindow::layerChanged);
QObject::connect(this->shellWindow, &LayerShellQt::Window::keyboardInteractivityChanged, this, &ProxyShellWindow::keyboardFocusChanged);
QObject::connect(this->window, &QWindow::widthChanged, this, &ProxyShellWindow::updateExclusionZone); QObject::connect(
QObject::connect(this->window, &QWindow::heightChanged, this, &ProxyShellWindow::updateExclusionZone); this->shellWindow, &LayerShellQt::Window::layerChanged,
QObject::connect(this, &ProxyShellWindow::anchorsChanged, this, &ProxyShellWindow::updateExclusionZone); this->mWayland, &WaylandShellWindowExtensions::layerChanged
QObject::connect(this, &ProxyShellWindow::marginsChanged, this, &ProxyShellWindow::updateExclusionZone); );
QObject::connect(
this->shellWindow, &LayerShellQt::Window::keyboardInteractivityChanged,
this->mWayland, &WaylandShellWindowExtensions::keyboardFocusChanged
);
QObject::connect(this->window, &QWindow::widthChanged, this, &WaylandShellWindow::updateExclusionZone);
QObject::connect(this->window, &QWindow::heightChanged, this, &WaylandShellWindow::updateExclusionZone);
QObject::connect(this, &ProxyShellWindow::anchorsChanged, this, &WaylandShellWindow::updateExclusionZone);
QObject::connect(this, &ProxyShellWindow::marginsChanged, this, &WaylandShellWindow::updateExclusionZone);
// clang-format on // clang-format on
this->setAnchors(this->mAnchors); this->setAnchors(this->mAnchors);
this->setMargins(this->mMargins); this->setMargins(this->mMargins);
this->setExclusionMode(this->mExclusionMode); // also sets exclusion zone this->setExclusionMode(this->mExclusionMode); // also sets exclusion zone
this->setLayer(this->mLayer); this->mWayland->setLayer(this->mLayer);
this->shellWindow->setScope(this->mScope); this->shellWindow->setScope(this->mScope);
this->setKeyboardFocus(this->mKeyboardFocus); this->mWayland->setKeyboardFocus(this->mKeyboardFocus);
this->connected = true; this->connected = true;
} }
QQuickWindow* ProxyShellWindow::disownWindow() { QQuickWindow* WaylandShellWindow::disownWindow() {
QObject::disconnect(this->shellWindow, nullptr, this, nullptr); QObject::disconnect(this->shellWindow, nullptr, this, nullptr);
return this->ProxyWindowBase::disownWindow(); return this->ProxyWindowBase::disownWindow();
} }
void ProxyShellWindow::setWidth(qint32 width) { void WaylandShellWindow::setWidth(qint32 width) {
this->mWidth = width; this->mWidth = width;
// only update the actual size if not blocked by anchors // only update the actual size if not blocked by anchors
auto anchors = this->anchors(); auto anchors = this->anchors();
if (!anchors.mLeft || !anchors.mRight) this->ProxyWindowBase::setWidth(width); if (!anchors.mLeft || !anchors.mRight) this->ProxyShellWindow::setWidth(width);
} }
void ProxyShellWindow::setHeight(qint32 height) { void WaylandShellWindow::setHeight(qint32 height) {
this->mHeight = height; this->mHeight = height;
// only update the actual size if not blocked by anchors // only update the actual size if not blocked by anchors
auto anchors = this->anchors(); auto anchors = this->anchors();
if (!anchors.mTop || !anchors.mBottom) this->ProxyWindowBase::setHeight(height); if (!anchors.mTop || !anchors.mBottom) this->ProxyShellWindow::setHeight(height);
} }
void ProxyShellWindow::setAnchors(Anchors anchors) { void WaylandShellWindow::setAnchors(Anchors anchors) {
if (this->window == nullptr) { if (this->window == nullptr) {
this->mAnchors = anchors; this->mAnchors = anchors;
return; return;
@ -79,7 +90,7 @@ void ProxyShellWindow::setAnchors(Anchors anchors) {
this->shellWindow->setAnchors(lsAnchors); this->shellWindow->setAnchors(lsAnchors);
} }
Anchors ProxyShellWindow::anchors() const { Anchors WaylandShellWindow::anchors() const {
if (this->window == nullptr) return this->mAnchors; if (this->window == nullptr) return this->mAnchors;
auto lsAnchors = this->shellWindow->anchors(); auto lsAnchors = this->shellWindow->anchors();
@ -93,7 +104,7 @@ Anchors ProxyShellWindow::anchors() const {
return anchors; return anchors;
} }
void ProxyShellWindow::setExclusiveZone(qint32 zone) { void WaylandShellWindow::setExclusiveZone(qint32 zone) {
if (zone < 0) zone = 0; if (zone < 0) zone = 0;
if (this->connected && zone == this->mExclusionZone) return; if (this->connected && zone == this->mExclusionZone) return;
this->mExclusionZone = zone; this->mExclusionZone = zone;
@ -104,14 +115,14 @@ void ProxyShellWindow::setExclusiveZone(qint32 zone) {
} }
} }
qint32 ProxyShellWindow::exclusiveZone() const { qint32 WaylandShellWindow::exclusiveZone() const {
if (this->window == nullptr) return this->mExclusionZone; if (this->window == nullptr) return this->mExclusionZone;
else return this->shellWindow->exclusionZone(); else return this->shellWindow->exclusionZone();
} }
ExclusionMode::Enum ProxyShellWindow::exclusionMode() const { return this->mExclusionMode; } ExclusionMode::Enum WaylandShellWindow::exclusionMode() const { return this->mExclusionMode; }
void ProxyShellWindow::setExclusionMode(ExclusionMode::Enum exclusionMode) { void WaylandShellWindow::setExclusionMode(ExclusionMode::Enum exclusionMode) {
if (this->connected && exclusionMode == this->mExclusionMode) return; if (this->connected && exclusionMode == this->mExclusionMode) return;
this->mExclusionMode = exclusionMode; this->mExclusionMode = exclusionMode;
@ -128,7 +139,7 @@ void ProxyShellWindow::setExclusionMode(ExclusionMode::Enum exclusionMode) {
} }
} }
void ProxyShellWindow::setMargins(Margins margins) { void WaylandShellWindow::setMargins(Margins margins) {
if (this->window == nullptr) this->mMargins = margins; if (this->window == nullptr) this->mMargins = margins;
else { else {
auto lsMargins = QMargins(margins.mLeft, margins.mTop, margins.mRight, margins.mBottom); auto lsMargins = QMargins(margins.mLeft, margins.mTop, margins.mRight, margins.mBottom);
@ -136,7 +147,7 @@ void ProxyShellWindow::setMargins(Margins margins) {
} }
} }
Margins ProxyShellWindow::margins() const { Margins WaylandShellWindow::margins() const {
if (this->window == nullptr) return this->mMargins; if (this->window == nullptr) return this->mMargins;
auto lsMargins = this->shellWindow->margins(); auto lsMargins = this->shellWindow->margins();
@ -149,9 +160,9 @@ Margins ProxyShellWindow::margins() const {
return margins; return margins;
} }
void ProxyShellWindow::setLayer(Layer::Enum layer) { void WaylandShellWindowExtensions::setLayer(Layer::Enum layer) {
if (this->window == nullptr) { if (this->window->window == nullptr) {
this->mLayer = layer; this->window->mLayer = layer;
return; return;
} }
@ -166,14 +177,14 @@ void ProxyShellWindow::setLayer(Layer::Enum layer) {
} }
// clang-format on // clang-format on
this->shellWindow->setLayer(lsLayer); this->window->shellWindow->setLayer(lsLayer);
} }
Layer::Enum ProxyShellWindow::layer() const { Layer::Enum WaylandShellWindowExtensions::layer() const {
if (this->window == nullptr) return this->mLayer; if (this->window->window == nullptr) return this->window->mLayer;
auto layer = Layer::Top; auto layer = Layer::Top;
auto lsLayer = this->shellWindow->layer(); auto lsLayer = this->window->shellWindow->layer();
// clang-format off // clang-format off
switch (lsLayer) { switch (lsLayer) {
@ -187,19 +198,19 @@ Layer::Enum ProxyShellWindow::layer() const {
return layer; return layer;
} }
void ProxyShellWindow::setScope(const QString& scope) { void WaylandShellWindowExtensions::setScope(const QString& scope) {
if (this->window == nullptr) this->mScope = scope; if (this->window->window == nullptr) this->window->mScope = scope;
else this->shellWindow->setScope(scope); else this->window->shellWindow->setScope(scope);
} }
QString ProxyShellWindow::scope() const { QString WaylandShellWindowExtensions::scope() const {
if (this->window == nullptr) return this->mScope; if (this->window->window == nullptr) return this->window->mScope;
else return this->shellWindow->scope(); else return this->window->shellWindow->scope();
} }
void ProxyShellWindow::setKeyboardFocus(KeyboardFocus::Enum focus) { void WaylandShellWindowExtensions::setKeyboardFocus(KeyboardFocus::Enum focus) {
if (this->window == nullptr) { if (this->window->window == nullptr) {
this->mKeyboardFocus = focus; this->window->mKeyboardFocus = focus;
return; return;
} }
@ -213,14 +224,14 @@ void ProxyShellWindow::setKeyboardFocus(KeyboardFocus::Enum focus) {
} }
// clang-format on // clang-format on
this->shellWindow->setKeyboardInteractivity(lsFocus); this->window->shellWindow->setKeyboardInteractivity(lsFocus);
} }
KeyboardFocus::Enum ProxyShellWindow::keyboardFocus() const { KeyboardFocus::Enum WaylandShellWindowExtensions::keyboardFocus() const {
if (this->window == nullptr) return this->mKeyboardFocus; if (this->window->window == nullptr) return this->window->mKeyboardFocus;
auto focus = KeyboardFocus::None; auto focus = KeyboardFocus::None;
auto lsFocus = this->shellWindow->keyboardInteractivity(); auto lsFocus = this->window->shellWindow->keyboardInteractivity();
// clang-format off // clang-format off
switch (lsFocus) { switch (lsFocus) {
@ -233,9 +244,9 @@ KeyboardFocus::Enum ProxyShellWindow::keyboardFocus() const {
return focus; return focus;
} }
void ProxyShellWindow::setScreenConfiguration(ScreenConfiguration::Enum configuration) { void WaylandShellWindowExtensions::setScreenConfiguration(ScreenConfiguration::Enum configuration) {
if (this->window == nullptr) { if (this->window->window == nullptr) {
this->mScreenConfiguration = configuration; this->window->mScreenConfiguration = configuration;
return; return;
} }
@ -248,14 +259,14 @@ void ProxyShellWindow::setScreenConfiguration(ScreenConfiguration::Enum configur
} }
// clang-format on // clang-format on
this->shellWindow->setScreenConfiguration(lsConfiguration); this->window->shellWindow->setScreenConfiguration(lsConfiguration);
} }
ScreenConfiguration::Enum ProxyShellWindow::screenConfiguration() const { ScreenConfiguration::Enum WaylandShellWindowExtensions::screenConfiguration() const {
if (this->window == nullptr) return this->mScreenConfiguration; if (this->window->window == nullptr) return this->window->mScreenConfiguration;
auto configuration = ScreenConfiguration::Window; auto configuration = ScreenConfiguration::Window;
auto lsConfiguration = this->shellWindow->screenConfiguration(); auto lsConfiguration = this->window->shellWindow->screenConfiguration();
// clang-format off // clang-format off
switch (lsConfiguration) { switch (lsConfiguration) {
@ -267,7 +278,7 @@ ScreenConfiguration::Enum ProxyShellWindow::screenConfiguration() const {
return configuration; return configuration;
} }
void ProxyShellWindow::updateExclusionZone() { void WaylandShellWindow::updateExclusionZone() {
if (this->window != nullptr && this->exclusionMode() == ExclusionMode::Auto) { if (this->window != nullptr && this->exclusionMode() == ExclusionMode::Auto) {
auto anchors = this->anchors(); auto anchors = this->anchors();

View file

@ -3,62 +3,10 @@
#include <LayerShellQt/window.h> #include <LayerShellQt/window.h>
#include <qobject.h> #include <qobject.h>
#include <qqmlintegration.h> #include <qqmlintegration.h>
#include <qqmllist.h>
#include <qquickwindow.h>
#include <qscreen.h>
#include <qtmetamacros.h> #include <qtmetamacros.h>
#include <qtypes.h> #include <qtypes.h>
#include <qvariant.h>
#include <qwindow.h>
#include "proxywindow.hpp" #include "shellwindow.hpp"
class Anchors {
Q_GADGET;
Q_PROPERTY(bool left MEMBER mLeft);
Q_PROPERTY(bool right MEMBER mRight);
Q_PROPERTY(bool top MEMBER mTop);
Q_PROPERTY(bool bottom MEMBER mBottom);
public:
bool mLeft = false;
bool mRight = false;
bool mTop = false;
bool mBottom = false;
};
class Margins {
Q_GADGET;
Q_PROPERTY(qint32 left MEMBER mLeft);
Q_PROPERTY(qint32 right MEMBER mRight);
Q_PROPERTY(qint32 top MEMBER mTop);
Q_PROPERTY(qint32 bottom MEMBER mBottom);
public:
qint32 mLeft = 0;
qint32 mRight = 0;
qint32 mTop = 0;
qint32 mBottom = 0;
};
namespace ExclusionMode { // NOLINT
Q_NAMESPACE;
QML_ELEMENT;
enum Enum {
/// Respect the exclusion zone of other shell layers and optionally set one
Normal = 0,
/// Ignore exclusion zones of other shell layers. You cannot set an exclusion zone in this mode.
Ignore = 1,
/// Decide the exclusion zone based on the window dimensions and anchors.
///
/// Will attempt to reseve exactly enough space for the window and its margins if
/// exactly 3 anchors are connected.
Auto = 2,
};
Q_ENUM_NS(Enum);
} // namespace ExclusionMode
namespace Layer { // NOLINT namespace Layer { // NOLINT
Q_NAMESPACE; Q_NAMESPACE;
@ -109,78 +57,69 @@ Q_ENUM_NS(Enum);
} // namespace ScreenConfiguration } // namespace ScreenConfiguration
///! Decorationless window attached to screen edges by anchors. class WaylandShellWindowExtensions;
/// Decorationless window attached to screen edges by anchors.
/// class WaylandShellWindow: public ProxyShellWindow {
/// #### Example Q_OBJECT;
/// The following snippet creates a white bar attached to the bottom of [TODO] screen. Q_PROPERTY(WaylandShellWindowExtensions* wayland MEMBER mWayland CONSTANT);
/// QML_NAMED_ELEMENT(ShellWindow);
/// ```qml
/// ShellWindow { public:
/// anchors { explicit WaylandShellWindow(QObject* parent = nullptr);
/// left: true
/// bottom: true WaylandShellWindowExtensions* wayland();
/// right: true
/// } void setupWindow() override;
/// QQuickWindow* disownWindow() override;
/// Text {
/// anchors.horizontalCenter: parent.horizontalCenter void setWidth(qint32 width) override;
/// anchors.verticalCenter: parent.verticalCenter void setHeight(qint32 height) override;
/// text: "Hello!"
/// } void setAnchors(Anchors anchors) override;
/// } [[nodiscard]] Anchors anchors() const override;
/// ```
class ProxyShellWindow: public ProxyWindowBase { void setExclusiveZone(qint32 zone) override;
// clang-format off [[nodiscard]] qint32 exclusiveZone() const override;
void setExclusionMode(ExclusionMode::Enum exclusionMode) override;
[[nodiscard]] ExclusionMode::Enum exclusionMode() const override;
void setMargins(Margins margins) override;
[[nodiscard]] Margins margins() const override;
protected slots:
void updateExclusionZone();
private:
WaylandShellWindowExtensions* mWayland = nullptr;
LayerShellQt::Window* shellWindow = nullptr;
Layer::Enum mLayer = Layer::Top;
QString mScope;
KeyboardFocus::Enum mKeyboardFocus = KeyboardFocus::None;
ScreenConfiguration::Enum mScreenConfiguration = ScreenConfiguration::Window;
bool connected = false;
friend class WaylandShellWindowExtensions;
};
class WaylandShellWindowExtensions: public QObject {
Q_OBJECT; Q_OBJECT;
/// Anchors attach a shell window to the sides of the screen.
/// By default all anchors are disabled to avoid blocking the entire screen due to a misconfiguration.
///
/// > [!INFO] When two opposite anchors are attached at the same time, the corrosponding dimension
/// > (width or height) will be forced to equal the screen width/height.
/// > Margins can be used to create anchored windows that are also disconnected from the monitor sides.
Q_PROPERTY(Anchors anchors READ anchors WRITE setAnchors NOTIFY anchorsChanged);
/// The amount of space reserved for the shell layer relative to its anchors.
///
/// > [!INFO] Some systems will require exactly 3 anchors to be attached for the exclusion zone to take
/// > effect.
Q_PROPERTY(qint32 exclusionZone READ exclusiveZone WRITE setExclusiveZone NOTIFY exclusionZoneChanged);
/// Defaults to `ExclusionMode.Normal`.
Q_PROPERTY(ExclusionMode::Enum exclusionMode READ exclusionMode WRITE setExclusionMode NOTIFY exclusionModeChanged);
/// Offsets from the sides of the screen.
///
/// > [!INFO] Only applies to edges with anchors
Q_PROPERTY(Margins margins READ margins WRITE setMargins NOTIFY marginsChanged);
/// The shell layer the window sits in. Defaults to `Layer.Top`. /// The shell layer the window sits in. Defaults to `Layer.Top`.
Q_PROPERTY(Layer::Enum layer READ layer WRITE setLayer NOTIFY layerChanged); Q_PROPERTY(Layer::Enum layer READ layer WRITE setLayer NOTIFY layerChanged);
Q_PROPERTY(QString scope READ scope WRITE setScope); Q_PROPERTY(QString scope READ scope WRITE setScope);
/// The degree of keyboard focus taken. Defaults to `KeyboardFocus.None`. /// The degree of keyboard focus taken. Defaults to `KeyboardFocus.None`.
Q_PROPERTY(KeyboardFocus::Enum keyboardFocus READ keyboardFocus WRITE setKeyboardFocus NOTIFY keyboardFocusChanged); Q_PROPERTY(KeyboardFocus::Enum keyboardFocus READ keyboardFocus WRITE setKeyboardFocus NOTIFY
Q_PROPERTY(ScreenConfiguration::Enum screenConfiguration READ screenConfiguration WRITE setScreenConfiguration); keyboardFocusChanged);
QML_NAMED_ELEMENT(ShellWindow); Q_PROPERTY(ScreenConfiguration::Enum screenConfiguration READ screenConfiguration WRITE
// clang-format on setScreenConfiguration);
QML_ELEMENT;
QML_UNCREATABLE("WaylandShellWindowExtensions cannot be created");
public: public:
void setupWindow() override; explicit WaylandShellWindowExtensions(WaylandShellWindow* window):
QQuickWindow* disownWindow() override; QObject(window), window(window) {}
QQmlListProperty<QObject> data();
void setWidth(qint32 width) override;
void setHeight(qint32 height) override;
void setAnchors(Anchors anchors);
[[nodiscard]] Anchors anchors() const;
void setExclusiveZone(qint32 zone);
[[nodiscard]] qint32 exclusiveZone() const;
void setExclusionMode(ExclusionMode::Enum exclusionMode);
[[nodiscard]] ExclusionMode::Enum exclusionMode() const;
void setMargins(Margins margins);
[[nodiscard]] Margins margins() const;
void setLayer(Layer::Enum layer); void setLayer(Layer::Enum layer);
[[nodiscard]] Layer::Enum layer() const; [[nodiscard]] Layer::Enum layer() const;
@ -195,26 +134,11 @@ public:
[[nodiscard]] ScreenConfiguration::Enum screenConfiguration() const; [[nodiscard]] ScreenConfiguration::Enum screenConfiguration() const;
signals: signals:
void anchorsChanged();
void marginsChanged();
void exclusionZoneChanged();
void exclusionModeChanged();
void layerChanged(); void layerChanged();
void keyboardFocusChanged(); void keyboardFocusChanged();
private slots:
void updateExclusionZone();
private: private:
LayerShellQt::Window* shellWindow = nullptr; WaylandShellWindow* window;
ExclusionMode::Enum mExclusionMode = ExclusionMode::Normal;
qint32 mExclusionZone = 0;
Anchors mAnchors;
Margins mMargins;
Layer::Enum mLayer = Layer::Top;
QString mScope;
KeyboardFocus::Enum mKeyboardFocus = KeyboardFocus::None;
ScreenConfiguration::Enum mScreenConfiguration = ScreenConfiguration::Window;
bool connected = false; friend class WaylandShellWindow;
}; };

1
src/cpp/shellwindow.cpp Normal file
View file

@ -0,0 +1 @@
#include "shellwindow.hpp" // NOLINT

134
src/cpp/shellwindow.hpp Normal file
View file

@ -0,0 +1,134 @@
#pragma once
#include <qobject.h>
#include <qqmlintegration.h>
#include <qqmllist.h>
#include <qquickwindow.h>
#include <qscreen.h>
#include <qtmetamacros.h>
#include <qtypes.h>
#include <qvariant.h>
#include <qwindow.h>
#include "proxywindow.hpp"
class Anchors {
Q_GADGET;
Q_PROPERTY(bool left MEMBER mLeft);
Q_PROPERTY(bool right MEMBER mRight);
Q_PROPERTY(bool top MEMBER mTop);
Q_PROPERTY(bool bottom MEMBER mBottom);
public:
bool mLeft = false;
bool mRight = false;
bool mTop = false;
bool mBottom = false;
};
class Margins {
Q_GADGET;
Q_PROPERTY(qint32 left MEMBER mLeft);
Q_PROPERTY(qint32 right MEMBER mRight);
Q_PROPERTY(qint32 top MEMBER mTop);
Q_PROPERTY(qint32 bottom MEMBER mBottom);
public:
qint32 mLeft = 0;
qint32 mRight = 0;
qint32 mTop = 0;
qint32 mBottom = 0;
};
namespace ExclusionMode { // NOLINT
Q_NAMESPACE;
QML_ELEMENT;
enum Enum {
/// Respect the exclusion zone of other shell layers and optionally set one
Normal = 0,
/// Ignore exclusion zones of other shell layers. You cannot set an exclusion zone in this mode.
Ignore = 1,
/// Decide the exclusion zone based on the window dimensions and anchors.
///
/// Will attempt to reseve exactly enough space for the window and its margins if
/// exactly 3 anchors are connected.
Auto = 2,
};
Q_ENUM_NS(Enum);
} // namespace ExclusionMode
///! Decorationless window attached to screen edges by anchors.
/// Decorationless window attached to screen edges by anchors.
///
/// #### Example
/// The following snippet creates a white bar attached to the bottom of the screen.
///
/// ```qml
/// ShellWindow {
/// anchors {
/// left: true
/// bottom: true
/// right: true
/// }
///
/// Text {
/// anchors.horizontalCenter: parent.horizontalCenter
/// anchors.verticalCenter: parent.verticalCenter
/// text: "Hello!"
/// }
/// }
/// ```
class ProxyShellWindow: public ProxyWindowBase {
// clang-format off
Q_OBJECT;
/// Anchors attach a shell window to the sides of the screen.
/// By default all anchors are disabled to avoid blocking the entire screen due to a misconfiguration.
///
/// > [!INFO] When two opposite anchors are attached at the same time, the corrosponding dimension
/// > (width or height) will be forced to equal the screen width/height.
/// > Margins can be used to create anchored windows that are also disconnected from the monitor sides.
Q_PROPERTY(Anchors anchors READ anchors WRITE setAnchors NOTIFY anchorsChanged);
/// The amount of space reserved for the shell layer relative to its anchors.
///
/// > [!INFO] Some systems will require exactly 3 anchors to be attached for the exclusion zone to take
/// > effect.
Q_PROPERTY(qint32 exclusionZone READ exclusiveZone WRITE setExclusiveZone NOTIFY exclusionZoneChanged);
/// Defaults to `ExclusionMode.Normal`.
Q_PROPERTY(ExclusionMode::Enum exclusionMode READ exclusionMode WRITE setExclusionMode NOTIFY exclusionModeChanged);
/// Offsets from the sides of the screen.
///
/// > [!INFO] Only applies to edges with anchors
Q_PROPERTY(Margins margins READ margins WRITE setMargins NOTIFY marginsChanged);
// clang-format on
public:
explicit ProxyShellWindow(QObject* parent = nullptr): ProxyWindowBase(parent) {}
QQmlListProperty<QObject> data();
virtual void setAnchors(Anchors anchors) = 0;
[[nodiscard]] virtual Anchors anchors() const = 0;
virtual void setExclusiveZone(qint32 zone) = 0;
[[nodiscard]] virtual qint32 exclusiveZone() const = 0;
virtual void setExclusionMode(ExclusionMode::Enum exclusionMode) = 0;
[[nodiscard]] virtual ExclusionMode::Enum exclusionMode() const = 0;
virtual void setMargins(Margins margins) = 0;
[[nodiscard]] virtual Margins margins() const = 0;
signals:
void anchorsChanged();
void marginsChanged();
void exclusionZoneChanged();
void exclusionModeChanged();
protected:
ExclusionMode::Enum mExclusionMode = ExclusionMode::Normal;
qint32 mExclusionZone = 0;
Anchors mAnchors;
Margins mMargins;
};