diff --git a/src/cpp/layershell.cpp b/src/cpp/layershell.cpp index ca1b099e..ed752eaa 100644 --- a/src/cpp/layershell.cpp +++ b/src/cpp/layershell.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,11 @@ void ProxyShellWindow::earlyInit(QObject* old) { 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(this->window, &QWindow::heightChanged, this, &ProxyShellWindow::updateExclusionZone); + QObject::connect(this, &ProxyShellWindow::anchorsChanged, this, &ProxyShellWindow::updateExclusionZone); + QObject::connect(this, &ProxyShellWindow::marginsChanged, this, &ProxyShellWindow::updateExclusionZone); // clang-format on } @@ -40,6 +46,7 @@ void ProxyShellWindow::componentComplete() { // The default anchor settings are a hazard because they cover the entire screen. // We opt for 0 anchors by default to avoid blocking user input. this->setAnchors(this->stagingAnchors); + this->updateExclusionZone(); // Make sure we signal changes from anchors, but only if this is a reload. // If we do it on first load then it sends an extra change at 0px. @@ -135,10 +142,36 @@ Anchors ProxyShellWindow::anchors() const { return anchors; } -void ProxyShellWindow::setExclusiveZone(qint32 zone) { this->shellWindow->setExclusiveZone(zone); } +void ProxyShellWindow::setExclusiveZone(qint32 zone) { + if (zone < 0) zone = 0; + if (zone == this->requestedExclusionZone) return; + this->requestedExclusionZone = zone; + + if (this->exclusionMode() == ExclusionMode::Normal) { + this->shellWindow->setExclusiveZone(zone); + emit this->exclusionZoneChanged(); + } +} qint32 ProxyShellWindow::exclusiveZone() const { return this->shellWindow->exclusionZone(); } +ExclusionMode::Enum ProxyShellWindow::exclusionMode() const { return this->mExclusionMode; } + +void ProxyShellWindow::setExclusionMode(ExclusionMode::Enum exclusionMode) { + if (exclusionMode == this->mExclusionMode) return; + this->mExclusionMode = exclusionMode; + + if (exclusionMode == ExclusionMode::Normal) { + this->shellWindow->setExclusiveZone(this->requestedExclusionZone); + emit this->exclusionZoneChanged(); + } else if (exclusionMode == ExclusionMode::Ignore) { + this->shellWindow->setExclusiveZone(-1); + emit this->exclusionZoneChanged(); + } else { + this->updateExclusionZone(); + } +} + void ProxyShellWindow::setMargins(Margins margins) { auto lsMargins = QMargins(margins.mLeft, margins.mTop, margins.mRight, margins.mBottom); this->shellWindow->setMargins(lsMargins); @@ -252,3 +285,24 @@ void ProxyShellWindow::setCloseOnDismissed(bool close) { } bool ProxyShellWindow::closeOnDismissed() const { return this->shellWindow->closeOnDismissed(); } + +void ProxyShellWindow::updateExclusionZone() { + if (this->exclusionMode() == ExclusionMode::Auto) { + auto anchors = this->anchors(); + + auto zone = -1; + + if (anchors.mTop && anchors.mBottom) { + if (anchors.mLeft) zone = this->width() + this->margins().mLeft; + else if (anchors.mRight) zone = this->width() + this->margins().mRight; + } else if (anchors.mLeft && anchors.mRight) { + if (anchors.mTop) zone = this->height() + this->margins().mTop; + else if (anchors.mBottom) zone = this->height() + this->margins().mBottom; + } + + if (zone != -1) { + this->shellWindow->setExclusiveZone(zone); + emit this->exclusionZoneChanged(); + } + } +} diff --git a/src/cpp/layershell.hpp b/src/cpp/layershell.hpp index 29375ce4..a7f53c56 100644 --- a/src/cpp/layershell.hpp +++ b/src/cpp/layershell.hpp @@ -42,6 +42,25 @@ public: 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 Q_NAMESPACE; QML_ELEMENT; @@ -131,6 +150,8 @@ class ProxyShellWindow: public ProxyWindowBase { /// > [!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 @@ -172,6 +193,9 @@ public: 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; @@ -195,12 +219,18 @@ signals: void anchorsChanged(); void marginsChanged(); void exclusionZoneChanged(); + void exclusionModeChanged(); void layerChanged(); void keyboardFocusChanged(); +private slots: + void updateExclusionZone(); + private: LayerShellQt::Window* shellWindow = nullptr; bool anchorsInitialized = false; + ExclusionMode::Enum mExclusionMode = ExclusionMode::Normal; + qint32 requestedExclusionZone = 0; // needed to ensure size dosent fuck up when changing layershell attachments // along with setWidth and setHeight overrides