forked from quickshell/quickshell
wayland/layershell: refactor layer shell surface integration
In addition to the much needed cleanup: - The bridge/extension type is now directly tied to the QWindow instead of the WlrLayershell object, and is much smaller. - Layer requests are now comitted via polish instead of for each change individually.
This commit is contained in:
parent
6a8284dae3
commit
e0cff677a5
13 changed files with 366 additions and 495 deletions
|
@ -1,7 +1,7 @@
|
|||
qt_add_library(quickshell-wayland-layershell STATIC
|
||||
wlr_layershell.cpp
|
||||
shell_integration.cpp
|
||||
surface.cpp
|
||||
window.cpp
|
||||
)
|
||||
|
||||
qt_add_qml_module(quickshell-wayland-layershell
|
||||
|
|
|
@ -6,16 +6,20 @@
|
|||
|
||||
#include "surface.hpp"
|
||||
|
||||
QSWaylandLayerShellIntegration::QSWaylandLayerShellIntegration()
|
||||
: QtWaylandClient::QWaylandShellIntegrationTemplate<QSWaylandLayerShellIntegration>(4) {}
|
||||
namespace qs::wayland::layershell {
|
||||
|
||||
QSWaylandLayerShellIntegration::~QSWaylandLayerShellIntegration() {
|
||||
LayerShellIntegration::LayerShellIntegration()
|
||||
: QtWaylandClient::QWaylandShellIntegrationTemplate<LayerShellIntegration>(4) {}
|
||||
|
||||
LayerShellIntegration::~LayerShellIntegration() {
|
||||
if (this->isInitialized()) {
|
||||
this->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
QtWaylandClient::QWaylandShellSurface*
|
||||
QSWaylandLayerShellIntegration::createShellSurface(QtWaylandClient::QWaylandWindow* window) {
|
||||
return new QSWaylandLayerSurface(this, window);
|
||||
LayerShellIntegration::createShellSurface(QtWaylandClient::QWaylandWindow* window) {
|
||||
return new LayerSurface(this, window);
|
||||
}
|
||||
|
||||
} // namespace qs::wayland::layershell
|
||||
|
|
|
@ -5,14 +5,18 @@
|
|||
#include <qtclasshelpermacros.h>
|
||||
#include <qwayland-wlr-layer-shell-unstable-v1.h>
|
||||
|
||||
class QSWaylandLayerShellIntegration
|
||||
: public QtWaylandClient::QWaylandShellIntegrationTemplate<QSWaylandLayerShellIntegration>
|
||||
namespace qs::wayland::layershell {
|
||||
|
||||
class LayerShellIntegration
|
||||
: public QtWaylandClient::QWaylandShellIntegrationTemplate<LayerShellIntegration>
|
||||
, public QtWayland::zwlr_layer_shell_v1 {
|
||||
public:
|
||||
QSWaylandLayerShellIntegration();
|
||||
~QSWaylandLayerShellIntegration() override;
|
||||
Q_DISABLE_COPY_MOVE(QSWaylandLayerShellIntegration);
|
||||
LayerShellIntegration();
|
||||
~LayerShellIntegration() override;
|
||||
Q_DISABLE_COPY_MOVE(LayerShellIntegration);
|
||||
|
||||
QtWaylandClient::QWaylandShellSurface* createShellSurface(QtWaylandClient::QWaylandWindow* window
|
||||
) override;
|
||||
};
|
||||
|
||||
} // namespace qs::wayland::layershell
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "surface.hpp"
|
||||
#include <algorithm>
|
||||
#include <any>
|
||||
#include <utility>
|
||||
|
||||
#include <private/qhighdpiscaling_p.h>
|
||||
#include <private/qwaylanddisplay_p.h>
|
||||
|
@ -13,16 +14,20 @@
|
|||
#include <qsize.h>
|
||||
#include <qtversionchecks.h>
|
||||
#include <qtypes.h>
|
||||
#include <qvariant.h>
|
||||
#include <qwayland-wlr-layer-shell-unstable-v1.h>
|
||||
#include <qwindow.h>
|
||||
|
||||
#include "../../window/panelinterface.hpp"
|
||||
#include "shell_integration.hpp"
|
||||
#include "window.hpp"
|
||||
#include "wlr_layershell.hpp"
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 7, 0)
|
||||
#include <qpoint.h>
|
||||
#endif
|
||||
|
||||
namespace qs::wayland::layershell {
|
||||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] QtWayland::zwlr_layer_shell_v1::layer toWaylandLayer(const WlrLayer::Enum& layer
|
||||
|
@ -69,21 +74,72 @@ toWaylandKeyboardFocus(const WlrKeyboardFocus::Enum& focus) noexcept {
|
|||
|
||||
} // namespace
|
||||
|
||||
QSWaylandLayerSurface::QSWaylandLayerSurface(
|
||||
QSWaylandLayerShellIntegration* shell,
|
||||
QtWaylandClient::QWaylandWindow* window
|
||||
)
|
||||
void LayerSurfaceBridge::commitState() {
|
||||
if (this->surface) this->surface->commit();
|
||||
}
|
||||
|
||||
LayerSurfaceBridge* LayerSurfaceBridge::get(QWindow* window) {
|
||||
auto v = window->property("layershell_bridge");
|
||||
|
||||
if (v.canConvert<LayerSurfaceBridge*>()) {
|
||||
return v.value<LayerSurfaceBridge*>();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LayerSurfaceBridge* LayerSurfaceBridge::init(QWindow* window, LayerSurfaceState state) {
|
||||
auto* bridge = LayerSurfaceBridge::get(window);
|
||||
|
||||
if (!bridge) {
|
||||
bridge = new LayerSurfaceBridge(window);
|
||||
window->setProperty("layershell_bridge", QVariant::fromValue(bridge));
|
||||
} else if (!bridge->state.isCompatible(state)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!bridge->surface) {
|
||||
// Qt appears to be resetting the window's screen on creation on some systems. This works around it.
|
||||
auto* screen = window->screen();
|
||||
window->create();
|
||||
window->setScreen(screen);
|
||||
|
||||
auto* waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow*>(window->handle());
|
||||
if (waylandWindow == nullptr) {
|
||||
qWarning() << window << "is not a wayland window. Cannot create layershell surface.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static LayerShellIntegration* layershellIntegration = nullptr; // NOLINT
|
||||
if (layershellIntegration == nullptr) {
|
||||
layershellIntegration = new LayerShellIntegration();
|
||||
if (!layershellIntegration->initialize(waylandWindow->display())) {
|
||||
delete layershellIntegration;
|
||||
layershellIntegration = nullptr;
|
||||
qWarning() << "Failed to initialize layershell integration";
|
||||
}
|
||||
}
|
||||
|
||||
waylandWindow->setShellIntegration(layershellIntegration);
|
||||
}
|
||||
|
||||
bridge->state = std::move(state);
|
||||
bridge->commitState();
|
||||
|
||||
return bridge;
|
||||
}
|
||||
|
||||
LayerSurface::LayerSurface(LayerShellIntegration* shell, QtWaylandClient::QWaylandWindow* window)
|
||||
: QtWaylandClient::QWaylandShellSurface(window) {
|
||||
|
||||
auto* qwindow = window->window();
|
||||
this->ext = LayershellWindowExtension::get(qwindow);
|
||||
|
||||
if (this->ext == nullptr) {
|
||||
qFatal() << "QSWaylandLayerSurface created with null LayershellWindowExtension";
|
||||
}
|
||||
this->bridge = LayerSurfaceBridge::get(qwindow);
|
||||
if (this->bridge == nullptr) qFatal() << "LayerSurface created with null bridge";
|
||||
const auto& s = this->bridge->state;
|
||||
|
||||
wl_output* output = nullptr; // NOLINT (include)
|
||||
if (this->ext->useWindowScreen) {
|
||||
if (!s.compositorPickesScreen) {
|
||||
auto* waylandScreen =
|
||||
dynamic_cast<QtWaylandClient::QWaylandScreen*>(qwindow->screen()->handle());
|
||||
|
||||
|
@ -98,36 +154,28 @@ QSWaylandLayerSurface::QSWaylandLayerSurface(
|
|||
this->init(shell->get_layer_surface(
|
||||
window->waylandSurface()->object(),
|
||||
output,
|
||||
toWaylandLayer(this->ext->mLayer),
|
||||
this->ext->mNamespace
|
||||
toWaylandLayer(s.layer),
|
||||
s.mNamespace
|
||||
));
|
||||
|
||||
this->updateAnchors();
|
||||
this->updateLayer();
|
||||
this->updateMargins();
|
||||
this->updateExclusiveZone();
|
||||
this->updateKeyboardFocus();
|
||||
|
||||
// new updates will be sent from the extension
|
||||
this->ext->surface = this;
|
||||
|
||||
auto size = constrainedSize(this->ext->mAnchors, window->surfaceSize());
|
||||
auto size = constrainedSize(s.anchors, QHighDpi::toNativePixels(s.implicitSize, qwindow));
|
||||
this->set_size(size.width(), size.height());
|
||||
this->set_anchor(toWaylandAnchors(s.anchors));
|
||||
this->set_margin(
|
||||
QHighDpi::toNativePixels(s.margins.mTop, qwindow),
|
||||
QHighDpi::toNativePixels(s.margins.mRight, qwindow),
|
||||
QHighDpi::toNativePixels(s.margins.mBottom, qwindow),
|
||||
QHighDpi::toNativePixels(s.margins.mLeft, qwindow)
|
||||
);
|
||||
this->set_exclusive_zone(QHighDpi::toNativePixels(s.exclusiveZone, qwindow));
|
||||
this->set_keyboard_interactivity(toWaylandKeyboardFocus(s.keyboardFocus));
|
||||
|
||||
this->bridge->surface = this;
|
||||
}
|
||||
|
||||
QSWaylandLayerSurface::~QSWaylandLayerSurface() {
|
||||
if (this->ext != nullptr) {
|
||||
this->ext->surface = nullptr;
|
||||
}
|
||||
LayerSurface::~LayerSurface() { this->destroy(); }
|
||||
|
||||
this->destroy();
|
||||
}
|
||||
|
||||
void QSWaylandLayerSurface::zwlr_layer_surface_v1_configure(
|
||||
quint32 serial,
|
||||
quint32 width,
|
||||
quint32 height
|
||||
) {
|
||||
void LayerSurface::zwlr_layer_surface_v1_configure(quint32 serial, quint32 width, quint32 height) {
|
||||
this->ack_configure(serial);
|
||||
|
||||
this->size = QSize(static_cast<qint32>(width), static_cast<qint32>(height));
|
||||
|
@ -146,51 +194,53 @@ void QSWaylandLayerSurface::zwlr_layer_surface_v1_configure(
|
|||
}
|
||||
}
|
||||
|
||||
void QSWaylandLayerSurface::zwlr_layer_surface_v1_closed() { this->window()->window()->close(); }
|
||||
void LayerSurface::zwlr_layer_surface_v1_closed() { this->window()->window()->close(); }
|
||||
|
||||
bool QSWaylandLayerSurface::isExposed() const { return this->configured; }
|
||||
bool LayerSurface::isExposed() const { return this->configured; }
|
||||
|
||||
void QSWaylandLayerSurface::applyConfigure() {
|
||||
this->window()->resizeFromApplyConfigure(this->size);
|
||||
void LayerSurface::applyConfigure() { this->window()->resizeFromApplyConfigure(this->size); }
|
||||
|
||||
QWindow* LayerSurface::qwindow() { return this->window()->window(); }
|
||||
|
||||
void LayerSurface::commit() {
|
||||
const auto& p = this->bridge->state;
|
||||
auto& c = this->committed;
|
||||
|
||||
if (p.implicitSize != c.implicitSize || p.anchors != c.anchors) {
|
||||
auto size =
|
||||
constrainedSize(p.anchors, QHighDpi::toNativePixels(p.implicitSize, this->qwindow()));
|
||||
this->set_size(size.width(), size.height());
|
||||
}
|
||||
|
||||
if (p.anchors != c.anchors) {
|
||||
this->set_anchor(toWaylandAnchors(p.anchors));
|
||||
}
|
||||
|
||||
if (p.margins != c.margins) {
|
||||
this->set_margin(
|
||||
QHighDpi::toNativePixels(p.margins.mTop, this->qwindow()),
|
||||
QHighDpi::toNativePixels(p.margins.mRight, this->qwindow()),
|
||||
QHighDpi::toNativePixels(p.margins.mBottom, this->qwindow()),
|
||||
QHighDpi::toNativePixels(p.margins.mLeft, this->qwindow())
|
||||
);
|
||||
}
|
||||
|
||||
if (p.layer != c.layer) {
|
||||
this->set_layer(p.layer);
|
||||
}
|
||||
|
||||
if (p.exclusiveZone != c.exclusiveZone) {
|
||||
this->set_exclusive_zone(QHighDpi::toNativePixels(p.exclusiveZone, this->qwindow()));
|
||||
}
|
||||
|
||||
if (p.keyboardFocus != c.keyboardFocus) {
|
||||
this->set_keyboard_interactivity(toWaylandKeyboardFocus(p.keyboardFocus));
|
||||
}
|
||||
|
||||
c = p;
|
||||
}
|
||||
|
||||
void QSWaylandLayerSurface::setWindowGeometry(const QRect& geometry) {
|
||||
if (this->ext == nullptr) return;
|
||||
auto size = constrainedSize(this->ext->mAnchors, geometry.size());
|
||||
this->set_size(size.width(), size.height());
|
||||
}
|
||||
|
||||
QWindow* QSWaylandLayerSurface::qwindow() { return this->window()->window(); }
|
||||
|
||||
void QSWaylandLayerSurface::updateLayer() {
|
||||
this->set_layer(toWaylandLayer(this->ext->mLayer));
|
||||
this->window()->waylandSurface()->commit();
|
||||
}
|
||||
|
||||
void QSWaylandLayerSurface::updateAnchors() {
|
||||
this->set_anchor(toWaylandAnchors(this->ext->mAnchors));
|
||||
this->setWindowGeometry(this->window()->windowContentGeometry());
|
||||
this->window()->waylandSurface()->commit();
|
||||
}
|
||||
|
||||
void QSWaylandLayerSurface::updateMargins() {
|
||||
auto& margins = this->ext->mMargins;
|
||||
this->set_margin(margins.mTop, margins.mRight, margins.mBottom, margins.mLeft);
|
||||
this->window()->waylandSurface()->commit();
|
||||
}
|
||||
|
||||
void QSWaylandLayerSurface::updateExclusiveZone() {
|
||||
auto nativeZone = QHighDpi::toNativePixels(this->ext->mExclusiveZone, this->window()->window());
|
||||
this->set_exclusive_zone(nativeZone);
|
||||
this->window()->waylandSurface()->commit();
|
||||
}
|
||||
|
||||
void QSWaylandLayerSurface::updateKeyboardFocus() {
|
||||
this->set_keyboard_interactivity(toWaylandKeyboardFocus(this->ext->mKeyboardFocus));
|
||||
this->window()->waylandSurface()->commit();
|
||||
}
|
||||
|
||||
void QSWaylandLayerSurface::attachPopup(QtWaylandClient::QWaylandShellSurface* popup) {
|
||||
void LayerSurface::attachPopup(QtWaylandClient::QWaylandShellSurface* popup) {
|
||||
std::any role = popup->surfaceRole();
|
||||
|
||||
if (auto* popupRole = std::any_cast<::xdg_popup*>(&role)) { // NOLINT
|
||||
|
@ -200,3 +250,5 @@ void QSWaylandLayerSurface::attachPopup(QtWaylandClient::QWaylandShellSurface* p
|
|||
<< "as the popup is not an xdg_popup.";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace qs::wayland::layershell
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include <private/qwaylandshellsurface_p.h>
|
||||
#include <private/qwaylandwindow_p.h>
|
||||
#include <qobject.h>
|
||||
#include <qsize.h>
|
||||
#include <qtclasshelpermacros.h>
|
||||
#include <qtwaylandclientexports.h>
|
||||
#include <qtypes.h>
|
||||
|
@ -9,40 +11,76 @@
|
|||
#include <qwindow.h>
|
||||
|
||||
#include "shell_integration.hpp"
|
||||
#include "window.hpp"
|
||||
#include "wlr_layershell.hpp"
|
||||
|
||||
class QSWaylandLayerSurface
|
||||
namespace qs::wayland::layershell {
|
||||
|
||||
struct LayerSurfaceState {
|
||||
QSize implicitSize;
|
||||
Anchors anchors;
|
||||
Margins margins;
|
||||
WlrLayer::Enum layer = WlrLayer::Top;
|
||||
qint32 exclusiveZone = 0;
|
||||
WlrKeyboardFocus::Enum keyboardFocus = WlrKeyboardFocus::None;
|
||||
|
||||
bool compositorPickesScreen = true;
|
||||
QString mNamespace = "quickshell";
|
||||
|
||||
[[nodiscard]] bool isCompatible(const LayerSurfaceState& other) const {
|
||||
return other.mNamespace == this->mNamespace;
|
||||
}
|
||||
};
|
||||
|
||||
class LayerSurface;
|
||||
|
||||
class LayerSurfaceBridge: public QObject {
|
||||
public:
|
||||
LayerSurfaceState state;
|
||||
|
||||
void commitState();
|
||||
|
||||
// Returns a bridge if attached, otherwise nullptr.
|
||||
static LayerSurfaceBridge* get(QWindow* window);
|
||||
|
||||
// Creates or reuses a bridge on the given window and returns if it compatible, otherwise nullptr.
|
||||
static LayerSurfaceBridge* init(QWindow* window, LayerSurfaceState state);
|
||||
|
||||
private:
|
||||
explicit LayerSurfaceBridge(QWindow* parent): QObject(parent) {}
|
||||
|
||||
LayerSurface* surface = nullptr;
|
||||
|
||||
friend class LayerSurface;
|
||||
};
|
||||
|
||||
class LayerSurface
|
||||
: public QtWaylandClient::QWaylandShellSurface
|
||||
, public QtWayland::zwlr_layer_surface_v1 {
|
||||
public:
|
||||
QSWaylandLayerSurface(
|
||||
QSWaylandLayerShellIntegration* shell,
|
||||
QtWaylandClient::QWaylandWindow* window
|
||||
);
|
||||
LayerSurface(LayerShellIntegration* shell, QtWaylandClient::QWaylandWindow* window);
|
||||
|
||||
~QSWaylandLayerSurface() override;
|
||||
Q_DISABLE_COPY_MOVE(QSWaylandLayerSurface);
|
||||
~LayerSurface() override;
|
||||
Q_DISABLE_COPY_MOVE(LayerSurface);
|
||||
|
||||
[[nodiscard]] bool isExposed() const override;
|
||||
void applyConfigure() override;
|
||||
void setWindowGeometry(const QRect& geometry) override;
|
||||
void setWindowGeometry(const QRect& /*geometry*/) override {}
|
||||
|
||||
void attachPopup(QtWaylandClient::QWaylandShellSurface* popup) override;
|
||||
|
||||
void commit();
|
||||
|
||||
private:
|
||||
void zwlr_layer_surface_v1_configure(quint32 serial, quint32 width, quint32 height) override;
|
||||
void zwlr_layer_surface_v1_closed() override;
|
||||
|
||||
QWindow* qwindow();
|
||||
void updateLayer();
|
||||
void updateAnchors();
|
||||
void updateMargins();
|
||||
void updateExclusiveZone();
|
||||
void updateKeyboardFocus();
|
||||
|
||||
LayershellWindowExtension* ext;
|
||||
QSize size;
|
||||
LayerSurfaceBridge* bridge;
|
||||
bool configured = false;
|
||||
QSize size;
|
||||
|
||||
friend class LayershellWindowExtension;
|
||||
LayerSurfaceState committed;
|
||||
};
|
||||
|
||||
} // namespace qs::wayland::layershell
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
#include "window.hpp"
|
||||
#include <utility>
|
||||
|
||||
#include <private/qwaylandwindow_p.h>
|
||||
#include <qlogging.h>
|
||||
#include <qobject.h>
|
||||
#include <qtmetamacros.h>
|
||||
#include <qtypes.h>
|
||||
#include <qvariant.h>
|
||||
#include <qwindow.h>
|
||||
|
||||
#include "../../window/panelinterface.hpp"
|
||||
#include "shell_integration.hpp"
|
||||
#include "surface.hpp"
|
||||
|
||||
LayershellWindowExtension::~LayershellWindowExtension() {
|
||||
if (this->surface != nullptr) {
|
||||
this->surface->ext = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
LayershellWindowExtension* LayershellWindowExtension::get(QWindow* window) {
|
||||
auto v = window->property("layershell_ext");
|
||||
|
||||
if (v.canConvert<LayershellWindowExtension*>()) {
|
||||
return v.value<LayershellWindowExtension*>();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool LayershellWindowExtension::attach(QWindow* window) {
|
||||
if (this->surface != nullptr)
|
||||
qFatal() << "Cannot change the attached window of a LayershellWindowExtension";
|
||||
|
||||
auto* current = LayershellWindowExtension::get(window);
|
||||
|
||||
bool hasSurface = false;
|
||||
|
||||
if (current != nullptr) {
|
||||
if (current->mNamespace != this->mNamespace) return false;
|
||||
|
||||
if (current->surface != nullptr) {
|
||||
if (current->surface->qwindow()->screen() != window->screen()) return false;
|
||||
this->surface = current->surface;
|
||||
|
||||
// update window with current settings, leveraging old extension's cached values
|
||||
current->setAnchors(this->mAnchors);
|
||||
current->setMargins(this->mMargins);
|
||||
current->setExclusiveZone(this->mExclusiveZone);
|
||||
current->setLayer(this->mLayer);
|
||||
current->setKeyboardFocus(this->mKeyboardFocus);
|
||||
|
||||
this->surface->ext = this;
|
||||
current->surface = nullptr;
|
||||
current->deleteLater();
|
||||
|
||||
hasSurface = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasSurface) {
|
||||
// Qt appears to be resetting the window's screen on creation on some systems. This works around it.
|
||||
auto* screen = window->screen();
|
||||
window->create();
|
||||
window->setScreen(screen);
|
||||
|
||||
auto* waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow*>(window->handle());
|
||||
if (waylandWindow == nullptr) {
|
||||
qWarning() << window << "is not a wayland window. Cannot create layershell surface.";
|
||||
return false;
|
||||
}
|
||||
|
||||
static QSWaylandLayerShellIntegration* layershellIntegration = nullptr; // NOLINT
|
||||
if (layershellIntegration == nullptr) {
|
||||
layershellIntegration = new QSWaylandLayerShellIntegration();
|
||||
if (!layershellIntegration->initialize(waylandWindow->display())) {
|
||||
delete layershellIntegration;
|
||||
layershellIntegration = nullptr;
|
||||
qWarning() << "Failed to initialize layershell integration";
|
||||
}
|
||||
}
|
||||
|
||||
waylandWindow->setShellIntegration(layershellIntegration);
|
||||
}
|
||||
|
||||
window->setProperty("layershell_ext", QVariant::fromValue(this));
|
||||
return true;
|
||||
}
|
||||
|
||||
void LayershellWindowExtension::setAnchors(Anchors anchors) {
|
||||
if (anchors != this->mAnchors) {
|
||||
this->mAnchors = anchors;
|
||||
if (this->surface != nullptr) this->surface->updateAnchors();
|
||||
emit this->anchorsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Anchors LayershellWindowExtension::anchors() const { return this->mAnchors; }
|
||||
|
||||
void LayershellWindowExtension::setMargins(Margins margins) {
|
||||
if (margins != this->mMargins) {
|
||||
this->mMargins = margins;
|
||||
if (this->surface != nullptr) this->surface->updateMargins();
|
||||
emit this->marginsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Margins LayershellWindowExtension::margins() const { return this->mMargins; }
|
||||
|
||||
void LayershellWindowExtension::setExclusiveZone(qint32 exclusiveZone) {
|
||||
if (exclusiveZone != this->mExclusiveZone) {
|
||||
this->mExclusiveZone = exclusiveZone;
|
||||
if (this->surface != nullptr) this->surface->updateExclusiveZone();
|
||||
emit this->exclusiveZoneChanged();
|
||||
}
|
||||
}
|
||||
|
||||
qint32 LayershellWindowExtension::exclusiveZone() const { return this->mExclusiveZone; }
|
||||
|
||||
void LayershellWindowExtension::setLayer(WlrLayer::Enum layer) {
|
||||
if (layer != this->mLayer) {
|
||||
this->mLayer = layer;
|
||||
if (this->surface != nullptr) this->surface->updateLayer();
|
||||
emit this->layerChanged();
|
||||
}
|
||||
}
|
||||
|
||||
WlrLayer::Enum LayershellWindowExtension::layer() const { return this->mLayer; }
|
||||
|
||||
void LayershellWindowExtension::setKeyboardFocus(WlrKeyboardFocus::Enum focus) {
|
||||
if (focus != this->mKeyboardFocus) {
|
||||
this->mKeyboardFocus = focus;
|
||||
if (this->surface != nullptr) this->surface->updateKeyboardFocus();
|
||||
emit this->keyboardFocusChanged();
|
||||
}
|
||||
}
|
||||
|
||||
WlrKeyboardFocus::Enum LayershellWindowExtension::keyboardFocus() const {
|
||||
return this->mKeyboardFocus;
|
||||
}
|
||||
|
||||
void LayershellWindowExtension::setUseWindowScreen(bool value) {
|
||||
this->useWindowScreen = value; // has no effect post configure
|
||||
}
|
||||
|
||||
void LayershellWindowExtension::setNamespace(QString ns) {
|
||||
if (!this->isConfigured()) this->mNamespace = std::move(ns);
|
||||
}
|
||||
|
||||
QString LayershellWindowExtension::ns() const { return this->mNamespace; }
|
||||
|
||||
bool LayershellWindowExtension::isConfigured() const { return this->surface != nullptr; }
|
|
@ -1,118 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <qobject.h>
|
||||
#include <qscreen.h>
|
||||
#include <qtclasshelpermacros.h>
|
||||
#include <qtmetamacros.h>
|
||||
#include <qtypes.h>
|
||||
#include <qwindow.h>
|
||||
|
||||
#include "../../window/panelinterface.hpp"
|
||||
|
||||
///! WlrLayershell layer.
|
||||
/// See @@WlrLayershell.layer.
|
||||
namespace WlrLayer { // NOLINT
|
||||
Q_NAMESPACE;
|
||||
QML_ELEMENT;
|
||||
|
||||
enum Enum : quint8 {
|
||||
/// Below bottom
|
||||
Background = 0,
|
||||
/// Above background, usually below windows
|
||||
Bottom = 1,
|
||||
/// Commonly used for panels, app launchers, and docks.
|
||||
/// Usually renders over normal windows and below fullscreen windows.
|
||||
Top = 2,
|
||||
/// Usually renders over fullscreen windows
|
||||
Overlay = 3,
|
||||
};
|
||||
Q_ENUM_NS(Enum);
|
||||
|
||||
} // namespace WlrLayer
|
||||
|
||||
///! WlrLayershell keyboard focus mode
|
||||
/// See @@WlrLayershell.keyboardFocus.
|
||||
namespace WlrKeyboardFocus { // NOLINT
|
||||
Q_NAMESPACE;
|
||||
QML_ELEMENT;
|
||||
|
||||
enum Enum : quint8 {
|
||||
/// No keyboard input will be accepted.
|
||||
None = 0,
|
||||
/// Exclusive access to the keyboard, locking out all other windows.
|
||||
///
|
||||
/// > [!WARNING] You **CANNOT** use this to make a secure lock screen.
|
||||
/// >
|
||||
/// > If you want to make a lock screen, use @@WlSessionLock.
|
||||
Exclusive = 1,
|
||||
/// Access to the keyboard as determined by the operating system.
|
||||
///
|
||||
/// > [!WARNING] On some systems, `OnDemand` may cause the shell window to
|
||||
/// > retain focus over another window unexpectedly.
|
||||
/// > You should try `None` if you experience issues.
|
||||
OnDemand = 2,
|
||||
};
|
||||
Q_ENUM_NS(Enum);
|
||||
|
||||
} // namespace WlrKeyboardFocus
|
||||
|
||||
class QSWaylandLayerSurface;
|
||||
|
||||
class LayershellWindowExtension: public QObject {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
LayershellWindowExtension(QObject* parent = nullptr): QObject(parent) {}
|
||||
~LayershellWindowExtension() override;
|
||||
Q_DISABLE_COPY_MOVE(LayershellWindowExtension);
|
||||
|
||||
// returns the layershell extension if attached, otherwise nullptr
|
||||
static LayershellWindowExtension* get(QWindow* window);
|
||||
|
||||
// Attach this layershell extension to the given window.
|
||||
// The extension is reparented to the window and replaces any existing layershell extension.
|
||||
// Returns false if the window cannot be used.
|
||||
bool attach(QWindow* window);
|
||||
|
||||
void setAnchors(Anchors anchors);
|
||||
[[nodiscard]] Anchors anchors() const;
|
||||
|
||||
void setMargins(Margins margins);
|
||||
[[nodiscard]] Margins margins() const;
|
||||
|
||||
void setExclusiveZone(qint32 exclusiveZone);
|
||||
[[nodiscard]] qint32 exclusiveZone() const;
|
||||
|
||||
void setLayer(WlrLayer::Enum layer);
|
||||
[[nodiscard]] WlrLayer::Enum layer() const;
|
||||
|
||||
void setKeyboardFocus(WlrKeyboardFocus::Enum focus);
|
||||
[[nodiscard]] WlrKeyboardFocus::Enum keyboardFocus() const;
|
||||
|
||||
// no effect if configured
|
||||
void setUseWindowScreen(bool value);
|
||||
void setNamespace(QString ns);
|
||||
[[nodiscard]] QString ns() const;
|
||||
[[nodiscard]] bool isConfigured() const;
|
||||
|
||||
signals:
|
||||
void anchorsChanged();
|
||||
void marginsChanged();
|
||||
void exclusiveZoneChanged();
|
||||
void layerChanged();
|
||||
void keyboardFocusChanged();
|
||||
|
||||
private:
|
||||
// if configured the screen cannot be changed
|
||||
QSWaylandLayerSurface* surface = nullptr;
|
||||
|
||||
bool useWindowScreen = false;
|
||||
Anchors mAnchors;
|
||||
Margins mMargins;
|
||||
qint32 mExclusiveZone = 0;
|
||||
WlrLayer::Enum mLayer = WlrLayer::Top;
|
||||
QString mNamespace = "quickshell";
|
||||
WlrKeyboardFocus::Enum mKeyboardFocus = WlrKeyboardFocus::None;
|
||||
|
||||
friend class QSWaylandLayerSurface;
|
||||
};
|
212
src/wayland/wlr_layershell/wlr_layershell.cpp
Normal file
212
src/wayland/wlr_layershell/wlr_layershell.cpp
Normal file
|
@ -0,0 +1,212 @@
|
|||
#include "wlr_layershell.hpp"
|
||||
|
||||
#include <qlogging.h>
|
||||
#include <qobject.h>
|
||||
#include <qqmllist.h>
|
||||
#include <qquickitem.h>
|
||||
#include <qquickwindow.h>
|
||||
#include <qtypes.h>
|
||||
|
||||
#include "../../core/qmlscreen.hpp"
|
||||
#include "../../window/panelinterface.hpp"
|
||||
#include "../../window/proxywindow.hpp"
|
||||
#include "surface.hpp"
|
||||
|
||||
namespace qs::wayland::layershell {
|
||||
|
||||
WlrLayershell::WlrLayershell(QObject* parent): ProxyWindowBase(parent) {}
|
||||
|
||||
ProxiedWindow* WlrLayershell::retrieveWindow(QObject* oldInstance) {
|
||||
auto* old = qobject_cast<WlrLayershell*>(oldInstance);
|
||||
auto* window = old == nullptr ? nullptr : old->disownWindow();
|
||||
|
||||
if (window != nullptr) {
|
||||
this->bridge = LayerSurfaceBridge::init(window, this->computeState());
|
||||
if (this->bridge) {
|
||||
return window;
|
||||
} else {
|
||||
window->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
return this->createQQuickWindow();
|
||||
}
|
||||
|
||||
ProxiedWindow* WlrLayershell::createQQuickWindow() {
|
||||
auto* window = this->ProxyWindowBase::createQQuickWindow();
|
||||
|
||||
this->bridge = LayerSurfaceBridge::init(window, this->computeState());
|
||||
if (!this->bridge) {
|
||||
qWarning() << "Could not attach Layershell extension to new QQuickWindow. Layer will not "
|
||||
"behave correctly.";
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
void WlrLayershell::connectWindow() {
|
||||
this->ProxyWindowBase::connectWindow();
|
||||
|
||||
QObject::connect(this, &ProxyWindowBase::widthChanged, this, &WlrLayershell::updateAutoExclusion);
|
||||
|
||||
QObject::connect(
|
||||
this,
|
||||
&ProxyWindowBase::heightChanged,
|
||||
this,
|
||||
&WlrLayershell::updateAutoExclusion
|
||||
);
|
||||
|
||||
this->updateAutoExclusion();
|
||||
}
|
||||
|
||||
bool WlrLayershell::deleteOnInvisible() const {
|
||||
// Qt windows behave weirdly when geometry is modified and setVisible(false)
|
||||
// is subsequently called in the same frame.
|
||||
// It will attach buffers to the wayland surface unconditionally before
|
||||
// the surface recieves a configure event, causing a protocol error.
|
||||
// To remedy this we forcibly disallow window reuse.
|
||||
return true;
|
||||
}
|
||||
|
||||
void WlrLayershell::onPolished() {
|
||||
if (this->bridge) {
|
||||
this->bridge->state = this->computeState();
|
||||
this->bridge->commitState();
|
||||
}
|
||||
|
||||
this->ProxyWindowBase::onPolished();
|
||||
}
|
||||
|
||||
void WlrLayershell::trySetWidth(qint32 /*implicitWidth*/) { this->onStateChanged(); }
|
||||
void WlrLayershell::trySetHeight(qint32 /*implicitHeight*/) { this->onStateChanged(); }
|
||||
|
||||
void WlrLayershell::setScreen(QuickshellScreenInfo* screen) {
|
||||
this->compositorPicksScreen = screen == nullptr;
|
||||
this->ProxyWindowBase::setScreen(screen);
|
||||
}
|
||||
|
||||
void WlrLayershell::onStateChanged() { this->schedulePolish(); }
|
||||
|
||||
bool WlrLayershell::aboveWindows() const { return this->layer() > WlrLayer::Bottom; }
|
||||
|
||||
void WlrLayershell::setAboveWindows(bool aboveWindows) {
|
||||
this->setLayer(aboveWindows ? WlrLayer::Top : WlrLayer::Bottom);
|
||||
}
|
||||
|
||||
bool WlrLayershell::focusable() const { return this->keyboardFocus() != WlrKeyboardFocus::None; }
|
||||
|
||||
void WlrLayershell::setFocusable(bool focusable) {
|
||||
this->setKeyboardFocus(focusable ? WlrKeyboardFocus::OnDemand : WlrKeyboardFocus::None);
|
||||
}
|
||||
|
||||
LayerSurfaceState WlrLayershell::computeState() const {
|
||||
return LayerSurfaceState {
|
||||
.implicitSize = QSize(this->implicitWidth(), this->implicitHeight()),
|
||||
.anchors = this->bAnchors,
|
||||
.margins = this->bMargins,
|
||||
.layer = this->bLayer,
|
||||
.exclusiveZone = this->bcExclusiveZone,
|
||||
.keyboardFocus = this->bKeyboardFocus,
|
||||
.compositorPickesScreen = this->compositorPicksScreen,
|
||||
.mNamespace = this->bNamespace,
|
||||
};
|
||||
}
|
||||
|
||||
qint32 WlrLayershell::computeExclusiveZone() const {
|
||||
switch (this->bExclusionMode.value()) {
|
||||
case ExclusionMode::Ignore: return -1;
|
||||
case ExclusionMode::Normal: return this->bExclusiveZone;
|
||||
case ExclusionMode::Auto:
|
||||
const auto anchors = this->bAnchors.value();
|
||||
|
||||
if (anchors.horizontalConstraint()) return this->height();
|
||||
else if (anchors.verticalConstraint()) return this->width();
|
||||
else return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void WlrLayershell::updateAutoExclusion() { this->bcExclusiveZone.notify(); }
|
||||
|
||||
WlrLayershell* WlrLayershell::qmlAttachedProperties(QObject* object) {
|
||||
if (auto* obj = qobject_cast<WaylandPanelInterface*>(object)) {
|
||||
return obj->layer;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// WaylandPanelInterface
|
||||
|
||||
WaylandPanelInterface::WaylandPanelInterface(QObject* parent)
|
||||
: PanelWindowInterface(parent)
|
||||
, layer(new WlrLayershell(this)) {
|
||||
|
||||
// clang-format off
|
||||
QObject::connect(this->layer, &ProxyWindowBase::windowConnected, this, &WaylandPanelInterface::windowConnected);
|
||||
QObject::connect(this->layer, &ProxyWindowBase::visibleChanged, this, &WaylandPanelInterface::visibleChanged);
|
||||
QObject::connect(this->layer, &ProxyWindowBase::backerVisibilityChanged, this, &WaylandPanelInterface::backingWindowVisibleChanged);
|
||||
QObject::connect(this->layer, &ProxyWindowBase::implicitHeightChanged, this, &WaylandPanelInterface::implicitHeightChanged);
|
||||
QObject::connect(this->layer, &ProxyWindowBase::implicitWidthChanged, this, &WaylandPanelInterface::implicitWidthChanged);
|
||||
QObject::connect(this->layer, &ProxyWindowBase::heightChanged, this, &WaylandPanelInterface::heightChanged);
|
||||
QObject::connect(this->layer, &ProxyWindowBase::widthChanged, this, &WaylandPanelInterface::widthChanged);
|
||||
QObject::connect(this->layer, &ProxyWindowBase::devicePixelRatioChanged, this, &WaylandPanelInterface::devicePixelRatioChanged);
|
||||
QObject::connect(this->layer, &ProxyWindowBase::screenChanged, this, &WaylandPanelInterface::screenChanged);
|
||||
QObject::connect(this->layer, &ProxyWindowBase::windowTransformChanged, this, &WaylandPanelInterface::windowTransformChanged);
|
||||
QObject::connect(this->layer, &ProxyWindowBase::colorChanged, this, &WaylandPanelInterface::colorChanged);
|
||||
QObject::connect(this->layer, &ProxyWindowBase::maskChanged, this, &WaylandPanelInterface::maskChanged);
|
||||
QObject::connect(this->layer, &ProxyWindowBase::surfaceFormatChanged, this, &WaylandPanelInterface::surfaceFormatChanged);
|
||||
|
||||
// panel specific
|
||||
QObject::connect(this->layer, &WlrLayershell::anchorsChanged, this, &WaylandPanelInterface::anchorsChanged);
|
||||
QObject::connect(this->layer, &WlrLayershell::marginsChanged, this, &WaylandPanelInterface::marginsChanged);
|
||||
QObject::connect(this->layer, &WlrLayershell::exclusiveZoneChanged, this, &WaylandPanelInterface::exclusiveZoneChanged);
|
||||
QObject::connect(this->layer, &WlrLayershell::exclusionModeChanged, this, &WaylandPanelInterface::exclusionModeChanged);
|
||||
QObject::connect(this->layer, &WlrLayershell::layerChanged, this, &WaylandPanelInterface::aboveWindowsChanged);
|
||||
QObject::connect(this->layer, &WlrLayershell::keyboardFocusChanged, this, &WaylandPanelInterface::focusableChanged);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void WaylandPanelInterface::onReload(QObject* oldInstance) {
|
||||
QQmlEngine::setContextForObject(this->layer, QQmlEngine::contextForObject(this));
|
||||
|
||||
auto* old = qobject_cast<WaylandPanelInterface*>(oldInstance);
|
||||
this->layer->reload(old != nullptr ? old->layer : nullptr);
|
||||
}
|
||||
|
||||
QQmlListProperty<QObject> WaylandPanelInterface::data() { return this->layer->data(); }
|
||||
ProxyWindowBase* WaylandPanelInterface::proxyWindow() const { return this->layer; }
|
||||
QQuickItem* WaylandPanelInterface::contentItem() const { return this->layer->contentItem(); }
|
||||
|
||||
bool WaylandPanelInterface::isBackingWindowVisible() const {
|
||||
return this->layer->isVisibleDirect();
|
||||
}
|
||||
|
||||
qreal WaylandPanelInterface::devicePixelRatio() const { return this->layer->devicePixelRatio(); }
|
||||
|
||||
// NOLINTBEGIN
|
||||
#define proxyPair(type, get, set) \
|
||||
type WaylandPanelInterface::get() const { return this->layer->get(); } \
|
||||
void WaylandPanelInterface::set(type value) { this->layer->set(value); }
|
||||
|
||||
proxyPair(bool, isVisible, setVisible);
|
||||
proxyPair(qint32, implicitWidth, setImplicitWidth);
|
||||
proxyPair(qint32, implicitHeight, setImplicitHeight);
|
||||
proxyPair(qint32, width, setWidth);
|
||||
proxyPair(qint32, height, setHeight);
|
||||
proxyPair(QuickshellScreenInfo*, screen, setScreen);
|
||||
proxyPair(QColor, color, setColor);
|
||||
proxyPair(PendingRegion*, mask, setMask);
|
||||
proxyPair(QsSurfaceFormat, surfaceFormat, setSurfaceFormat);
|
||||
|
||||
// panel specific
|
||||
proxyPair(Anchors, anchors, setAnchors);
|
||||
proxyPair(Margins, margins, setMargins);
|
||||
proxyPair(qint32, exclusiveZone, setExclusiveZone);
|
||||
proxyPair(ExclusionMode::Enum, exclusionMode, setExclusionMode);
|
||||
proxyPair(bool, focusable, setFocusable);
|
||||
proxyPair(bool, aboveWindows, setAboveWindows);
|
||||
|
||||
#undef proxyPair
|
||||
// NOLINTEND
|
||||
|
||||
} // namespace qs::wayland::layershell
|
277
src/wayland/wlr_layershell/wlr_layershell.hpp
Normal file
277
src/wayland/wlr_layershell/wlr_layershell.hpp
Normal file
|
@ -0,0 +1,277 @@
|
|||
#pragma once
|
||||
|
||||
#include <qcontainerfwd.h>
|
||||
#include <qobject.h>
|
||||
#include <qproperty.h>
|
||||
#include <qqmlintegration.h>
|
||||
#include <qquickitem.h>
|
||||
#include <qquickwindow.h>
|
||||
#include <qsize.h>
|
||||
#include <qtmetamacros.h>
|
||||
#include <qtypes.h>
|
||||
|
||||
#include "../../core/doc.hpp"
|
||||
#include "../../core/util.hpp"
|
||||
#include "../../window/panelinterface.hpp"
|
||||
#include "../../window/proxywindow.hpp"
|
||||
|
||||
namespace qs::wayland::layershell {
|
||||
|
||||
struct LayerSurfaceState;
|
||||
class LayerSurfaceBridge;
|
||||
|
||||
///! WlrLayershell layer.
|
||||
/// See @@WlrLayershell.layer.
|
||||
namespace WlrLayer { // NOLINT
|
||||
Q_NAMESPACE;
|
||||
QML_ELEMENT;
|
||||
|
||||
enum Enum : quint8 {
|
||||
/// Below bottom
|
||||
Background = 0,
|
||||
/// Above background, usually below windows
|
||||
Bottom = 1,
|
||||
/// Commonly used for panels, app launchers, and docks.
|
||||
/// Usually renders over normal windows and below fullscreen windows.
|
||||
Top = 2,
|
||||
/// Usually renders over fullscreen windows
|
||||
Overlay = 3,
|
||||
};
|
||||
Q_ENUM_NS(Enum);
|
||||
|
||||
} // namespace WlrLayer
|
||||
|
||||
///! WlrLayershell keyboard focus mode
|
||||
/// See @@WlrLayershell.keyboardFocus.
|
||||
namespace WlrKeyboardFocus { // NOLINT
|
||||
Q_NAMESPACE;
|
||||
QML_ELEMENT;
|
||||
|
||||
enum Enum : quint8 {
|
||||
/// No keyboard input will be accepted.
|
||||
None = 0,
|
||||
/// Exclusive access to the keyboard, locking out all other windows.
|
||||
///
|
||||
/// > [!WARNING] You **CANNOT** use this to make a secure lock screen.
|
||||
/// >
|
||||
/// > If you want to make a lock screen, use @@WlSessionLock.
|
||||
Exclusive = 1,
|
||||
/// Access to the keyboard as determined by the operating system.
|
||||
///
|
||||
/// > [!WARNING] On some systems, `OnDemand` may cause the shell window to
|
||||
/// > retain focus over another window unexpectedly.
|
||||
/// > You should try `None` if you experience issues.
|
||||
OnDemand = 2,
|
||||
};
|
||||
Q_ENUM_NS(Enum);
|
||||
|
||||
} // namespace WlrKeyboardFocus
|
||||
|
||||
///! Wlroots layershell window
|
||||
/// Decorationless window that can be attached to the screen edges using the [zwlr_layer_shell_v1] protocol.
|
||||
///
|
||||
/// #### Attached object
|
||||
/// `WlrLayershell` works as an attached object of @@Quickshell.PanelWindow which you should use instead if you can,
|
||||
/// as it is platform independent.
|
||||
///
|
||||
/// ```qml
|
||||
/// PanelWindow {
|
||||
/// // When PanelWindow is backed with WlrLayershell this will work
|
||||
/// WlrLayershell.layer: WlrLayer.Bottom
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// To maintain platform compatibility you can dynamically set layershell specific properties.
|
||||
/// ```qml
|
||||
/// PanelWindow {
|
||||
/// Component.onCompleted: {
|
||||
/// if (this.WlrLayershell != null) {
|
||||
/// this.WlrLayershell.layer = WlrLayer.Bottom;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [zwlr_layer_shell_v1]: https://wayland.app/protocols/wlr-layer-shell-unstable-v1
|
||||
class WlrLayershell: public ProxyWindowBase {
|
||||
QSDOC_BASECLASS(PanelWindowInterface);
|
||||
// clang-format off
|
||||
Q_OBJECT;
|
||||
/// The shell layer the window sits in. Defaults to `WlrLayer.Top`.
|
||||
Q_PROPERTY(qs::wayland::layershell::WlrLayer::Enum layer READ layer WRITE setLayer NOTIFY layerChanged);
|
||||
/// Similar to the class property of windows. Can be used to identify the window to external tools.
|
||||
///
|
||||
/// Cannot be set after windowConnected.
|
||||
Q_PROPERTY(QString namespace READ ns WRITE setNamespace NOTIFY namespaceChanged);
|
||||
/// The degree of keyboard focus taken. Defaults to `KeyboardFocus.None`.
|
||||
Q_PROPERTY(qs::wayland::layershell::WlrKeyboardFocus::Enum keyboardFocus READ keyboardFocus WRITE setKeyboardFocus NOTIFY keyboardFocusChanged);
|
||||
|
||||
QSDOC_HIDE Q_PROPERTY(Anchors anchors READ anchors WRITE setAnchors NOTIFY anchorsChanged);
|
||||
QSDOC_HIDE Q_PROPERTY(qint32 exclusiveZone READ exclusiveZone WRITE setExclusiveZone NOTIFY exclusiveZoneChanged);
|
||||
QSDOC_HIDE Q_PROPERTY(ExclusionMode::Enum exclusionMode READ exclusionMode WRITE setExclusionMode NOTIFY exclusionModeChanged);
|
||||
QSDOC_HIDE Q_PROPERTY(Margins margins READ margins WRITE setMargins NOTIFY marginsChanged);
|
||||
QSDOC_HIDE Q_PROPERTY(bool aboveWindows READ aboveWindows WRITE setAboveWindows NOTIFY layerChanged);
|
||||
QSDOC_HIDE Q_PROPERTY(bool focusable READ focusable WRITE setFocusable NOTIFY keyboardFocusChanged);
|
||||
QML_ATTACHED(WlrLayershell);
|
||||
QML_ELEMENT;
|
||||
// clang-format on
|
||||
|
||||
public:
|
||||
explicit WlrLayershell(QObject* parent = nullptr);
|
||||
|
||||
ProxiedWindow* retrieveWindow(QObject* oldInstance) override;
|
||||
ProxiedWindow* createQQuickWindow() override;
|
||||
void connectWindow() override;
|
||||
[[nodiscard]] bool deleteOnInvisible() const override;
|
||||
|
||||
void onPolished() override;
|
||||
void trySetWidth(qint32 implicitWidth) override;
|
||||
void trySetHeight(qint32 implicitHeight) override;
|
||||
|
||||
void setScreen(QuickshellScreenInfo* screen) override;
|
||||
|
||||
[[nodiscard]] WlrLayer::Enum layer() const { return this->bLayer; }
|
||||
void setLayer(WlrLayer::Enum layer) { this->bLayer = layer; }
|
||||
|
||||
[[nodiscard]] QString ns() const { return this->bNamespace; }
|
||||
void setNamespace(const QString& ns) { this->bNamespace = ns; }
|
||||
|
||||
[[nodiscard]] WlrKeyboardFocus::Enum keyboardFocus() const { return this->bKeyboardFocus; }
|
||||
void setKeyboardFocus(WlrKeyboardFocus::Enum focus) { this->bKeyboardFocus = focus; }
|
||||
|
||||
[[nodiscard]] Anchors anchors() const { return this->bAnchors; }
|
||||
void setAnchors(Anchors anchors) { this->bAnchors = anchors; }
|
||||
|
||||
[[nodiscard]] qint32 exclusiveZone() const { return this->bExclusiveZone; }
|
||||
void setExclusiveZone(qint32 exclusiveZone) {
|
||||
Qt::beginPropertyUpdateGroup();
|
||||
this->bExclusiveZone = exclusiveZone;
|
||||
this->bExclusionMode = ExclusionMode::Normal;
|
||||
Qt::endPropertyUpdateGroup();
|
||||
}
|
||||
|
||||
[[nodiscard]] ExclusionMode::Enum exclusionMode() const { return this->bExclusionMode; }
|
||||
void setExclusionMode(ExclusionMode::Enum exclusionMode) { this->bExclusionMode = exclusionMode; }
|
||||
|
||||
[[nodiscard]] Margins margins() const { return this->bMargins; }
|
||||
void setMargins(Margins margins) { this->bMargins = margins; }
|
||||
|
||||
[[nodiscard]] bool aboveWindows() const;
|
||||
void setAboveWindows(bool aboveWindows);
|
||||
|
||||
[[nodiscard]] bool focusable() const;
|
||||
void setFocusable(bool focusable);
|
||||
|
||||
static WlrLayershell* qmlAttachedProperties(QObject* object);
|
||||
|
||||
signals:
|
||||
void layerChanged();
|
||||
void namespaceChanged();
|
||||
void keyboardFocusChanged();
|
||||
QSDOC_HIDE void anchorsChanged();
|
||||
QSDOC_HIDE void exclusiveZoneChanged();
|
||||
QSDOC_HIDE void exclusionModeChanged();
|
||||
QSDOC_HIDE void marginsChanged();
|
||||
|
||||
private slots:
|
||||
void updateAutoExclusion();
|
||||
|
||||
private:
|
||||
[[nodiscard]] LayerSurfaceState computeState() const;
|
||||
[[nodiscard]] qint32 computeExclusiveZone() const;
|
||||
|
||||
void onStateChanged();
|
||||
|
||||
bool compositorPicksScreen = true;
|
||||
LayerSurfaceBridge* bridge = nullptr;
|
||||
|
||||
// clang-format off
|
||||
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(WlrLayershell, WlrLayer::Enum, bLayer, WlrLayer::Top, &WlrLayershell::layerChanged);
|
||||
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(WlrLayershell, QString, bNamespace, "quickshell", &WlrLayershell::namespaceChanged);
|
||||
Q_OBJECT_BINDABLE_PROPERTY(WlrLayershell, Anchors, bAnchors, &WlrLayershell::anchorsChanged);
|
||||
Q_OBJECT_BINDABLE_PROPERTY(WlrLayershell, Margins, bMargins, &WlrLayershell::marginsChanged);
|
||||
Q_OBJECT_BINDABLE_PROPERTY(WlrLayershell, qint32, bExclusiveZone, &WlrLayershell::exclusiveZoneChanged);
|
||||
Q_OBJECT_BINDABLE_PROPERTY(WlrLayershell, WlrKeyboardFocus::Enum, bKeyboardFocus, &WlrLayershell::keyboardFocusChanged);
|
||||
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(WlrLayershell, ExclusionMode::Enum, bExclusionMode, ExclusionMode::Auto, &WlrLayershell::exclusionModeChanged);
|
||||
Q_OBJECT_COMPUTED_PROPERTY(WlrLayershell, qint32, bcExclusiveZone, &WlrLayershell::computeExclusiveZone);
|
||||
|
||||
QS_BINDING_SUBSCRIBE_METHOD(WlrLayershell, bLayer, onStateChanged, onValueChanged);
|
||||
QS_BINDING_SUBSCRIBE_METHOD(WlrLayershell, bAnchors, onStateChanged, onValueChanged);
|
||||
QS_BINDING_SUBSCRIBE_METHOD(WlrLayershell, bMargins, onStateChanged, onValueChanged);
|
||||
QS_BINDING_SUBSCRIBE_METHOD(WlrLayershell, bcExclusiveZone, onStateChanged, onValueChanged);
|
||||
QS_BINDING_SUBSCRIBE_METHOD(WlrLayershell, bKeyboardFocus, onStateChanged, onValueChanged);
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
class WaylandPanelInterface: public PanelWindowInterface {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
explicit WaylandPanelInterface(QObject* parent = nullptr);
|
||||
|
||||
void onReload(QObject* oldInstance) override;
|
||||
|
||||
[[nodiscard]] ProxyWindowBase* proxyWindow() const override;
|
||||
[[nodiscard]] QQuickItem* contentItem() const override;
|
||||
|
||||
// NOLINTBEGIN
|
||||
[[nodiscard]] bool isVisible() const override;
|
||||
[[nodiscard]] bool isBackingWindowVisible() const override;
|
||||
void setVisible(bool visible) override;
|
||||
|
||||
[[nodiscard]] qint32 implicitWidth() const override;
|
||||
void setImplicitWidth(qint32 implicitWidth) override;
|
||||
|
||||
[[nodiscard]] qint32 implicitHeight() const override;
|
||||
void setImplicitHeight(qint32 implicitHeight) override;
|
||||
|
||||
[[nodiscard]] qint32 width() const override;
|
||||
void setWidth(qint32 width) override;
|
||||
|
||||
[[nodiscard]] qint32 height() const override;
|
||||
void setHeight(qint32 height) override;
|
||||
|
||||
[[nodiscard]] virtual qreal devicePixelRatio() const override;
|
||||
|
||||
[[nodiscard]] QuickshellScreenInfo* screen() const override;
|
||||
void setScreen(QuickshellScreenInfo* screen) override;
|
||||
|
||||
[[nodiscard]] QColor color() const override;
|
||||
void setColor(QColor color) override;
|
||||
|
||||
[[nodiscard]] PendingRegion* mask() const override;
|
||||
void setMask(PendingRegion* mask) override;
|
||||
|
||||
[[nodiscard]] QsSurfaceFormat surfaceFormat() const override;
|
||||
void setSurfaceFormat(QsSurfaceFormat mask) override;
|
||||
|
||||
[[nodiscard]] QQmlListProperty<QObject> data() override;
|
||||
|
||||
// panel specific
|
||||
|
||||
[[nodiscard]] Anchors anchors() const override;
|
||||
void setAnchors(Anchors anchors) override;
|
||||
|
||||
[[nodiscard]] Margins margins() const override;
|
||||
void setMargins(Margins margins) override;
|
||||
|
||||
[[nodiscard]] qint32 exclusiveZone() const override;
|
||||
void setExclusiveZone(qint32 exclusiveZone) override;
|
||||
|
||||
[[nodiscard]] ExclusionMode::Enum exclusionMode() const override;
|
||||
void setExclusionMode(ExclusionMode::Enum exclusionMode) override;
|
||||
|
||||
[[nodiscard]] bool aboveWindows() const override;
|
||||
void setAboveWindows(bool aboveWindows) override;
|
||||
|
||||
[[nodiscard]] bool focusable() const override;
|
||||
void setFocusable(bool focusable) override;
|
||||
// NOLINTEND
|
||||
|
||||
private:
|
||||
WlrLayershell* layer;
|
||||
|
||||
friend class WlrLayershell;
|
||||
};
|
||||
|
||||
} // namespace qs::wayland::layershell
|
Loading…
Add table
Add a link
Reference in a new issue