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,252 +0,0 @@
|
|||
#include "wlr_layershell.hpp"
|
||||
#include <utility>
|
||||
|
||||
#include <qlogging.h>
|
||||
#include <qobject.h>
|
||||
#include <qqmllist.h>
|
||||
#include <qquickitem.h>
|
||||
#include <qquickwindow.h>
|
||||
#include <qtmetamacros.h>
|
||||
#include <qtypes.h>
|
||||
|
||||
#include "../core/qmlscreen.hpp"
|
||||
#include "../window/panelinterface.hpp"
|
||||
#include "../window/proxywindow.hpp"
|
||||
#include "wlr_layershell/window.hpp"
|
||||
|
||||
WlrLayershell::WlrLayershell(QObject* parent)
|
||||
: ProxyWindowBase(parent)
|
||||
, ext(new LayershellWindowExtension(this)) {}
|
||||
|
||||
ProxiedWindow* WlrLayershell::retrieveWindow(QObject* oldInstance) {
|
||||
auto* old = qobject_cast<WlrLayershell*>(oldInstance);
|
||||
auto* window = old == nullptr ? nullptr : old->disownWindow();
|
||||
|
||||
if (window != nullptr) {
|
||||
if (this->ext->attach(window)) {
|
||||
return window;
|
||||
} else {
|
||||
window->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
return this->createQQuickWindow();
|
||||
}
|
||||
|
||||
ProxiedWindow* WlrLayershell::createQQuickWindow() {
|
||||
auto* window = this->ProxyWindowBase::createQQuickWindow();
|
||||
|
||||
if (!this->ext->attach(window)) {
|
||||
qWarning() << "Could not attach Layershell extension to new QQuickWindow. Layer will not "
|
||||
"behave correctly.";
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
void WlrLayershell::connectWindow() {
|
||||
this->ProxyWindowBase::connectWindow();
|
||||
|
||||
// clang-format off
|
||||
QObject::connect(this->ext, &LayershellWindowExtension::layerChanged, this, &WlrLayershell::layerChanged);
|
||||
QObject::connect(this->ext, &LayershellWindowExtension::keyboardFocusChanged, this, &WlrLayershell::keyboardFocusChanged);
|
||||
QObject::connect(this->ext, &LayershellWindowExtension::anchorsChanged, this, &WlrLayershell::anchorsChanged);
|
||||
QObject::connect(this->ext, &LayershellWindowExtension::exclusiveZoneChanged, this, &WlrLayershell::exclusiveZoneChanged);
|
||||
QObject::connect(this->ext, &LayershellWindowExtension::marginsChanged, this, &WlrLayershell::marginsChanged);
|
||||
|
||||
QObject::connect(this, &ProxyWindowBase::widthChanged, this, &WlrLayershell::updateAutoExclusion);
|
||||
QObject::connect(this, &ProxyWindowBase::heightChanged, this, &WlrLayershell::updateAutoExclusion);
|
||||
QObject::connect(this, &WlrLayershell::anchorsChanged, this, &WlrLayershell::updateAutoExclusion);
|
||||
// clang-format on
|
||||
|
||||
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::trySetWidth(qint32 implicitWidth) {
|
||||
// only update the actual size if not blocked by anchors
|
||||
if (!this->ext->anchors().horizontalConstraint()) {
|
||||
this->ProxyWindowBase::trySetWidth(implicitWidth);
|
||||
}
|
||||
}
|
||||
|
||||
void WlrLayershell::trySetHeight(qint32 implicitHeight) {
|
||||
// only update the actual size if not blocked by anchors
|
||||
if (!this->ext->anchors().verticalConstraint()) {
|
||||
this->ProxyWindowBase::trySetHeight(implicitHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void WlrLayershell::setScreen(QuickshellScreenInfo* screen) {
|
||||
this->ext->setUseWindowScreen(screen != nullptr);
|
||||
this->ProxyWindowBase::setScreen(screen);
|
||||
}
|
||||
|
||||
// NOLINTBEGIN
|
||||
#define extPair(type, get, set) \
|
||||
type WlrLayershell::get() const { return this->ext->get(); } \
|
||||
void WlrLayershell::set(type value) { this->ext->set(value); }
|
||||
|
||||
extPair(WlrLayer::Enum, layer, setLayer);
|
||||
extPair(WlrKeyboardFocus::Enum, keyboardFocus, setKeyboardFocus);
|
||||
extPair(Margins, margins, setMargins);
|
||||
// NOLINTEND
|
||||
|
||||
Anchors WlrLayershell::anchors() const { return this->ext->anchors(); }
|
||||
|
||||
void WlrLayershell::setAnchors(Anchors anchors) {
|
||||
this->ext->setAnchors(anchors);
|
||||
if (!this->window) return;
|
||||
|
||||
// explicitly set width values are tracked so the entire screen isn't covered if an anchor is removed.
|
||||
if (!anchors.horizontalConstraint()) this->ProxyWindowBase::trySetWidth(this->implicitWidth());
|
||||
if (!anchors.verticalConstraint()) this->ProxyWindowBase::trySetHeight(this->implicitHeight());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
QString WlrLayershell::ns() const { return this->ext->ns(); }
|
||||
|
||||
void WlrLayershell::setNamespace(QString ns) {
|
||||
this->ext->setNamespace(std::move(ns));
|
||||
emit this->namespaceChanged();
|
||||
}
|
||||
|
||||
qint32 WlrLayershell::exclusiveZone() const { return this->ext->exclusiveZone(); }
|
||||
|
||||
void WlrLayershell::setExclusiveZone(qint32 exclusiveZone) {
|
||||
this->mExclusiveZone = exclusiveZone;
|
||||
this->setExclusionMode(ExclusionMode::Normal);
|
||||
this->ext->setExclusiveZone(exclusiveZone);
|
||||
}
|
||||
|
||||
ExclusionMode::Enum WlrLayershell::exclusionMode() const { return this->mExclusionMode; }
|
||||
|
||||
void WlrLayershell::setExclusionMode(ExclusionMode::Enum exclusionMode) {
|
||||
if (exclusionMode == this->mExclusionMode) return;
|
||||
this->mExclusionMode = exclusionMode;
|
||||
|
||||
if (exclusionMode == ExclusionMode::Normal) {
|
||||
this->ext->setExclusiveZone(this->mExclusiveZone);
|
||||
} else if (exclusionMode == ExclusionMode::Ignore) {
|
||||
this->ext->setExclusiveZone(-1);
|
||||
} else {
|
||||
this->setAutoExclusion();
|
||||
}
|
||||
}
|
||||
|
||||
void WlrLayershell::setAutoExclusion() {
|
||||
const auto anchors = this->anchors();
|
||||
auto zone = 0;
|
||||
|
||||
if (anchors.horizontalConstraint()) zone = this->height();
|
||||
else if (anchors.verticalConstraint()) zone = this->width();
|
||||
|
||||
this->ext->setExclusiveZone(zone);
|
||||
}
|
||||
|
||||
void WlrLayershell::updateAutoExclusion() {
|
||||
if (this->mExclusionMode == ExclusionMode::Auto) {
|
||||
this->setAutoExclusion();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
Loading…
Add table
Add a link
Reference in a new issue