Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwaylandshmbackingstore.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
#
include
"qwaylandshmbackingstore_p.h"
5
#
include
"qwaylandwindow_p.h"
6
#
include
"qwaylandsubsurface_p.h"
7
#
include
"qwaylanddisplay_p.h"
8
#
include
"qwaylandscreen_p.h"
9
#
include
"qwaylandabstractdecoration_p.h"
10
11
#
include
<
QtCore
/
qdebug
.
h
>
12
#
include
<
QtCore
/
qstandardpaths
.
h
>
13
#
include
<
QtCore
/
qtemporaryfile
.
h
>
14
#
include
<
QtGui
/
QPainter
>
15
#
include
<
QtGui
/
QTransform
>
16
#
include
<
QMutexLocker
>
17
18
#
include
<
QtWaylandClient
/
private
/
wayland
-
wayland
-
client
-
protocol
.
h
>
19
20
#
include
<
memory
>
21
22
#
include
<
fcntl
.
h
>
23
#
include
<
unistd
.
h
>
24
#
include
<
sys
/
mman
.
h
>
25
26
#
ifdef
Q_OS_LINUX
27
#
include
<
sys
/
syscall
.
h
>
28
// from linux/memfd.h:
29
#
ifndef
MFD_CLOEXEC
30
#
define
MFD_CLOEXEC
0x0001U
31
#
endif
32
#
ifndef
MFD_ALLOW_SEALING
33
#
define
MFD_ALLOW_SEALING
0x0002U
34
#
endif
35
// from bits/fcntl-linux.h
36
#
ifndef
F_ADD_SEALS
37
#
define
F_ADD_SEALS
1033
38
#
endif
39
#
ifndef
F_SEAL_SEAL
40
#
define
F_SEAL_SEAL
0x0001
41
#
endif
42
#
ifndef
F_SEAL_SHRINK
43
#
define
F_SEAL_SHRINK
0x0002
44
#
endif
45
#
endif
46
47
QT_BEGIN_NAMESPACE
48
49
extern
void
qt_scrollRectInImage
(QImage &,
const
QRect &,
const
QPoint &);
50
51
namespace
QtWaylandClient
{
52
53
QWaylandShmBuffer
::
QWaylandShmBuffer
(
QWaylandDisplay
*
display
,
54
const
QSize
&
size
,
QImage
::
Format
format
,
qreal
scale
,
wl_event_queue
*
customEventQueue
)
55
:
mDirtyRegion
(
QRect
(
QPoint
(0, 0),
size
/
scale
))
56
{
57
int
stride
=
size
.
width
() * 4;
58
int
alloc
=
stride
*
size
.
height
();
59
int
fd
= -1;
60
61
#
ifdef
SYS_memfd_create
62
fd
=
syscall
(
SYS_memfd_create
,
"wayland-shm"
,
MFD_CLOEXEC
|
MFD_ALLOW_SEALING
);
63
if
(
fd
>= 0)
64
fcntl
(
fd
,
F_ADD_SEALS
,
F_SEAL_SHRINK
|
F_SEAL_SEAL
);
65
#
endif
66
67
std
::
unique_ptr
<
QFile
>
filePointer
;
68
bool
opened
;
69
70
if
(
fd
== -1) {
71
auto
tmpFile
=
72
std
::
make_unique
<
QTemporaryFile
>(
QStandardPaths
::
writableLocation
(
QStandardPaths
::
RuntimeLocation
) +
73
QLatin1String
(
"/wayland-shm-XXXXXX"
));
74
opened
=
tmpFile
->
open
();
75
filePointer
=
std
::
move
(
tmpFile
);
76
}
else
{
77
auto
file
=
std
::
make_unique
<
QFile
>();
78
opened
=
file
->
open
(
fd
,
QIODevice
::
ReadWrite
|
QIODevice
::
Unbuffered
,
QFile
::
AutoCloseHandle
);
79
filePointer
=
std
::
move
(
file
);
80
}
81
// NOTE beginPaint assumes a new buffer be all zeroes, which QFile::resize does.
82
if
(!
opened
|| !
filePointer
->
resize
(
alloc
)) {
83
qWarning
(
"QWaylandShmBuffer: failed: %s"
,
qUtf8Printable
(
filePointer
->
errorString
()));
84
return
;
85
}
86
fd
=
filePointer
->
handle
();
87
88
// map ourselves: QFile::map() will unmap when the object is destroyed,
89
// but we want this mapping to persist (unmapping in destructor)
90
uchar
*
data
= (
uchar
*)
91
mmap
(
nullptr
,
alloc
, PROT_READ | PROT_WRITE, MAP_SHARED,
fd
, 0);
92
if
(
data
== (
uchar
*)
MAP_FAILED
) {
93
qErrnoWarning
(
"QWaylandShmBuffer: mmap failed"
);
94
return
;
95
}
96
97
QWaylandShm
*
shm
=
display
->
shm
();
98
wl_shm_format
wl_format
=
shm
->
formatFrom
(
format
);
99
mImage
=
QImage
(
data
,
size
.
width
(),
size
.
height
(),
stride
,
format
);
100
mImage
.
setDevicePixelRatio
(
scale
);
101
102
mShmPool
=
wl_shm_create_pool
(
shm
->
object
(),
fd
,
alloc
);
103
init
(
wl_shm_pool_create_buffer
(
mShmPool
,0,
size
.
width
(),
size
.
height
(),
104
stride
,
wl_format
));
105
if
(
customEventQueue
)
106
wl_proxy_set_queue
(
reinterpret_cast
<
struct
wl_proxy
*>(
buffer
()),
customEventQueue
);
107
}
108
109
QWaylandShmBuffer
::~
QWaylandShmBuffer
(
void
)
110
{
111
delete
mMarginsImage
;
112
if
(
mImage
.
constBits
())
113
munmap
((
void
*)
mImage
.
constBits
(),
mImage
.
sizeInBytes
());
114
if
(
mShmPool
)
115
wl_shm_pool_destroy
(
mShmPool
);
116
}
117
118
QImage
*
QWaylandShmBuffer
::
imageInsideMargins
(
const
QMargins
&
marginsIn
)
119
{
120
QMargins
margins
=
marginsIn
*
mImage
.
devicePixelRatio
();
121
122
if
(!
margins
.
isNull
() &&
margins
!=
mMargins
) {
123
if
(
mMarginsImage
) {
124
delete
mMarginsImage
;
125
}
126
uchar
*
bits
=
const_cast
<
uchar
*>(
mImage
.
constBits
());
127
uchar
*
b_s_data
=
bits
+
margins
.
top
() *
mImage
.
bytesPerLine
() +
margins
.
left
() * 4;
128
int
b_s_width
=
mImage
.
size
().
width
() -
margins
.
left
() -
margins
.
right
();
129
int
b_s_height
=
mImage
.
size
().
height
() -
margins
.
top
() -
margins
.
bottom
();
130
mMarginsImage
=
new
QImage
(
b_s_data
,
b_s_width
,
b_s_height
,
mImage
.
bytesPerLine
(),
mImage
.
format
());
131
mMarginsImage
->
setDevicePixelRatio
(
mImage
.
devicePixelRatio
());
132
}
133
if
(
margins
.
isNull
()) {
134
delete
mMarginsImage
;
135
mMarginsImage
=
nullptr
;
136
}
137
138
mMargins
=
margins
;
139
if
(!
mMarginsImage
)
140
return
&
mImage
;
141
142
return
mMarginsImage
;
143
144
}
145
146
QWaylandShmBackingStore
::
QWaylandShmBackingStore
(
QWindow
*
window
,
QWaylandDisplay
*
display
)
147
:
QPlatformBackingStore
(
window
)
148
,
mDisplay
(
display
)
149
{
150
mEventQueue
=
wl_display_create_queue
(
mDisplay
->
wl_display
());
151
QObject
::
connect
(
mDisplay
, &
QWaylandDisplay
::
connected
,
window
, [
this
]() {
152
auto
oldEventQueue
=
mEventQueue
;
153
mEventQueue
=
wl_display_create_queue
(
mDisplay
->
wl_display
());
154
auto
copy
=
mBuffers
;
155
// clear available buffers so we create new ones
156
// actual deletion is deferred till after resize call so we can copy
157
// contents from the back buffer
158
mBuffers
.
clear
();
159
mFrontBuffer
=
nullptr
;
160
// recreateBackBufferIfNeeded always resets mBackBuffer
161
if
(
mRequestedSize
.
isValid
() &&
waylandWindow
())
162
recreateBackBufferIfNeeded
();
163
else
164
mBackBuffer
=
nullptr
;
165
qDeleteAll
(
copy
);
166
wl_event_queue_destroy
(
oldEventQueue
);
167
});
168
}
169
170
QWaylandShmBackingStore
::~
QWaylandShmBackingStore
()
171
{
172
if
(
QWaylandWindow
*
w
=
waylandWindow
())
173
w
->
setBackingStore
(
nullptr
);
174
175
// if (mFrontBuffer == waylandWindow()->attached())
176
// waylandWindow()->attach(0);
177
178
qDeleteAll
(
mBuffers
);
179
wl_event_queue_destroy
(
mEventQueue
);
180
}
181
182
QPaintDevice
*
QWaylandShmBackingStore
::
paintDevice
()
183
{
184
return
contentSurface
();
185
}
186
187
void
QWaylandShmBackingStore
::
updateDirtyStates
(
const
QRegion
&
region
)
188
{
189
// Update dirty state of buffers based on what was painted. The back buffer will be
190
// less dirty, since we painted to it, while other buffers will become more dirty.
191
// This allows us to minimize copies between front and back buffers on swap in the
192
// cases where the painted region overlaps with the previous frame (front buffer).
193
for
(
QWaylandShmBuffer
*
b
:
std
::
as_const
(
mBuffers
)) {
194
if
(
b
!=
mBackBuffer
)
195
b
->
dirtyRegion
() +=
region
;
196
else
197
b
->
dirtyRegion
() -=
region
;
198
}
199
}
200
201
void
QWaylandShmBackingStore
::
beginPaint
(
const
QRegion
&
region
)
202
{
203
mPainting
=
true
;
204
waylandWindow
()->
setBackingStore
(
this
);
205
206
const
QMargins
margins
=
windowDecorationMargins
();
207
const
QRegion
regionTranslated
=
region
.
translated
(
margins
.
left
(),
margins
.
top
());
208
const
bool
bufferWasRecreated
=
recreateBackBufferIfNeeded
();
209
updateDirtyStates
(
regionTranslated
);
210
211
// Although undocumented, QBackingStore::beginPaint expects the painted region
212
// to be cleared before use if the window has a surface format with an alpha.
213
// Fresh QWaylandShmBuffer are already cleared, so we don't need to clear those.
214
if
(!
bufferWasRecreated
&&
window
()->
format
().
hasAlpha
()) {
215
QPainter
p
(
paintDevice
());
216
p
.
setCompositionMode
(
QPainter
::
CompositionMode_Source
);
217
const
QColor
blank
=
Qt
::
transparent
;
218
for
(
const
QRect
&
rect
:
region
)
219
p
.
fillRect
(
rect
,
blank
);
220
}
221
}
222
223
void
QWaylandShmBackingStore
::
endPaint
()
224
{
225
mPainting
=
false
;
226
if
(
mPendingFlush
)
227
flush
(
window
(),
mPendingRegion
,
QPoint
());
228
}
229
230
// Inspired by QCALayerBackingStore.
231
bool
QWaylandShmBackingStore
::
scroll
(
const
QRegion
&
region
,
int
dx
,
int
dy
)
232
{
233
if
(
Q_UNLIKELY
(!
mBackBuffer
))
234
return
false
;
235
236
const
qreal
devicePixelRatio
=
waylandWindow
()->
scale
();
237
238
// On Wayland, the window can have a device pixel ratio different from
239
// the window/screen, therefore we cannot rely on QHighDpi here, cf. QBackingStore::scroll.
240
// With fractional scaling we cannot easily scroll the existing pixels.
241
if
(!
qFuzzyIsNull
(
devicePixelRatio
-
static_cast
<
int
>(
devicePixelRatio
)))
242
return
false
;
243
244
recreateBackBufferIfNeeded
();
245
if
(!
mFrontBuffer
)
246
return
false
;
247
248
const
QPoint
scrollDelta
(
dx
,
dy
);
249
const
QMargins
margins
=
windowDecorationMargins
();
250
const
QRegion
adjustedRegion
=
region
.
translated
(
margins
.
left
(),
margins
.
top
());
251
252
const
QRegion
inPlaceRegion
=
adjustedRegion
-
mBackBuffer
->
dirtyRegion
();
253
const
QRegion
frontBufferRegion
=
adjustedRegion
-
inPlaceRegion
;
254
255
if
(!
inPlaceRegion
.
isEmpty
()) {
256
const
QRect
inPlaceBoundingRect
=
inPlaceRegion
.
boundingRect
();
257
const
QPoint
devicePixelDelta
=
scrollDelta
*
devicePixelRatio
;
258
259
qt_scrollRectInImage
(*
mBackBuffer
->
image
(),
260
QRect
(
inPlaceBoundingRect
.
topLeft
() *
devicePixelRatio
,
261
inPlaceBoundingRect
.
size
() *
devicePixelRatio
),
262
devicePixelDelta
);
263
}
264
265
if
(!
frontBufferRegion
.
isEmpty
()) {
266
QPainter
painter
(
mBackBuffer
->
image
());
267
painter
.
setCompositionMode
(
QPainter
::
CompositionMode_Source
);
268
painter
.
scale
(
qreal
(1) /
devicePixelRatio
,
qreal
(1) /
devicePixelRatio
);
269
for
(
const
QRect
&
rect
:
frontBufferRegion
) {
270
QRect
sourceRect
(
rect
.
topLeft
() *
devicePixelRatio
,
271
rect
.
size
() *
devicePixelRatio
);
272
QRect
destinationRect
((
rect
.
topLeft
() +
scrollDelta
) *
devicePixelRatio
,
273
rect
.
size
() *
devicePixelRatio
);
274
painter
.
drawImage
(
destinationRect
, *
mFrontBuffer
->
image
(),
sourceRect
);
275
}
276
}
277
278
// We do not mark the source region as dirty, even though it technically has "moved".
279
// This matches the behavior of other backingstore implementations using qt_scrollRectInImage.
280
updateDirtyStates
(
adjustedRegion
.
translated
(
scrollDelta
));
281
282
return
true
;
283
}
284
285
void
QWaylandShmBackingStore
::
flush
(
QWindow
*
window
,
const
QRegion
&
region
,
const
QPoint
&
offset
)
286
{
287
// Invoked when the window is of type RasterSurface.
288
289
if
(
window
!=
this
->
window
()) {
290
auto
waylandWindow
=
static_cast
<
QWaylandWindow
*>(
window
->
handle
());
291
const
auto
scale
=
waylandWindow
->
scale
();
292
auto
newBuffer
=
new
QWaylandShmBuffer
(
293
mDisplay
,
window
->
size
() *
scale
,
mBackBuffer
->
image
()->
format
(),
294
mBackBuffer
->
image
()->
devicePixelRatio
());
295
newBuffer
->
setDeleteOnRelease
(
true
);
296
QRect
sourceRect
(
offset
*
scale
,
window
->
size
() *
scale
);
297
QPainter
painter
(
newBuffer
->
image
());
298
painter
.
drawImage
(
QPoint
(0, 0), *
mBackBuffer
->
image
(),
sourceRect
);
299
waylandWindow
->
safeCommit
(
newBuffer
,
region
);
300
return
;
301
}
302
303
if
(
mPainting
) {
304
mPendingRegion
|=
region
;
305
mPendingFlush
=
true
;
306
return
;
307
}
308
309
mPendingFlush
=
false
;
310
mPendingRegion
=
QRegion
();
311
312
if
(
windowDecoration
() &&
windowDecoration
()->
isDirty
())
313
updateDecorations
();
314
315
finalizeBackBuffer
();
316
317
mFrontBuffer
=
mBackBuffer
;
318
319
QMargins
margins
=
windowDecorationMargins
();
320
waylandWindow
()->
safeCommit
(
mFrontBuffer
,
region
.
translated
(
margins
.
left
(),
margins
.
top
()));
321
}
322
323
void
QWaylandShmBackingStore
::
resize
(
const
QSize
&
size
,
const
QRegion
&)
324
{
325
mRequestedSize
=
size
;
326
}
327
328
QWaylandShmBuffer
*
QWaylandShmBackingStore
::
getBuffer
(
const
QSize
&
size
,
bool
&
bufferWasRecreated
)
329
{
330
static
const
int
MAX_BUFFERS
= 5;
331
static
const
int
MAX_AGE
= 10 *
MAX_BUFFERS
;
332
bufferWasRecreated
=
false
;
333
334
// Prune buffers that have not been used in a while or with different size.
335
for
(
auto
i
=
mBuffers
.
size
() - 1;
i
>= 0; --
i
) {
336
QWaylandShmBuffer
*
buffer
=
mBuffers
[
i
];
337
if
(
buffer
->
age
() >
MAX_AGE
||
buffer
->
size
() !=
size
) {
338
mBuffers
.
removeAt
(
i
);
339
if
(
mBackBuffer
==
buffer
)
340
mBackBuffer
=
nullptr
;
341
if
(
mFrontBuffer
==
buffer
)
342
mFrontBuffer
=
nullptr
;
343
delete
buffer
;
344
}
345
}
346
347
QWaylandShmBuffer
*
buffer
=
nullptr
;
348
for
(
QWaylandShmBuffer
*
candidate
:
std
::
as_const
(
mBuffers
)) {
349
if
(
candidate
->
busy
())
350
continue
;
351
352
if
(!
buffer
||
candidate
->
age
() <
buffer
->
age
())
353
buffer
=
candidate
;
354
}
355
356
if
(
buffer
)
357
return
buffer
;
358
359
if
(
mBuffers
.
size
() <
MAX_BUFFERS
) {
360
QImage
::
Format
format
=
QImage
::
Format_ARGB32_Premultiplied
;
361
if
(!
waylandWindow
()->
format
().
hasAlpha
())
362
format
=
QImage
::
Format_RGB32
;
363
QWaylandShmBuffer
*
b
=
new
QWaylandShmBuffer
(
mDisplay
,
size
,
format
,
waylandWindow
()->
scale
(),
mEventQueue
);
364
bufferWasRecreated
=
true
;
365
mBuffers
.
push_front
(
b
);
366
return
b
;
367
}
368
return
nullptr
;
369
}
370
371
bool
QWaylandShmBackingStore
::
recreateBackBufferIfNeeded
()
372
{
373
wl_display_dispatch_queue_pending
(
mDisplay
->
wl_display
(),
mEventQueue
);
374
375
bool
bufferWasRecreated
=
false
;
376
QMargins
margins
=
windowDecorationMargins
();
377
qreal
scale
=
waylandWindow
()->
scale
();
378
const
QSize
sizeWithMargins
= (
mRequestedSize
+
QSize
(
margins
.
left
() +
margins
.
right
(),
margins
.
top
() +
margins
.
bottom
())) *
scale
;
379
380
// We look for a free buffer to draw into. If the buffer is not the last buffer we used,
381
// that is mBackBuffer, and the size is the same we copy the damaged content into the new
382
// buffer so that QPainter is happy to find the stuff it had drawn before. If the new
383
// buffer has a different size it needs to be redrawn completely anyway, and if the buffer
384
// is the same the stuff is there already.
385
// You can exercise the different codepaths with weston, switching between the gl and the
386
// pixman renderer. With the gl renderer release events are sent early so we can effectively
387
// run single buffered, while with the pixman renderer we have to use two.
388
QWaylandShmBuffer
*
buffer
=
getBuffer
(
sizeWithMargins
,
bufferWasRecreated
);
389
while
(!
buffer
) {
390
struct
::
wl_display
*
display
=
mDisplay
->
wl_display
();
391
if
(
wl_display_dispatch_queue
(
display
,
mEventQueue
) < 0) {
392
int
ecode
=
wl_display_get_error
(
display
);
393
if
((
ecode
==
EPIPE
||
ecode
==
ECONNRESET
))
394
qWarning
(
"The Wayland connection broke during blocking read event. Did the Wayland compositor die?"
);
395
else
396
qWarning
(
"The Wayland connection experienced a fatal error during blocking read event: %s"
,
strerror
(
ecode
));
397
_exit
(-1);
398
}
399
buffer
=
getBuffer
(
sizeWithMargins
,
bufferWasRecreated
);
400
}
401
402
qsizetype
oldSizeInBytes
=
mBackBuffer
?
mBackBuffer
->
image
()->
sizeInBytes
() : 0;
403
qsizetype
newSizeInBytes
=
buffer
->
image
()->
sizeInBytes
();
404
405
mBackBuffer
=
buffer
;
406
407
for
(
QWaylandShmBuffer
*
buffer
:
std
::
as_const
(
mBuffers
)) {
408
if
(
mBackBuffer
==
buffer
) {
409
buffer
->
setAge
(0);
410
}
else
{
411
buffer
->
setAge
(
buffer
->
age
() + 1);
412
}
413
}
414
415
if
(
windowDecoration
() &&
window
()->
isVisible
() &&
oldSizeInBytes
!=
newSizeInBytes
)
416
windowDecoration
()->
update
();
417
418
return
bufferWasRecreated
;
419
}
420
421
void
QWaylandShmBackingStore
::
finalizeBackBuffer
()
422
{
423
Q_ASSERT
(
mBackBuffer
);
424
425
const
QRegion
clipRegion
=
mBackBuffer
->
dirtyRegion
();
426
if
(
clipRegion
.
isEmpty
())
427
return
;
428
429
if
(
Q_UNLIKELY
(!
mFrontBuffer
||
mFrontBuffer
==
mBackBuffer
))
430
return
;
431
432
const
QImage
*
sourceImage
=
mFrontBuffer
->
image
();
433
QImage
*
targetImage
=
mBackBuffer
->
image
();
434
435
QPainter
painter
(
targetImage
);
436
painter
.
setCompositionMode
(
QPainter
::
CompositionMode_Source
);
437
const
qreal
targetDevicePixelRatio
=
painter
.
device
()->
devicePixelRatio
();
438
const
auto
clipRects
=
clipRegion
.
rects
();
439
for
(
const
QRect
&
clipRect
:
clipRects
) {
// Iterate clip rects, because complicated clip region causes higher CPU usage
440
if
(
clipRects
.
size
() > 1)
441
painter
.
save
();
442
painter
.
setClipRect
(
clipRect
);
443
painter
.
scale
(
qreal
(1) /
targetDevicePixelRatio
,
qreal
(1) /
targetDevicePixelRatio
);
444
painter
.
drawImage
(
QRectF
(
QPointF
(),
targetImage
->
size
()), *
sourceImage
,
sourceImage
->
rect
());
445
if
(
clipRects
.
size
() > 1)
446
painter
.
restore
();
447
}
448
449
mBackBuffer
->
dirtyRegion
() =
QRegion
();
450
}
451
452
QImage
*
QWaylandShmBackingStore
::
entireSurface
()
const
453
{
454
return
mBackBuffer
->
image
();
455
}
456
457
QImage
*
QWaylandShmBackingStore
::
contentSurface
()
const
458
{
459
return
windowDecoration
() ?
mBackBuffer
->
imageInsideMargins
(
windowDecorationMargins
()) :
mBackBuffer
->
image
();
460
}
461
462
void
QWaylandShmBackingStore
::
updateDecorations
()
463
{
464
QPainter
decorationPainter
(
entireSurface
());
465
decorationPainter
.
setCompositionMode
(
QPainter
::
CompositionMode_Source
);
466
QImage
sourceImage
=
windowDecoration
()->
contentImage
();
467
468
qreal
dp
=
sourceImage
.
devicePixelRatio
();
469
int
dpWidth
=
int
(
sourceImage
.
width
() /
dp
);
470
int
dpHeight
=
int
(
sourceImage
.
height
() /
dp
);
471
QTransform
sourceMatrix
;
472
sourceMatrix
.
scale
(
dp
,
dp
);
473
QRect
target
;
// needs to be in device independent pixels
474
QRegion
dirtyRegion
;
475
476
//Top
477
target
.
setX
(0);
478
target
.
setY
(0);
479
target
.
setWidth
(
dpWidth
);
480
target
.
setHeight
(
windowDecorationMargins
().
top
());
481
decorationPainter
.
drawImage
(
target
,
sourceImage
,
sourceMatrix
.
mapRect
(
target
));
482
dirtyRegion
+=
target
;
483
484
//Left
485
target
.
setWidth
(
windowDecorationMargins
().
left
());
486
target
.
setHeight
(
dpHeight
);
487
decorationPainter
.
drawImage
(
target
,
sourceImage
,
sourceMatrix
.
mapRect
(
target
));
488
dirtyRegion
+=
target
;
489
490
//Right
491
target
.
setX
(
dpWidth
-
windowDecorationMargins
().
right
());
492
target
.
setWidth
(
windowDecorationMargins
().
right
());
493
decorationPainter
.
drawImage
(
target
,
sourceImage
,
sourceMatrix
.
mapRect
(
target
));
494
dirtyRegion
+=
target
;
495
496
//Bottom
497
target
.
setX
(0);
498
target
.
setY
(
dpHeight
-
windowDecorationMargins
().
bottom
());
499
target
.
setWidth
(
dpWidth
);
500
target
.
setHeight
(
windowDecorationMargins
().
bottom
());
501
decorationPainter
.
drawImage
(
target
,
sourceImage
,
sourceMatrix
.
mapRect
(
target
));
502
dirtyRegion
+=
target
;
503
504
updateDirtyStates
(
dirtyRegion
);
505
}
506
507
QWaylandAbstractDecoration
*
QWaylandShmBackingStore
::
windowDecoration
()
const
508
{
509
return
waylandWindow
()->
decoration
();
510
}
511
512
QMargins
QWaylandShmBackingStore
::
windowDecorationMargins
()
const
513
{
514
if
(
windowDecoration
())
515
return
windowDecoration
()->
margins
();
516
return
QMargins
();
517
}
518
519
QWaylandWindow
*
QWaylandShmBackingStore
::
waylandWindow
()
const
520
{
521
return
static_cast
<
QWaylandWindow
*>(
window
()->
handle
());
522
}
523
524
#
if
QT_CONFIG
(
opengl
)
525
QImage
QWaylandShmBackingStore
::
toImage
()
const
526
{
527
// Invoked from QPlatformBackingStore::composeAndFlush() that is called
528
// instead of flush() for widgets that have renderToTexture children
529
// (QOpenGLWidget, QQuickWidget).
530
531
const_cast
<
QWaylandShmBackingStore
*>(
this
)->
finalizeBackBuffer
();
532
533
return
*
contentSurface
();
534
}
535
#
endif
// opengl
536
537
}
538
539
QT_END_NAMESPACE
QtWaylandClient
Definition
qwaylandclientextension.h:16
MAP_FAILED
#define MAP_FAILED
Definition
qresource.cpp:1158
qt_scrollRectInImage
QT_BEGIN_NAMESPACE void qt_scrollRectInImage(QImage &, const QRect &, const QPoint &)
Definition
qbackingstore.cpp:301
qtbase
src
plugins
platforms
wayland
qwaylandshmbackingstore.cpp
Generated on
for Qt by
1.16.1