Skip to content

Commit e0cff67

Browse files
committed
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.
1 parent 6a8284d commit e0cff67

File tree

13 files changed

+362
-491
lines changed

13 files changed

+362
-491
lines changed

src/wayland/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ add_library(quickshell-wayland-init OBJECT init.cpp)
8585
set(WAYLAND_MODULES)
8686

8787
if (WAYLAND_WLR_LAYERSHELL)
88-
target_sources(quickshell-wayland PRIVATE wlr_layershell.cpp)
8988
add_subdirectory(wlr_layershell)
9089
target_compile_definitions(quickshell-wayland PRIVATE QS_WAYLAND_WLR_LAYERSHELL)
9190
target_compile_definitions(quickshell-wayland-init PRIVATE QS_WAYLAND_WLR_LAYERSHELL)

src/wayland/init.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include "../core/plugin.hpp"
88

99
#ifdef QS_WAYLAND_WLR_LAYERSHELL
10-
#include "wlr_layershell.hpp"
10+
#include "wlr_layershell/wlr_layershell.hpp"
1111
#endif
1212

1313
void installPlatformMenuHook(); // NOLINT(misc-use-internal-linkage)
@@ -39,7 +39,12 @@ class WaylandPlugin: public QsEnginePlugin {
3939

4040
void registerTypes() override {
4141
#ifdef QS_WAYLAND_WLR_LAYERSHELL
42-
qmlRegisterType<WaylandPanelInterface>("Quickshell._WaylandOverlay", 1, 0, "PanelWindow");
42+
qmlRegisterType<qs::wayland::layershell::WaylandPanelInterface>(
43+
"Quickshell._WaylandOverlay",
44+
1,
45+
0,
46+
"PanelWindow"
47+
);
4348

4449
// If any types are defined inside a module using QML_ELEMENT then all QML_ELEMENT types
4550
// will not be registered. This can be worked around with a module import which makes

src/wayland/module.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
name = "Quickshell.Wayland"
22
description = "Wayland specific Quickshell types"
33
headers = [
4-
"wlr_layershell/window.hpp",
5-
"wlr_layershell.hpp",
4+
"wlr_layershell/wlr_layershell.hpp",
65
"session_lock.hpp",
76
"toplevel_management/qml.hpp",
87
"screencopy/view.hpp",

src/wayland/wlr_layershell/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
qt_add_library(quickshell-wayland-layershell STATIC
2+
wlr_layershell.cpp
23
shell_integration.cpp
34
surface.cpp
4-
window.cpp
55
)
66

77
qt_add_qml_module(quickshell-wayland-layershell

src/wayland/wlr_layershell/shell_integration.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@
66

77
#include "surface.hpp"
88

9-
QSWaylandLayerShellIntegration::QSWaylandLayerShellIntegration()
10-
: QtWaylandClient::QWaylandShellIntegrationTemplate<QSWaylandLayerShellIntegration>(4) {}
9+
namespace qs::wayland::layershell {
1110

12-
QSWaylandLayerShellIntegration::~QSWaylandLayerShellIntegration() {
11+
LayerShellIntegration::LayerShellIntegration()
12+
: QtWaylandClient::QWaylandShellIntegrationTemplate<LayerShellIntegration>(4) {}
13+
14+
LayerShellIntegration::~LayerShellIntegration() {
1315
if (this->isInitialized()) {
1416
this->destroy();
1517
}
1618
}
1719

1820
QtWaylandClient::QWaylandShellSurface*
19-
QSWaylandLayerShellIntegration::createShellSurface(QtWaylandClient::QWaylandWindow* window) {
20-
return new QSWaylandLayerSurface(this, window);
21+
LayerShellIntegration::createShellSurface(QtWaylandClient::QWaylandWindow* window) {
22+
return new LayerSurface(this, window);
2123
}
24+
25+
} // namespace qs::wayland::layershell

src/wayland/wlr_layershell/shell_integration.hpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@
55
#include <qtclasshelpermacros.h>
66
#include <qwayland-wlr-layer-shell-unstable-v1.h>
77

8-
class QSWaylandLayerShellIntegration
9-
: public QtWaylandClient::QWaylandShellIntegrationTemplate<QSWaylandLayerShellIntegration>
8+
namespace qs::wayland::layershell {
9+
10+
class LayerShellIntegration
11+
: public QtWaylandClient::QWaylandShellIntegrationTemplate<LayerShellIntegration>
1012
, public QtWayland::zwlr_layer_shell_v1 {
1113
public:
12-
QSWaylandLayerShellIntegration();
13-
~QSWaylandLayerShellIntegration() override;
14-
Q_DISABLE_COPY_MOVE(QSWaylandLayerShellIntegration);
14+
LayerShellIntegration();
15+
~LayerShellIntegration() override;
16+
Q_DISABLE_COPY_MOVE(LayerShellIntegration);
1517

1618
QtWaylandClient::QWaylandShellSurface* createShellSurface(QtWaylandClient::QWaylandWindow* window
1719
) override;
1820
};
21+
22+
} // namespace qs::wayland::layershell
Lines changed: 120 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "surface.hpp"
22
#include <algorithm>
33
#include <any>
4+
#include <utility>
45

56
#include <private/qhighdpiscaling_p.h>
67
#include <private/qwaylanddisplay_p.h>
@@ -13,16 +14,20 @@
1314
#include <qsize.h>
1415
#include <qtversionchecks.h>
1516
#include <qtypes.h>
17+
#include <qvariant.h>
1618
#include <qwayland-wlr-layer-shell-unstable-v1.h>
19+
#include <qwindow.h>
1720

1821
#include "../../window/panelinterface.hpp"
1922
#include "shell_integration.hpp"
20-
#include "window.hpp"
23+
#include "wlr_layershell.hpp"
2124

2225
#if QT_VERSION < QT_VERSION_CHECK(6, 7, 0)
2326
#include <qpoint.h>
2427
#endif
2528

29+
namespace qs::wayland::layershell {
30+
2631
namespace {
2732

2833
[[nodiscard]] QtWayland::zwlr_layer_shell_v1::layer toWaylandLayer(const WlrLayer::Enum& layer
@@ -69,21 +74,72 @@ toWaylandKeyboardFocus(const WlrKeyboardFocus::Enum& focus) noexcept {
6974

7075
} // namespace
7176

72-
QSWaylandLayerSurface::QSWaylandLayerSurface(
73-
QSWaylandLayerShellIntegration* shell,
74-
QtWaylandClient::QWaylandWindow* window
75-
)
77+
void LayerSurfaceBridge::commitState() {
78+
if (this->surface) this->surface->commit();
79+
}
80+
81+
LayerSurfaceBridge* LayerSurfaceBridge::get(QWindow* window) {
82+
auto v = window->property("layershell_bridge");
83+
84+
if (v.canConvert<LayerSurfaceBridge*>()) {
85+
return v.value<LayerSurfaceBridge*>();
86+
}
87+
88+
return nullptr;
89+
}
90+
91+
LayerSurfaceBridge* LayerSurfaceBridge::init(QWindow* window, LayerSurfaceState state) {
92+
auto* bridge = LayerSurfaceBridge::get(window);
93+
94+
if (!bridge) {
95+
bridge = new LayerSurfaceBridge(window);
96+
window->setProperty("layershell_bridge", QVariant::fromValue(bridge));
97+
} else if (!bridge->state.isCompatible(state)) {
98+
return nullptr;
99+
}
100+
101+
if (!bridge->surface) {
102+
// Qt appears to be resetting the window's screen on creation on some systems. This works around it.
103+
auto* screen = window->screen();
104+
window->create();
105+
window->setScreen(screen);
106+
107+
auto* waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow*>(window->handle());
108+
if (waylandWindow == nullptr) {
109+
qWarning() << window << "is not a wayland window. Cannot create layershell surface.";
110+
return nullptr;
111+
}
112+
113+
static LayerShellIntegration* layershellIntegration = nullptr; // NOLINT
114+
if (layershellIntegration == nullptr) {
115+
layershellIntegration = new LayerShellIntegration();
116+
if (!layershellIntegration->initialize(waylandWindow->display())) {
117+
delete layershellIntegration;
118+
layershellIntegration = nullptr;
119+
qWarning() << "Failed to initialize layershell integration";
120+
}
121+
}
122+
123+
waylandWindow->setShellIntegration(layershellIntegration);
124+
}
125+
126+
bridge->state = std::move(state);
127+
bridge->commitState();
128+
129+
return bridge;
130+
}
131+
132+
LayerSurface::LayerSurface(LayerShellIntegration* shell, QtWaylandClient::QWaylandWindow* window)
76133
: QtWaylandClient::QWaylandShellSurface(window) {
77134

78135
auto* qwindow = window->window();
79-
this->ext = LayershellWindowExtension::get(qwindow);
80136

81-
if (this->ext == nullptr) {
82-
qFatal() << "QSWaylandLayerSurface created with null LayershellWindowExtension";
83-
}
137+
this->bridge = LayerSurfaceBridge::get(qwindow);
138+
if (this->bridge == nullptr) qFatal() << "LayerSurface created with null bridge";
139+
const auto& s = this->bridge->state;
84140

85141
wl_output* output = nullptr; // NOLINT (include)
86-
if (this->ext->useWindowScreen) {
142+
if (!s.compositorPickesScreen) {
87143
auto* waylandScreen =
88144
dynamic_cast<QtWaylandClient::QWaylandScreen*>(qwindow->screen()->handle());
89145

@@ -98,36 +154,28 @@ QSWaylandLayerSurface::QSWaylandLayerSurface(
98154
this->init(shell->get_layer_surface(
99155
window->waylandSurface()->object(),
100156
output,
101-
toWaylandLayer(this->ext->mLayer),
102-
this->ext->mNamespace
157+
toWaylandLayer(s.layer),
158+
s.mNamespace
103159
));
104160

105-
this->updateAnchors();
106-
this->updateLayer();
107-
this->updateMargins();
108-
this->updateExclusiveZone();
109-
this->updateKeyboardFocus();
110-
111-
// new updates will be sent from the extension
112-
this->ext->surface = this;
113-
114-
auto size = constrainedSize(this->ext->mAnchors, window->surfaceSize());
161+
auto size = constrainedSize(s.anchors, QHighDpi::toNativePixels(s.implicitSize, qwindow));
115162
this->set_size(size.width(), size.height());
116-
}
117-
118-
QSWaylandLayerSurface::~QSWaylandLayerSurface() {
119-
if (this->ext != nullptr) {
120-
this->ext->surface = nullptr;
121-
}
163+
this->set_anchor(toWaylandAnchors(s.anchors));
164+
this->set_margin(
165+
QHighDpi::toNativePixels(s.margins.mTop, qwindow),
166+
QHighDpi::toNativePixels(s.margins.mRight, qwindow),
167+
QHighDpi::toNativePixels(s.margins.mBottom, qwindow),
168+
QHighDpi::toNativePixels(s.margins.mLeft, qwindow)
169+
);
170+
this->set_exclusive_zone(QHighDpi::toNativePixels(s.exclusiveZone, qwindow));
171+
this->set_keyboard_interactivity(toWaylandKeyboardFocus(s.keyboardFocus));
122172

123-
this->destroy();
173+
this->bridge->surface = this;
124174
}
125175

126-
void QSWaylandLayerSurface::zwlr_layer_surface_v1_configure(
127-
quint32 serial,
128-
quint32 width,
129-
quint32 height
130-
) {
176+
LayerSurface::~LayerSurface() { this->destroy(); }
177+
178+
void LayerSurface::zwlr_layer_surface_v1_configure(quint32 serial, quint32 width, quint32 height) {
131179
this->ack_configure(serial);
132180

133181
this->size = QSize(static_cast<qint32>(width), static_cast<qint32>(height));
@@ -146,51 +194,53 @@ void QSWaylandLayerSurface::zwlr_layer_surface_v1_configure(
146194
}
147195
}
148196

149-
void QSWaylandLayerSurface::zwlr_layer_surface_v1_closed() { this->window()->window()->close(); }
197+
void LayerSurface::zwlr_layer_surface_v1_closed() { this->window()->window()->close(); }
150198

151-
bool QSWaylandLayerSurface::isExposed() const { return this->configured; }
199+
bool LayerSurface::isExposed() const { return this->configured; }
152200

153-
void QSWaylandLayerSurface::applyConfigure() {
154-
this->window()->resizeFromApplyConfigure(this->size);
155-
}
201+
void LayerSurface::applyConfigure() { this->window()->resizeFromApplyConfigure(this->size); }
156202

157-
void QSWaylandLayerSurface::setWindowGeometry(const QRect& geometry) {
158-
if (this->ext == nullptr) return;
159-
auto size = constrainedSize(this->ext->mAnchors, geometry.size());
160-
this->set_size(size.width(), size.height());
161-
}
203+
QWindow* LayerSurface::qwindow() { return this->window()->window(); }
162204

163-
QWindow* QSWaylandLayerSurface::qwindow() { return this->window()->window(); }
205+
void LayerSurface::commit() {
206+
const auto& p = this->bridge->state;
207+
auto& c = this->committed;
164208

165-
void QSWaylandLayerSurface::updateLayer() {
166-
this->set_layer(toWaylandLayer(this->ext->mLayer));
167-
this->window()->waylandSurface()->commit();
168-
}
209+
if (p.implicitSize != c.implicitSize || p.anchors != c.anchors) {
210+
auto size =
211+
constrainedSize(p.anchors, QHighDpi::toNativePixels(p.implicitSize, this->qwindow()));
212+
this->set_size(size.width(), size.height());
213+
}
169214

170-
void QSWaylandLayerSurface::updateAnchors() {
171-
this->set_anchor(toWaylandAnchors(this->ext->mAnchors));
172-
this->setWindowGeometry(this->window()->windowContentGeometry());
173-
this->window()->waylandSurface()->commit();
174-
}
215+
if (p.anchors != c.anchors) {
216+
this->set_anchor(toWaylandAnchors(p.anchors));
217+
}
175218

176-
void QSWaylandLayerSurface::updateMargins() {
177-
auto& margins = this->ext->mMargins;
178-
this->set_margin(margins.mTop, margins.mRight, margins.mBottom, margins.mLeft);
179-
this->window()->waylandSurface()->commit();
180-
}
219+
if (p.margins != c.margins) {
220+
this->set_margin(
221+
QHighDpi::toNativePixels(p.margins.mTop, this->qwindow()),
222+
QHighDpi::toNativePixels(p.margins.mRight, this->qwindow()),
223+
QHighDpi::toNativePixels(p.margins.mBottom, this->qwindow()),
224+
QHighDpi::toNativePixels(p.margins.mLeft, this->qwindow())
225+
);
226+
}
181227

182-
void QSWaylandLayerSurface::updateExclusiveZone() {
183-
auto nativeZone = QHighDpi::toNativePixels(this->ext->mExclusiveZone, this->window()->window());
184-
this->set_exclusive_zone(nativeZone);
185-
this->window()->waylandSurface()->commit();
186-
}
228+
if (p.layer != c.layer) {
229+
this->set_layer(p.layer);
230+
}
187231

188-
void QSWaylandLayerSurface::updateKeyboardFocus() {
189-
this->set_keyboard_interactivity(toWaylandKeyboardFocus(this->ext->mKeyboardFocus));
190-
this->window()->waylandSurface()->commit();
232+
if (p.exclusiveZone != c.exclusiveZone) {
233+
this->set_exclusive_zone(QHighDpi::toNativePixels(p.exclusiveZone, this->qwindow()));
234+
}
235+
236+
if (p.keyboardFocus != c.keyboardFocus) {
237+
this->set_keyboard_interactivity(toWaylandKeyboardFocus(p.keyboardFocus));
238+
}
239+
240+
c = p;
191241
}
192242

193-
void QSWaylandLayerSurface::attachPopup(QtWaylandClient::QWaylandShellSurface* popup) {
243+
void LayerSurface::attachPopup(QtWaylandClient::QWaylandShellSurface* popup) {
194244
std::any role = popup->surfaceRole();
195245

196246
if (auto* popupRole = std::any_cast<::xdg_popup*>(&role)) { // NOLINT
@@ -200,3 +250,5 @@ void QSWaylandLayerSurface::attachPopup(QtWaylandClient::QWaylandShellSurface* p
200250
<< "as the popup is not an xdg_popup.";
201251
}
202252
}
253+
254+
} // namespace qs::wayland::layershell

0 commit comments

Comments
 (0)