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