11#include " qml.hpp"
22#include < memory>
33
4+ #include < private/qhighdpiscaling_p.h>
45#include < private/qwaylandwindow_p.h>
56#include < qlogging.h>
67#include < qobject.h>
78#include < qqmlinfo.h>
9+ #include < qregion.h>
810#include < qtmetamacros.h>
911#include < qtypes.h>
12+ #include < qvariant.h>
1013#include < qwindow.h>
1114
15+ #include " ../../../core/region.hpp"
1216#include " ../../../window/proxywindow.hpp"
1317#include " ../../../window/windowinterface.hpp"
14- #include " ../../util.hpp"
1518#include " manager.hpp"
1619#include " surface.hpp"
1720
@@ -40,6 +43,15 @@ HyprlandWindow::HyprlandWindow(ProxyWindowBase* window): QObject(nullptr), proxy
4043 &HyprlandWindow::onWindowConnected
4144 );
4245
46+ QObject::connect (window, &ProxyWindowBase::polished, this , &HyprlandWindow::onWindowPolished);
47+
48+ QObject::connect (
49+ window,
50+ &ProxyWindowBase::devicePixelRatioChanged,
51+ this ,
52+ &HyprlandWindow::updateVisibleMask
53+ );
54+
4355 QObject::connect (window, &QObject::destroyed, this , &HyprlandWindow::onProxyWindowDestroyed);
4456
4557 if (window->backingWindow ()) {
@@ -60,14 +72,76 @@ void HyprlandWindow::setOpacity(qreal opacity) {
6072
6173 this ->mOpacity = opacity;
6274
63- if (this ->surface ) {
64- this ->surface -> setOpacity ( opacity) ;
65- qs::wayland::util::scheduleCommit ( this ->proxyWindow );
75+ if (this ->surface && this -> proxyWindow ) {
76+ this ->pendingPolish . opacity = true ;
77+ this ->proxyWindow -> schedulePolish ( );
6678 }
6779
6880 emit this ->opacityChanged ();
6981}
7082
83+ PendingRegion* HyprlandWindow::visibleMask () const { return this ->mVisibleMask ; }
84+
85+ void HyprlandWindow::setVisibleMask (PendingRegion* mask) {
86+ if (mask == this ->mVisibleMask ) return ;
87+
88+ if (this ->mVisibleMask ) {
89+ QObject::disconnect (this ->mVisibleMask , nullptr , this , nullptr );
90+ }
91+
92+ this ->mVisibleMask = mask;
93+
94+ if (mask) {
95+ QObject::connect (mask, &QObject::destroyed, this , &HyprlandWindow::onVisibleMaskDestroyed);
96+ QObject::connect (mask, &PendingRegion::changed, this , &HyprlandWindow::updateVisibleMask);
97+ }
98+
99+ this ->updateVisibleMask ();
100+ emit this ->visibleMaskChanged ();
101+ }
102+
103+ void HyprlandWindow::onVisibleMaskDestroyed () {
104+ this ->mVisibleMask = nullptr ;
105+ this ->updateVisibleMask ();
106+ emit this ->visibleMaskChanged ();
107+ }
108+
109+ void HyprlandWindow::updateVisibleMask () {
110+ if (!this ->surface || !this ->proxyWindow ) return ;
111+
112+ this ->pendingPolish .visibleMask = true ;
113+ this ->proxyWindow ->schedulePolish ();
114+ }
115+
116+ void HyprlandWindow::onWindowPolished () {
117+ if (!this ->surface ) return ;
118+
119+ if (this ->pendingPolish .opacity ) {
120+ this ->surface ->setOpacity (this ->mOpacity );
121+ this ->pendingPolish .opacity = false ;
122+ }
123+
124+ if (this ->pendingPolish .visibleMask ) {
125+ QRegion mask;
126+ if (this ->mVisibleMask != nullptr ) {
127+ mask =
128+ this ->mVisibleMask ->applyTo (QRect (0 , 0 , this ->mWindow ->width (), this ->mWindow ->height ()));
129+ }
130+
131+ auto dpr = this ->proxyWindow ->devicePixelRatio ();
132+ if (dpr != 1.0 ) {
133+ mask = QHighDpi::scale (mask, dpr);
134+ }
135+
136+ if (mask.isEmpty () && this ->mVisibleMask ) {
137+ mask = QRect (-1 , -1 , 1 , 1 );
138+ }
139+
140+ this ->surface ->setVisibleRegion (mask);
141+ this ->pendingPolish .visibleMask = false ;
142+ }
143+ }
144+
71145void HyprlandWindow::onWindowConnected () {
72146 this ->mWindow = this ->proxyWindow ->backingWindow ();
73147 // disconnected by destructor
@@ -86,33 +160,46 @@ void HyprlandWindow::onWindowVisibleChanged() {
86160 if (!this ->mWindow ->handle ()) {
87161 this ->mWindow ->create ();
88162 }
163+ }
89164
90- this ->mWaylandWindow = dynamic_cast <QWaylandWindow*>(this ->mWindow ->handle ());
165+ auto * window = dynamic_cast <QWaylandWindow*>(this ->mWindow ->handle ());
166+ if (window == this ->mWaylandWindow ) return ;
91167
92- if (this ->mWaylandWindow ) {
93- // disconnected by destructor
168+ if (this ->mWaylandWindow ) {
169+ QObject::disconnect (this ->mWaylandWindow , nullptr , this , nullptr );
170+ }
94171
95- QObject::connect (
96- this ->mWaylandWindow ,
97- &QWaylandWindow::surfaceCreated,
98- this ,
99- &HyprlandWindow::onWaylandSurfaceCreated
100- );
172+ this ->mWaylandWindow = window;
173+ if (!window) return ;
101174
102- QObject::connect (
103- this ->mWaylandWindow ,
104- &QWaylandWindow::surfaceDestroyed ,
105- this ,
106- &HyprlandWindow::onWaylandSurfaceDestroyed
107- );
175+ QObject::connect (
176+ this ->mWaylandWindow ,
177+ &QObject::destroyed ,
178+ this ,
179+ &HyprlandWindow::onWaylandWindowDestroyed
180+ );
108181
109- if (this ->mWaylandWindow ->surface ()) {
110- this ->onWaylandSurfaceCreated ();
111- }
112- }
182+ QObject::connect (
183+ this ->mWaylandWindow ,
184+ &QWaylandWindow::surfaceCreated,
185+ this ,
186+ &HyprlandWindow::onWaylandSurfaceCreated
187+ );
188+
189+ QObject::connect (
190+ this ->mWaylandWindow ,
191+ &QWaylandWindow::surfaceDestroyed,
192+ this ,
193+ &HyprlandWindow::onWaylandSurfaceDestroyed
194+ );
195+
196+ if (this ->mWaylandWindow ->surface ()) {
197+ this ->onWaylandSurfaceCreated ();
113198 }
114199}
115200
201+ void HyprlandWindow::onWaylandWindowDestroyed () { this ->mWaylandWindow = nullptr ; }
202+
116203void HyprlandWindow::onWaylandSurfaceCreated () {
117204 auto * manager = impl::HyprlandSurfaceManager::instance ();
118205
@@ -122,12 +209,26 @@ void HyprlandWindow::onWaylandSurfaceCreated() {
122209 return ;
123210 }
124211
125- auto * ext = manager->createHyprlandExtension (this ->mWaylandWindow );
126- this ->surface = std::unique_ptr<impl::HyprlandSurface>(ext);
212+ auto v = this ->mWaylandWindow ->property (" hyprland_window_ext" );
213+ if (v.canConvert <HyprlandWindow*>()) {
214+ auto * windowExt = v.value <HyprlandWindow*>();
215+ if (windowExt != this && windowExt->surface ) {
216+ this ->surface .swap (windowExt->surface );
217+ }
218+ }
219+
220+ if (!this ->surface ) {
221+ auto * ext = manager->createHyprlandExtension (this ->mWaylandWindow );
222+ this ->surface = std::unique_ptr<impl::HyprlandSurface>(ext);
223+ }
127224
128- if (this ->mOpacity != 1.0 ) {
129- this ->surface ->setOpacity (this ->mOpacity );
130- qs::wayland::util::scheduleCommit (this ->proxyWindow );
225+ this ->mWaylandWindow ->setProperty (" hyprland_window_ext" , QVariant::fromValue (this ));
226+
227+ this ->pendingPolish .opacity = this ->mOpacity != 1.0 ;
228+ this ->pendingPolish .visibleMask = this ->mVisibleMask ;
229+
230+ if (this ->pendingPolish .opacity || this ->pendingPolish .visibleMask ) {
231+ this ->proxyWindow ->schedulePolish ();
131232 }
132233}
133234
@@ -144,8 +245,9 @@ void HyprlandWindow::onProxyWindowDestroyed() {
144245 // Deleting it when the proxy window is deleted will cause a full opacity frame between the destruction of the
145246 // hyprland_surface_v1 and wl_surface objects.
146247
248+ this ->proxyWindow = nullptr ;
249+
147250 if (this ->surface == nullptr ) {
148- this ->proxyWindow = nullptr ;
149251 this ->deleteLater ();
150252 }
151253}
0 commit comments