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>
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+
2631namespace {
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