diff --git a/src/x11/panel_window.cpp b/src/x11/panel_window.cpp index ef271b58..57003644 100644 --- a/src/x11/panel_window.cpp +++ b/src/x11/panel_window.cpp @@ -98,6 +98,26 @@ XPanelWindow::XPanelWindow(QObject* parent): ProxyWindowBase(parent) { this, &XPanelWindow::xInit ); + + this->bcExclusiveZone.setBinding([this]() -> qint32 { + switch (this->bExclusionMode.value()) { + case ExclusionMode::Ignore: return 0; + case ExclusionMode::Normal: return this->bExclusiveZone; + case ExclusionMode::Auto: + auto edge = this->bcExclusionEdge.value(); + auto margins = this->bMargins.value(); + + if (edge == Qt::TopEdge || edge == Qt::BottomEdge) { + return this->bImplicitHeight + margins.top + margins.bottom; + } else if (edge == Qt::LeftEdge || edge == Qt::RightEdge) { + return this->bImplicitWidth + margins.left + margins.right; + } else { + return 0; + } + } + }); + + this->bcExclusionEdge.setBinding([this] { return this->bAnchors.value().exclusionEdge(); }); } XPanelWindow::~XPanelWindow() { XPanelStack::instance()->removePanel(this); } @@ -133,7 +153,7 @@ void XPanelWindow::connectWindow() { void XPanelWindow::trySetWidth(qint32 implicitWidth) { // only update the actual size if not blocked by anchors - if (!this->mAnchors.horizontalConstraint()) { + if (!this->bAnchors.value().horizontalConstraint()) { this->ProxyWindowBase::trySetWidth(implicitWidth); this->updateDimensions(); } @@ -141,7 +161,7 @@ void XPanelWindow::trySetWidth(qint32 implicitWidth) { void XPanelWindow::trySetHeight(qint32 implicitHeight) { // only update the actual size if not blocked by anchors - if (!this->mAnchors.verticalConstraint()) { + if (!this->bAnchors.value().verticalConstraint()) { this->ProxyWindowBase::trySetHeight(implicitHeight); this->updateDimensions(); } @@ -152,61 +172,6 @@ void XPanelWindow::setScreen(QuickshellScreenInfo* screen) { this->connectScreen(); } -Anchors XPanelWindow::anchors() const { return this->mAnchors; } - -void XPanelWindow::setAnchors(Anchors anchors) { - if (this->mAnchors == anchors) return; - this->mAnchors = anchors; - this->updateDimensions(); - emit this->anchorsChanged(); -} - -qint32 XPanelWindow::exclusiveZone() const { return this->mExclusiveZone; } - -void XPanelWindow::setExclusiveZone(qint32 exclusiveZone) { - if (this->mExclusiveZone == exclusiveZone) return; - this->mExclusiveZone = exclusiveZone; - this->setExclusionMode(ExclusionMode::Normal); - this->updateStrut(); - emit this->exclusiveZoneChanged(); -} - -ExclusionMode::Enum XPanelWindow::exclusionMode() const { return this->mExclusionMode; } - -void XPanelWindow::setExclusionMode(ExclusionMode::Enum exclusionMode) { - if (this->mExclusionMode == exclusionMode) return; - this->mExclusionMode = exclusionMode; - this->updateStrut(); - emit this->exclusionModeChanged(); -} - -Margins XPanelWindow::margins() const { return this->mMargins; } - -void XPanelWindow::setMargins(Margins margins) { - if (this->mMargins == margins) return; - this->mMargins = margins; - this->updateDimensions(); - emit this->marginsChanged(); -} - -bool XPanelWindow::aboveWindows() const { return this->mAboveWindows; } - -void XPanelWindow::setAboveWindows(bool aboveWindows) { - if (this->mAboveWindows == aboveWindows) return; - this->mAboveWindows = aboveWindows; - this->updateAboveWindows(); - emit this->aboveWindowsChanged(); -} - -bool XPanelWindow::focusable() const { return this->mFocusable; } - -void XPanelWindow::setFocusable(bool focusable) { - if (this->mFocusable == focusable) return; - this->mFocusable = focusable; - this->updateFocusable(); - emit this->focusableChanged(); -} - void XPanelWindow::xInit() { if (this->window == nullptr || this->window->handle() == nullptr) return; this->updateDimensions(); @@ -271,44 +236,42 @@ void XPanelWindow::updateDimensions(bool propagate) { auto screenGeometry = this->mScreen->geometry(); - if (this->mExclusionMode != ExclusionMode::Ignore) { + if (this->bExclusionMode != ExclusionMode::Ignore) { for (auto* panel: XPanelStack::instance()->panels(this)) { // we only care about windows below us if (panel == this) break; // we only care about windows in the same layer - if (panel->mAboveWindows != this->mAboveWindows) continue; + if (panel->bAboveWindows != this->bAboveWindows) continue; if (panel->mScreen != this->mScreen) continue; - int side = -1; - quint32 exclusiveZone = 0; - panel->getExclusion(side, exclusiveZone); - - if (exclusiveZone == 0) continue; - - auto zone = static_cast(exclusiveZone); + auto edge = this->bcExclusionEdge.value(); + auto exclusiveZone = this->bcExclusiveZone.value(); screenGeometry.adjust( - side == 0 ? zone : 0, - side == 2 ? zone : 0, - side == 1 ? -zone : 0, - side == 3 ? -zone : 0 + edge == Qt::LeftEdge ? exclusiveZone : 0, + edge == Qt::TopEdge ? exclusiveZone : 0, + edge == Qt::RightEdge ? -exclusiveZone : 0, + edge == Qt::BottomEdge ? -exclusiveZone : 0 ); } } auto geometry = QRect(); - if (this->mAnchors.horizontalConstraint()) { - geometry.setX(screenGeometry.x() + this->mMargins.left); - geometry.setWidth(screenGeometry.width() - this->mMargins.left - this->mMargins.right); + auto anchors = this->bAnchors.value(); + auto margins = this->bMargins.value(); + + if (anchors.horizontalConstraint()) { + geometry.setX(screenGeometry.x() + margins.left); + geometry.setWidth(screenGeometry.width() - margins.left - margins.right); } else { - if (this->mAnchors.mLeft) { - geometry.setX(screenGeometry.x() + this->mMargins.left); - } else if (this->mAnchors.mRight) { + if (anchors.mLeft) { + geometry.setX(screenGeometry.x() + margins.left); + } else if (anchors.mRight) { geometry.setX( - screenGeometry.x() + screenGeometry.width() - this->implicitWidth() - this->mMargins.right + screenGeometry.x() + screenGeometry.width() - this->implicitWidth() - margins.right ); } else { geometry.setX(screenGeometry.x() + screenGeometry.width() / 2 - this->implicitWidth() / 2); @@ -317,16 +280,15 @@ void XPanelWindow::updateDimensions(bool propagate) { geometry.setWidth(this->implicitWidth()); } - if (this->mAnchors.verticalConstraint()) { - geometry.setY(screenGeometry.y() + this->mMargins.top); - geometry.setHeight(screenGeometry.height() - this->mMargins.top - this->mMargins.bottom); + if (anchors.verticalConstraint()) { + geometry.setY(screenGeometry.y() + margins.top); + geometry.setHeight(screenGeometry.height() - margins.top - margins.bottom); } else { - if (this->mAnchors.mTop) { - geometry.setY(screenGeometry.y() + this->mMargins.top); - } else if (this->mAnchors.mBottom) { + if (anchors.mTop) { + geometry.setY(screenGeometry.y() + margins.top); + } else if (anchors.mBottom) { geometry.setY( - screenGeometry.y() + screenGeometry.height() - this->implicitHeight() - - this->mMargins.bottom + screenGeometry.y() + screenGeometry.height() - this->implicitHeight() - margins.bottom ); } else { geometry.setY(screenGeometry.y() + screenGeometry.height() / 2 - this->implicitHeight() / 2); @@ -355,42 +317,6 @@ void XPanelWindow::updatePanelStack() { } } -void XPanelWindow::getExclusion(int& side, quint32& exclusiveZone) { - if (this->mExclusionMode == ExclusionMode::Ignore) { - exclusiveZone = 0; - return; - } - - auto& anchors = this->mAnchors; - if (anchors.mLeft || anchors.mRight || anchors.mTop || anchors.mBottom) { - if (!anchors.horizontalConstraint() - && (anchors.verticalConstraint() || (!anchors.mTop && !anchors.mBottom))) - { - side = anchors.mLeft ? 0 : anchors.mRight ? 1 : -1; - } else if (!anchors.verticalConstraint() - && (anchors.horizontalConstraint() || (!anchors.mLeft && !anchors.mRight))) - { - side = anchors.mTop ? 2 : anchors.mBottom ? 3 : -1; - } - } - - if (side == -1) return; - - auto autoExclude = this->mExclusionMode == ExclusionMode::Auto; - - if (autoExclude) { - if (side == 0 || side == 1) { - exclusiveZone = - this->implicitWidth() + (side == 0 ? this->mMargins.left : this->mMargins.right); - } else { - exclusiveZone = - this->implicitHeight() + (side == 2 ? this->mMargins.top : this->mMargins.bottom); - } - } else { - exclusiveZone = this->mExclusiveZone; - } -} - // Disable xinerama structs to break multi monitor configurations with bad WMs less. // Usually this results in one monitor at the top left corner of the root window working // perfectly and all others being broken semi randomly. @@ -400,12 +326,10 @@ void XPanelWindow::updateStrut(bool propagate) { if (this->window == nullptr || this->window->handle() == nullptr) return; auto* conn = x11Connection(); - int side = -1; - quint32 exclusiveZone = 0; + auto edge = this->bcExclusionEdge.value(); + auto exclusiveZone = this->bcExclusiveZone.value(); - this->getExclusion(side, exclusiveZone); - - if (side == -1 || this->mExclusionMode == ExclusionMode::Ignore) { + if (edge == 0 || this->bExclusionMode == ExclusionMode::Ignore) { xcb_delete_property(conn, this->window->winId(), XAtom::_NET_WM_STRUT.atom()); xcb_delete_property(conn, this->window->winId(), XAtom::_NET_WM_STRUT_PARTIAL.atom()); return; @@ -413,18 +337,27 @@ void XPanelWindow::updateStrut(bool propagate) { auto rootGeometry = this->window->screen()->virtualGeometry(); auto screenGeometry = this->window->screen()->geometry(); - auto horizontal = side == 0 || side == 1; + auto horizontal = edge == Qt::LeftEdge || edge == Qt::RightEdge; if (XINERAMA_STRUTS) { - switch (side) { - case 0: exclusiveZone += screenGeometry.left(); break; - case 1: exclusiveZone += rootGeometry.right() - screenGeometry.right(); break; - case 2: exclusiveZone += screenGeometry.top(); break; - case 3: exclusiveZone += rootGeometry.bottom() - screenGeometry.bottom(); break; + switch (edge) { + case Qt::LeftEdge: exclusiveZone += screenGeometry.left(); break; + case Qt::RightEdge: exclusiveZone += rootGeometry.right() - screenGeometry.right(); break; + case Qt::TopEdge: exclusiveZone += screenGeometry.top(); break; + case Qt::BottomEdge: exclusiveZone += rootGeometry.bottom() - screenGeometry.bottom(); break; default: break; } } + quint32 side = -1; + + switch (edge) { + case Qt::LeftEdge: side = 0; break; + case Qt::RightEdge: side = 1; break; + case Qt::TopEdge: side = 2; break; + case Qt::BottomEdge: side = 3; break; + } + auto data = std::array(); data[side] = exclusiveZone; @@ -461,13 +394,14 @@ void XPanelWindow::updateStrut(bool propagate) { void XPanelWindow::updateAboveWindows() { if (this->window == nullptr) return; - this->window->setFlag(Qt::WindowStaysOnBottomHint, !this->mAboveWindows); - this->window->setFlag(Qt::WindowStaysOnTopHint, this->mAboveWindows); + auto above = this->bAboveWindows.value(); + this->window->setFlag(Qt::WindowStaysOnBottomHint, !above); + this->window->setFlag(Qt::WindowStaysOnTopHint, above); } void XPanelWindow::updateFocusable() { if (this->window == nullptr) return; - this->window->setFlag(Qt::WindowDoesNotAcceptFocus, !this->mFocusable); + this->window->setFlag(Qt::WindowDoesNotAcceptFocus, !this->bFocusable); } // XPanelInterface diff --git a/src/x11/panel_window.hpp b/src/x11/panel_window.hpp index c6c1de77..b809dc19 100644 --- a/src/x11/panel_window.hpp +++ b/src/x11/panel_window.hpp @@ -1,6 +1,8 @@ #pragma once +#include #include +#include #include #include #include @@ -8,6 +10,7 @@ #include #include "../core/doc.hpp" +#include "../core/util.hpp" #include "../window/panelinterface.hpp" #include "../window/proxywindow.hpp" @@ -51,23 +54,28 @@ public: void setScreen(QuickshellScreenInfo* screen) override; - [[nodiscard]] Anchors anchors() const; - void setAnchors(Anchors anchors); + [[nodiscard]] bool aboveWindows() const { return this->bAboveWindows; } + void setAboveWindows(bool aboveWindows) { this->bAboveWindows = aboveWindows; } - [[nodiscard]] qint32 exclusiveZone() const; - void setExclusiveZone(qint32 exclusiveZone); + [[nodiscard]] Anchors anchors() const { return this->bAnchors; } + void setAnchors(Anchors anchors) { this->bAnchors = anchors; } - [[nodiscard]] ExclusionMode::Enum exclusionMode() const; - void setExclusionMode(ExclusionMode::Enum exclusionMode); + [[nodiscard]] qint32 exclusiveZone() const { return this->bExclusiveZone; } + void setExclusiveZone(qint32 exclusiveZone) { + Qt::beginPropertyUpdateGroup(); + this->bExclusiveZone = exclusiveZone; + this->bExclusionMode = ExclusionMode::Normal; + Qt::endPropertyUpdateGroup(); + } - [[nodiscard]] Margins margins() const; - void setMargins(Margins margins); + [[nodiscard]] ExclusionMode::Enum exclusionMode() const { return this->bExclusionMode; } + void setExclusionMode(ExclusionMode::Enum exclusionMode) { this->bExclusionMode = exclusionMode; } - [[nodiscard]] bool aboveWindows() const; - void setAboveWindows(bool aboveWindows); + [[nodiscard]] Margins margins() const { return this->bMargins; } + void setMargins(Margins margins) { this->bMargins = margins; } - [[nodiscard]] bool focusable() const; - void setFocusable(bool focusable); + [[nodiscard]] bool focusable() const { return this->bFocusable; } + void setFocusable(bool focusable) { this->bFocusable = focusable; } signals: QSDOC_HIDE void anchorsChanged(); @@ -85,24 +93,36 @@ private slots: private: void connectScreen(); - void getExclusion(int& side, quint32& exclusiveZone); void updateStrut(bool propagate = true); + void updateStrutCb() { this->updateStrut(); } void updateAboveWindows(); void updateFocusable(); void updateDimensions(bool propagate = true); + void updateDimensionsCb() { this->updateDimensions(); } QPointer mTrackedScreen = nullptr; - bool mAboveWindows = true; - bool mFocusable = false; - Anchors mAnchors; - Margins mMargins; - qint32 mExclusiveZone = 0; - ExclusionMode::Enum mExclusionMode = ExclusionMode::Auto; EngineGeneration* knownGeneration = nullptr; QRect lastScreenVirtualGeometry; XPanelEventFilter eventFilter; + // clang-format off + Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(XPanelWindow, bool, bAboveWindows, true, &XPanelWindow::aboveWindowsChanged); + Q_OBJECT_BINDABLE_PROPERTY(XPanelWindow, bool, bFocusable, &XPanelWindow::focusableChanged); + Q_OBJECT_BINDABLE_PROPERTY(XPanelWindow, Anchors, bAnchors, &XPanelWindow::anchorsChanged); + Q_OBJECT_BINDABLE_PROPERTY(XPanelWindow, Margins, bMargins, &XPanelWindow::marginsChanged); + Q_OBJECT_BINDABLE_PROPERTY(XPanelWindow, qint32, bExclusiveZone, &XPanelWindow::exclusiveZoneChanged); + Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(XPanelWindow, ExclusionMode::Enum, bExclusionMode, ExclusionMode::Auto, &XPanelWindow::exclusionModeChanged); + Q_OBJECT_BINDABLE_PROPERTY(XPanelWindow, qint32, bcExclusiveZone); + Q_OBJECT_BINDABLE_PROPERTY(XPanelWindow, Qt::Edge, bcExclusionEdge); + + QS_BINDING_SUBSCRIBE_METHOD(XPanelWindow, bAboveWindows, updateAboveWindows, onValueChanged); + QS_BINDING_SUBSCRIBE_METHOD(XPanelWindow, bAnchors, updateDimensionsCb, onValueChanged); + QS_BINDING_SUBSCRIBE_METHOD(XPanelWindow, bMargins, updateDimensionsCb, onValueChanged); + QS_BINDING_SUBSCRIBE_METHOD(XPanelWindow, bcExclusiveZone, updateStrutCb, onValueChanged); + QS_BINDING_SUBSCRIBE_METHOD(XPanelWindow, bFocusable, updateFocusable, onValueChanged); + // clang-format on + friend class XPanelStack; };