Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qwaylanddisplay.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// Copyright (C) 2024 Jie Liu <liujie01@kylinos.cn>
3
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
// Qt-Security score:significant reason:default
5
6
#
include
"qwaylanddisplay_p.h"
7
8
#
include
"qwaylandappmenu_p.h"
9
#
include
"qwaylandintegration_p.h"
10
#
include
"qwaylandwindow_p.h"
11
#
include
"qwaylandsurface_p.h"
12
#
include
"qwaylandabstractdecoration_p.h"
13
#
include
"qwaylandscreen_p.h"
14
#
include
"qwaylandcursor_p.h"
15
#
include
"qwaylandinputdevice_p.h"
16
#
if
QT_CONFIG
(
clipboard
)
17
#
include
"qwaylandclipboard_p.h"
18
#
include
"qwaylanddatacontrolv1_p.h"
19
#
endif
20
#
if
QT_CONFIG
(
wayland_datadevice
)
21
#
include
"qwaylanddatadevicemanager_p.h"
22
#
include
"qwaylanddatadevice_p.h"
23
#
endif
// QT_CONFIG(wayland_datadevice)
24
#
if
QT_CONFIG
(
wayland_client_primary_selection
)
25
#
include
"qwaylandprimaryselectionv1_p.h"
26
#
endif
// QT_CONFIG(wayland_client_primary_selection)
27
#
if
QT_CONFIG
(
cursor
)
28
#
include
<
wayland
-
cursor
.
h
>
29
#
endif
30
#
include
"qwaylandhardwareintegration_p.h"
31
#
include
"qwaylandtextinputv1_p.h"
32
#
include
"qwaylandtextinputv2_p.h"
33
#
include
"qwaylandtextinputv3_p.h"
34
#
include
"qwaylandinputcontext_p.h"
35
#
include
"qwaylandinputmethodcontext_p.h"
36
37
#
include
"qwaylandwindowmanagerintegration_p.h"
38
#
include
"qwaylandshellintegration_p.h"
39
#
include
"qwaylandclientbufferintegration_p.h"
40
41
#
include
"qwaylandpointergestures_p.h"
42
#
include
"qwaylandsubsurface_p.h"
43
#
if
QT_CONFIG
(
tabletevent
)
44
#
include
"qwaylandtabletv2_p.h"
45
#
endif
46
47
#
include
"qwaylandcolormanagement_p.h"
48
49
#
include
<
QtWaylandClient
/
private
/
qwayland
-
text
-
input
-
unstable
-
v1
.
h
>
50
#
include
<
QtWaylandClient
/
private
/
qwayland
-
text
-
input
-
unstable
-
v2
.
h
>
51
#
include
<
QtWaylandClient
/
private
/
qwayland
-
text
-
input
-
unstable
-
v3
.
h
>
52
#
include
<
QtWaylandClient
/
private
/
qwayland
-
wp
-
primary
-
selection
-
unstable
-
v1
.
h
>
53
#
include
<
QtWaylandClient
/
private
/
qwayland
-
qt
-
text
-
input
-
method
-
unstable
-
v1
.
h
>
54
#
include
<
QtWaylandClient
/
private
/
qwayland
-
fractional
-
scale
-
v1
.
h
>
55
#
include
<
QtWaylandClient
/
private
/
qwayland
-
viewporter
.
h
>
56
#
include
<
QtWaylandClient
/
private
/
qwayland
-
cursor
-
shape
-
v1
.
h
>
57
#
include
<
QtWaylandClient
/
private
/
qwayland
-
xdg
-
session
-
management
-
v1
.
h
>
58
#
include
<
QtWaylandClient
/
private
/
qwayland
-
xdg
-
system
-
bell
-
v1
.
h
>
59
#
include
<
QtWaylandClient
/
private
/
qwayland
-
xdg
-
toplevel
-
drag
-
v1
.
h
>
60
#
include
<
QtWaylandClient
/
private
/
qwayland
-
wlr
-
data
-
control
-
unstable
-
v1
.
h
>
61
#
include
<
QtWaylandClient
/
private
/
qwayland
-
pointer
-
warp
-
v1
.
h
>
62
#
include
<
QtWaylandClient
/
private
/
qwayland
-
xx
-
cutouts
-
v1
.
h
>
63
64
#
include
<
QtCore
/
private
/
qcore_unix_p
.
h
>
65
66
#
include
<
QtCore
/
QAbstractEventDispatcher
>
67
#
include
<
QtGui
/
qpa
/
qwindowsysteminterface
.
h
>
68
#
include
<
QtGui
/
private
/
qguiapplication_p
.
h
>
69
70
#
include
<
QtCore
/
QDebug
>
71
72
#
include
<
errno
.
h
>
73
74
#
include
<
tuple
>
// for std::tie
75
76
QT_BEGIN_NAMESPACE
77
78
namespace
QtWaylandClient
{
79
80
class
EventThread
:
public
QThread
81
{
82
Q_OBJECT
83
public
:
84
enum
OperatingMode
{
85
EmitToDispatch
,
// Emit the signal, allow dispatching in a differnt thread.
86
SelfDispatch
,
// Dispatch the events inside this thread.
87
};
88
89
EventThread
(
struct
wl_display *
wl
,
90
struct
wl_event_queue * ev_queue,
91
OperatingMode mode,
92
QObject *parent =
nullptr
)
93
: QThread(parent)
94
, m_fd(wl_display_get_fd(wl))
95
, m_pipefd{ -1, -1 }
96
, m_wldisplay(wl)
97
, m_wlevqueue(ev_queue)
98
, m_mode(mode)
99
, m_reading(
true
)
100
, m_quitting(
false
)
101
{
102
setObjectName(QStringLiteral(
"WaylandEventThread"
));
103
104
// The pipe lets stop() interrupt the poll() in run(), which would otherwise never
105
// return once the compositor stops sending events.
106
if
(qt_safe_pipe(m_pipefd) != 0)
107
qErrnoWarning(
"Pipe creation failed. Quitting may hang."
);
108
}
109
110
~
EventThread
()
override
111
{
112
// run()'s poll() uses the pipe, so the thread must be stopped by now.
113
Q_ASSERT(!isRunning());
114
115
if
(m_pipefd[0] != -1) {
116
qt_safe_close(m_pipefd[0]);
117
qt_safe_close(m_pipefd[1]);
118
}
119
}
120
121
void
readAndDispatchEvents
()
122
{
123
/*
124
* Dispatch pending events and flush the requests at least once. If the event thread
125
* is not reading, try to call _prepare_read() to allow the event thread to poll().
126
* If that fails, re-try dispatch & flush again until _prepare_read() is successful.
127
*
128
* This allow any call to readAndDispatchEvents() to start event thread's polling,
129
* not only the one issued from event thread's waitForReading(), which means functions
130
* called from dispatch_pending() can safely spin an event loop.
131
*/
132
if
(m_quitting.loadRelaxed())
133
return
;
134
135
for
(;;) {
136
if
(dispatchQueuePending() < 0) {
137
Q_EMIT waylandError();
138
QMutexLocker lock(&m_mutex);
139
m_quitting.storeRelaxed(
true
);
140
m_cond.wakeOne();
141
return
;
142
}
143
144
wl_display_flush(m_wldisplay);
145
146
// We have to check if event thread is reading every time we dispatch
147
// something, as that may recursively call this function.
148
if
(m_reading.loadAcquire())
149
break
;
150
151
if
(prepareReadQueue() == 0) {
152
QMutexLocker l(&m_mutex);
153
m_reading.storeRelease(
true
);
154
m_cond.wakeOne();
155
break
;
156
}
157
}
158
}
159
160
void
stop
()
161
{
162
// We have to both write to the pipe and set the flag, as the thread may be
163
// either in the poll() or waiting for _prepare_read().
164
if
(m_pipefd[1] != -1 && qt_safe_write(m_pipefd[1],
"\0"
, 1) == -1)
165
qErrnoWarning(
"Failed to write to the pipe"
);
166
167
{
168
// The lock makes sure the event thread doesn't start waiting just after it
169
// checked m_quitting, which would make it miss the wakeOne() here.
170
QMutexLocker lock(&m_mutex);
171
m_quitting.storeRelaxed(
true
);
172
m_cond.wakeOne();
173
}
174
175
wait();
176
}
177
178
Q_SIGNALS
:
179
void
needReadAndDispatch
();
180
void
waylandError
();
181
182
protected
:
183
void
run
()
override
184
{
185
// Make the main thread call wl_prepare_read(), dispatch the pending messages and flush the
186
// outbound ones. Wait until it's done before proceeding, unless we're told to quit.
187
while
(waitForReading()) {
188
if
(!m_reading.loadRelaxed())
189
break
;
190
191
// m_pipefd[0] is what makes this poll() return when stop() is called.
192
pollfd fds[2] = { { m_fd, POLLIN, 0 }, { m_pipefd[0], POLLIN, 0 } };
193
poll(fds, 2, -1);
194
195
if
(fds[1].revents & POLLIN) {
196
// we don't really care to read the byte that was written here since we're closing down.
197
// The pending read is cancelled after the loop.
198
break
;
199
}
200
201
if
(fds[0].revents & POLLIN)
202
wl_display_read_events(m_wldisplay);
203
// The poll was succesfull and the event thread did the wl_display_read_events(). On the next iteration of the loop
204
// the event sent to the main thread will cause it to dispatch the messages just read, unless the loop exits in which
205
// case we don't care anymore about them.
206
else
207
wl_display_cancel_read(m_wldisplay);
208
}
209
210
// If a read was prepared (by us or by the main thread on our behalf) and we are
211
// exiting without consuming it, cancel it so that other readers are not blocked.
212
if
(m_reading.loadAcquire())
213
wl_display_cancel_read(m_wldisplay);
214
}
215
216
private
:
217
bool
waitForReading()
218
{
219
Q_ASSERT(isCurrentThread());
220
221
m_reading.storeRelease(
false
);
222
223
if
(m_mode == SelfDispatch) {
224
readAndDispatchEvents
(
)
;
225
}
else
{
226
Q_EMIT needReadAndDispatch();
227
228
QMutexLocker lock(&m_mutex);
229
// m_reading might be set from our emit or some other invocation of
230
// readAndDispatchEvents().
231
while
(!m_reading.loadRelaxed() && !m_quitting.loadRelaxed())
232
m_cond.wait(&m_mutex);
233
}
234
235
return
!m_quitting.loadRelaxed();
236
}
237
238
int
dispatchQueuePending()
239
{
240
if
(m_wlevqueue)
241
return
wl_display_dispatch_queue_pending(m_wldisplay, m_wlevqueue);
242
else
243
return
wl_display_dispatch_pending(m_wldisplay);
244
}
245
246
int
prepareReadQueue()
247
{
248
if
(m_wlevqueue)
249
return
wl_display_prepare_read_queue(m_wldisplay, m_wlevqueue);
250
else
251
return
wl_display_prepare_read(m_wldisplay);
252
}
253
254
int
m_fd;
255
int
m_pipefd[2];
// set in the constructor, closed in the destructor, constant in between
256
wl_display *m_wldisplay;
257
wl_event_queue *m_wlevqueue;
258
OperatingMode m_mode;
259
260
/* Concurrency note when operating in EmitToDispatch mode:
261
* m_reading is set to false inside event thread's waitForReading(), and is
262
* set to true inside main thread's readAndDispatchEvents().
263
* The lock is not taken when setting m_reading to false, as the main thread
264
* is not actively waiting for it to turn false. However, the lock is taken
265
* inside readAndDispatchEvents() before setting m_reading to true,
266
* as the event thread is actively waiting for it under the wait condition.
267
* m_quitting is set inside stop() and readAndDispatchEvents(), which both take the
268
* lock for the same reason: the event thread waits on it too.
269
*/
270
271
QAtomicInteger<
bool
> m_reading;
272
QAtomicInteger<
bool
> m_quitting;
273
QMutex m_mutex;
274
QWaitCondition m_cond;
275
};
276
277
Q_LOGGING_CATEGORY
(
lcQpaWayland
,
"qt.qpa.wayland"
);
// for general (uncategorized) Wayland platform logging
278
279
struct
wl_surface
*
QWaylandDisplay
::
createSurface
(
void
*
handle
)
280
{
281
struct
wl_surface
*
surface
=
mGlobals
.
compositor
->
create_surface
();
282
wl_surface_set_user_data
(
surface
,
handle
);
283
return
surface
;
284
}
285
286
struct
::wl_region *
QWaylandDisplay
::
createRegion
(
const
QRegion
&
qregion
)
287
{
288
struct
::
wl_region
*
region
=
mGlobals
.
compositor
->
create_region
();
289
290
for
(
const
QRect
&
rect
:
qregion
)
291
wl_region_add
(
region
,
rect
.
x
(),
rect
.
y
(),
rect
.
width
(),
rect
.
height
());
292
293
return
region
;
294
}
295
296
::
wl_subsurface
*
QWaylandDisplay
::
createSubSurface
(
QWaylandSurface
*
window
,
QWaylandSurface
*
parent
)
297
{
298
if
(!
mGlobals
.
subCompositor
) {
299
qCWarning
(
lcQpaWayland
) <<
"Can't create subsurface, not supported by the compositor."
;
300
return
nullptr
;
301
}
302
303
return
mGlobals
.
subCompositor
->
get_subsurface
(
window
->
object
(),
parent
->
object
());
304
}
305
306
::
wp_viewport
*
QWaylandDisplay
::
createViewport
(
QWaylandSurface
*
surface
)
307
{
308
if
(!
mGlobals
.
viewporter
) {
309
qCWarning
(
lcQpaWayland
) <<
"Can't create wp_viewport, not supported by the compositor."
;
310
return
nullptr
;
311
}
312
313
return
mGlobals
.
viewporter
->
get_viewport
(
surface
->
object
());
314
}
315
316
QWaylandShellIntegration
*
QWaylandDisplay
::
shellIntegration
()
const
317
{
318
return
mWaylandIntegration
->
shellIntegration
();
319
}
320
321
QWaylandClientBufferIntegration
*
QWaylandDisplay
::
clientBufferIntegration
()
const
322
{
323
return
mWaylandIntegration
->
clientBufferIntegration
();
324
}
325
326
QWaylandWindowManagerIntegration
*
QWaylandDisplay
::
windowManagerIntegration
()
const
327
{
328
return
mGlobals
.
windowManagerIntegration
.
get
();
329
}
330
331
QWaylandDisplay
::
QWaylandDisplay
(
QWaylandIntegration
*
waylandIntegration
,
QObject
*
parent
)
332
:
QObject
(
parent
)
333
,
mWaylandIntegration
(
waylandIntegration
)
334
{
335
qRegisterMetaType
<
uint32_t
>(
"uint32_t"
);
336
337
mDisplay
=
wl_display_connect
(
nullptr
);
338
if
(
mDisplay
) {
339
setupConnection
();
340
}
else
{
341
qErrnoWarning
(errno,
"Failed to create wl_display"
);
342
}
343
344
mWaylandTryReconnect
=
qEnvironmentVariableIsSet
(
"QT_WAYLAND_RECONNECT"
);
345
mPreferWlrDataControl
=
qEnvironmentVariableIntValue
(
"QT_WAYLAND_USE_DATA_CONTROL"
) > 0;
346
}
347
348
void
QWaylandDisplay
::
setupConnection
()
349
{
350
struct
::
wl_registry
*
registry
=
wl_display_get_registry
(
mDisplay
);
351
init
(
registry
);
352
353
#
if
QT_CONFIG
(
xkbcommon
)
354
mXkbContext
.
reset
(
xkb_context_new
(
XKB_CONTEXT_NO_FLAGS
));
355
if
(!
mXkbContext
)
356
qCWarning
(
lcQpaWayland
,
"failed to create xkb context"
);
357
#
endif
358
if
(
mWaylandInputContextRequested
)
359
checkTextInputProtocol
();
360
}
361
362
QWaylandDisplay
::~
QWaylandDisplay
(
void
)
363
{
364
if
(
m_eventThread
)
365
m_eventThread
->
stop
();
366
367
if
(
m_frameEventQueueThread
)
368
m_frameEventQueueThread
->
stop
();
369
370
if
(
mSyncCallback
)
371
wl_callback_destroy
(
mSyncCallback
);
372
373
qDeleteAll
(
std
::
exchange
(
mInputDevices
, {}));
374
375
for
(
QWaylandScreen
*
screen
:
std
::
exchange
(
mScreens
, {})) {
376
QWindowSystemInterface
::
handleScreenRemoved
(
screen
);
377
}
378
qDeleteAll
(
mWaitingScreens
);
379
380
#
if
QT_CONFIG
(
cursor
)
381
mCursorThemes
.
clear
();
382
#
endif
383
384
if
(
m_frameEventQueue
)
385
wl_event_queue_destroy
(
m_frameEventQueue
);
386
387
// Reset the globals manually since they need to be destroyed before the wl_display
388
mGlobals
= {};
389
390
if
(
object
()) {
391
if
(
mFixes
)
392
mFixes
->
destroy_registry
(
object
());
393
394
wl_registry_destroy
(
object
());
395
}
396
397
mFixes
.
reset
();
398
399
if
(
mDisplay
)
400
wl_display_disconnect
(
mDisplay
);
401
}
402
403
// Steps which is called just after constructor. This separates registry_global() out of the constructor
404
// so that factory functions in integration can be overridden.
405
bool
QWaylandDisplay
::
initialize
()
406
{
407
if
(!
isInitialized
())
408
return
false
;
409
410
forceRoundTrip
();
411
412
emit
connected
();
413
414
if
(!
mWaitingScreens
.
isEmpty
()) {
415
// Give wl_output.done and zxdg_output_v1.done events a chance to arrive
416
forceRoundTrip
();
417
}
418
if
(
mWaylandInputContextRequested
)
419
mTextInputManagerIndex
=
INT_MAX
;
420
421
return
qEnvironmentVariableIntValue
(
"QT_WAYLAND_DONT_CHECK_SHELL_INTEGRATION"
) ||
shellIntegration
();
422
}
423
424
void
QWaylandDisplay
::
ensureScreen
()
425
{
426
if
(!
mScreens
.
empty
() ||
mPlaceholderScreen
)
427
return
;
// There are real screens or we already have a fake one
428
429
qCInfo
(
lcQpaWayland
) <<
"There are no outputs - creating placeholder screen"
;
430
431
mPlaceholderScreen
=
new
QPlatformPlaceholderScreen
();
432
QWindowSystemInterface
::
handleScreenAdded
(
mPlaceholderScreen
);
433
Q_ASSERT
(!
QGuiApplication
::
screens
().
empty
());
434
}
435
436
void
QWaylandDisplay
::
reconnect
()
437
{
438
qCWarning
(
lcQpaWayland
) <<
"Attempting wayland reconnect"
;
439
m_eventThread
->
stop
();
440
m_frameEventQueueThread
->
stop
();
441
m_eventThread
->
wait
();
442
m_frameEventQueueThread
->
wait
();
443
444
qDeleteAll
(
mWaitingScreens
);
445
mWaitingScreens
.
clear
();
446
447
while
(!
mScreens
.
isEmpty
()) {
448
auto
screen
=
mScreens
.
takeLast
();
449
ensureScreen
();
450
QWindowSystemInterface
::
handleScreenRemoved
(
screen
);
451
}
452
453
mCursorThemes
.
clear
();
454
mCursor
.
reset
();
455
456
mGlobals
=
GlobalHolder
();
457
458
mWaylandIntegration
->
reset
();
459
460
qDeleteAll
(
std
::
exchange
(
mInputDevices
, {}));
461
mLastInputDevice
=
nullptr
;
462
463
for
(
const
RegistryGlobal
&
global
:
mRegistryGlobals
) {
464
emit
globalRemoved
(
global
);
465
}
466
mRegistryGlobals
.
clear
();
467
468
mLastInputSerial
= 0;
469
mLastInputSurface
.
clear
();
470
mLastKeyboardFocus
.
clear
();
471
mActiveWindows
.
clear
();
472
mActiveSubSurface
.
clear
();
473
474
const
auto
windows
=
QGuiApplication
::
allWindows
();
475
QList
<
QWaylandWindow
*>
allPlatformWindows
;
476
for
(
auto
window
:
windows
) {
477
if
(
auto
waylandWindow
=
static_cast
<
QWaylandWindow
*>(
window
->
handle
())) {
478
waylandWindow
->
closeChildPopups
();
479
allPlatformWindows
.
push_back
(
waylandWindow
);
480
}
481
}
482
483
// Remove windows that do not need to be recreated and now closed popups
484
QList
<
QWaylandWindow
*>
recreateWindows
;
485
for
(
auto
window
:
std
::
as_const
(
allPlatformWindows
)) {
486
if
(
window
->
subSurfaceWindow
() ||
window
->
shellSurface
()) {
487
recreateWindows
.
push_back
(
window
);
488
}
489
window
->
reset
();
490
}
491
492
if
(
mSyncCallback
) {
493
wl_callback_destroy
(
mSyncCallback
);
494
mSyncCallback
=
nullptr
;
495
}
496
497
if
(
object
()) {
498
if
(
mFixes
)
499
mFixes
->
destroy_registry
(
object
());
500
501
wl_registry_destroy
(
object
());
502
}
503
504
mFixes
.
reset
();
505
506
mDisplay
=
wl_display_connect
(
nullptr
);
507
if
(!
mDisplay
)
508
_exit
(1);
509
510
QMetaObject
::
Connection
connection
=
511
connect
(
512
this
, &
QWaylandDisplay
::
connected
,
this
,
513
[
this
, &
allPlatformWindows
] {
514
for
(
auto
&
window
:
std
::
as_const
(
allPlatformWindows
)) {
515
window
->
initializeWlSurface
(
false
);
516
}
517
forceRoundTrip
();
// we need a roundtrip to receive the color space features the compositor supports
518
for
(
auto
&
window
:
std
::
as_const
(
allPlatformWindows
)) {
519
window
->
initializeColorSpace
();
520
}
521
},
522
Qt
::
SingleShotConnection
);
523
524
setupConnection
();
525
526
if
(
m_frameEventQueue
)
527
wl_event_queue_destroy
(
m_frameEventQueue
);
528
initEventThread
();
529
530
initialize
();
531
532
auto
needsRecreate
= [](
QPlatformWindow
*
window
) {
533
auto
waylandWindow
=
static_cast
<
QWaylandWindow
*>(
window
);
534
return
waylandWindow
&& !
waylandWindow
->
subSurfaceWindow
() && !
waylandWindow
->
shellSurface
();
535
};
536
auto
window
=
recreateWindows
.
begin
();
537
while
(!
recreateWindows
.
isEmpty
()) {
538
if
(!
needsRecreate
((*
window
)->
QPlatformWindow
::
parent
()) && !
needsRecreate
((*
window
)->
transientParent
())) {
539
(*
window
)->
reinit
();
540
window
=
recreateWindows
.
erase
(
window
);
541
}
else
{
542
++
window
;
543
}
544
if
(
window
==
recreateWindows
.
end
())
545
window
=
recreateWindows
.
begin
();
546
}
547
548
mWaylandIntegration
->
reconfigureInputContext
();
549
550
// Failsafe: Make sure we don't have a lingering connection referencing local variables
551
// (This will have been executed and disconnected in initialize())
552
disconnect
(
connection
);
553
}
554
555
void
QWaylandDisplay
::
flushRequests
()
556
{
557
m_eventThread
->
readAndDispatchEvents
();
558
}
559
560
// We have to wait until we have an eventDispatcher before creating the eventThread,
561
// otherwise forceRoundTrip() may block inside _events_read() because eventThread is
562
// polling.
563
void
QWaylandDisplay
::
initEventThread
()
564
{
565
m_eventThread
.
reset
(
566
new
EventThread
(
mDisplay
,
/* default queue */
nullptr
,
EventThread
::
EmitToDispatch
));
567
connect
(
m_eventThread
.
get
(), &
EventThread
::
needReadAndDispatch
,
this
,
568
&
QWaylandDisplay
::
flushRequests
,
Qt
::
QueuedConnection
);
569
connect
(
m_eventThread
.
get
(), &
EventThread
::
waylandError
,
this
,
570
&
QWaylandDisplay
::
checkWaylandError
,
Qt
::
QueuedConnection
);
571
m_eventThread
->
start
();
572
573
// wl_display_disconnect() free this.
574
m_frameEventQueue
=
wl_display_create_queue
(
mDisplay
);
575
m_frameEventQueueThread
.
reset
(
576
new
EventThread
(
mDisplay
,
m_frameEventQueue
,
EventThread
::
SelfDispatch
));
577
m_frameEventQueueThread
->
start
();
578
}
579
580
void
QWaylandDisplay
::
checkWaylandError
()
581
{
582
int
ecode
=
wl_display_get_error
(
mDisplay
);
583
if
((
ecode
== EPIPE ||
ecode
== ECONNRESET)) {
584
qWarning
(
"The Wayland connection broke. Did the Wayland compositor die?"
);
585
if
(
mWaylandTryReconnect
) {
586
reconnect
();
587
return
;
588
}
589
}
else
{
590
qWarning
(
"The Wayland connection experienced a fatal error: %s"
,
strerror
(
ecode
));
591
}
592
_exit
(-1);
593
}
594
595
void
QWaylandDisplay
::
checkTextInputProtocol
()
596
{
597
QStringList
tips
,
timps
;
// for text input protocols and text input manager protocols
598
// zwp_text_input_v2 is preferred over zwp_text_input_v3 because:
599
// - Currently, v3 is not as feature rich as v2.
600
// - While v2 is not upstreamed, it is well supported by KWin since Plasma 5 and Plasma
601
// Mobile uses some v2 only.
602
tips
<<
QLatin1String
(
QtWayland
::
qt_text_input_method_v1
::
interface
()->
name
)
603
<<
QLatin1String
(
QtWayland
::
zwp_text_input_v2
::
interface
()->
name
)
604
<<
QLatin1String
(
QtWayland
::
zwp_text_input_v3
::
interface
()->
name
)
605
<<
QLatin1String
(
QtWayland
::
zwp_text_input_v1
::
interface
()->
name
);
606
timps
<<
QLatin1String
(
QtWayland
::
qt_text_input_method_manager_v1
::
interface
()->
name
)
607
<<
QLatin1String
(
QtWayland
::
zwp_text_input_manager_v2
::
interface
()->
name
)
608
<<
QLatin1String
(
QtWayland
::
zwp_text_input_manager_v3
::
interface
()->
name
)
609
<<
QLatin1String
(
QtWayland
::
zwp_text_input_manager_v1
::
interface
()->
name
);
610
611
QString
tiProtocols
=
QString
::
fromLocal8Bit
(
qgetenv
(
"QT_WAYLAND_TEXT_INPUT_PROTOCOL"
));
612
qCDebug
(
lcQpaWayland
) <<
"QT_WAYLAND_TEXT_INPUT_PROTOCOL="
<<
tiProtocols
;
613
QStringList
keys
;
614
if
(!
tiProtocols
.
isEmpty
()) {
615
keys
=
tiProtocols
.
split
(
QLatin1Char
(
';'
));
616
QList
<
QString
>::
iterator
it
=
keys
.
begin
();
617
while
(
it
!=
keys
.
end
()) {
618
if
(
tips
.
contains
(*
it
))
619
mTextInputManagerList
.
append
(
timps
.
at
(
tips
.
indexOf
(*
it
)));
620
else
621
qCDebug
(
lcQpaWayland
) <<
"text input: unknown protocol - "
<< *
it
;
622
++
it
;
623
}
624
}
625
if
(
mTextInputManagerList
.
isEmpty
())
// fallback
626
mTextInputManagerList
=
timps
;
627
}
628
629
QWaylandScreen
*
QWaylandDisplay
::
screenForOutput
(
struct
wl_output *
output
)
const
630
{
631
for
(
auto
screen
:
std
::
as_const
(
mScreens
)) {
632
if
(
screen
->
output
() ==
output
)
633
return
screen
;
634
}
635
return
nullptr
;
636
}
637
638
void
QWaylandDisplay
::
handleScreenInitialized
(
QWaylandScreen
*
screen
)
639
{
640
if
(!
mWaitingScreens
.
removeOne
(
screen
))
641
return
;
642
mScreens
.
append
(
screen
);
643
QWindowSystemInterface
::
handleScreenAdded
(
screen
);
644
if
(
mPlaceholderScreen
) {
645
// handleScreenRemoved deletes the platform screen
646
QPlatformScreen
*
s
=
mPlaceholderScreen
;
647
mPlaceholderScreen
=
nullptr
;
648
QWindowSystemInterface
::
handleScreenRemoved
(
s
);
649
650
}
651
}
652
653
template
<
typename
T,
auto
f>
654
struct
WithDestructor
:
public
T
655
{
656
using
T::T;
657
~
WithDestructor
()
658
{
659
f(
this
->object());
660
}
661
662
private
:
663
Q_DISABLE_COPY
(
WithDestructor
)
664
};
665
666
void
QWaylandDisplay
::
registry_global
(
uint32_t
id
,
const
QString
&
interface
,
uint32_t
version
)
667
{
668
struct
::
wl_registry
*
registry
=
object
();
669
670
static
QStringList
interfaceBlacklist
=
qEnvironmentVariable
(
"QT_WAYLAND_DISABLED_INTERFACES"
).
split
(u',');
671
if
(
interfaceBlacklist
.
contains
(
interface
)) {
672
return
;
673
}
674
675
if
(
interface
==
QLatin1String
(
QtWayland
::
wl_output
::
interface
()->
name
)) {
676
mWaitingScreens
<<
mWaylandIntegration
->
createPlatformScreen
(
this
,
version
,
id
);
677
}
else
if
(
interface
==
QLatin1String
(
QtWayland
::
wl_compositor
::
interface
()->
name
)) {
678
mGlobals
.
compositor
.
reset
(
679
new
WithDestructor
<
QtWayland
::
wl_compositor
,
wl_compositor_destroy
>(
680
registry
,
id
,
qMin
((
int
)
version
, 6)));
681
}
else
if
(
interface
==
QLatin1String
(
QWaylandShm
::
interface
()->
name
)) {
682
mGlobals
.
shm
.
reset
(
new
QWaylandShm
(
this
,
version
,
id
));
683
}
else
if
(
interface
==
QLatin1String
(
QWaylandInputDevice
::
interface
()->
name
)) {
684
QWaylandInputDevice
*
inputDevice
=
mWaylandIntegration
->
createInputDevice
(
this
,
version
,
id
);
685
mInputDevices
.
append
(
inputDevice
);
686
#
if
QT_CONFIG
(
wayland_datadevice
)
687
}
else
if
(
interface
==
QLatin1String
(
QWaylandDataDeviceManager
::
interface
()->
name
)) {
688
mGlobals
.
dndSelectionHandler
.
reset
(
new
QWaylandDataDeviceManager
(
this
,
version
,
id
));
689
#
endif
690
}
else
if
(
interface
==
QLatin1String
(
QtWayland
::
wl_subcompositor
::
interface
()->
name
)) {
691
mGlobals
.
subCompositor
.
reset
(
692
new
WithDestructor
<
QtWayland
::
wl_subcompositor
,
wl_subcompositor_destroy
>(
registry
,
693
id
, 1));
694
#
if
QT_CONFIG
(
tabletevent
)
695
}
else
if
(
interface
==
QLatin1String
(
QWaylandTabletManagerV2
::
interface
()->
name
)) {
696
mGlobals
.
tabletManager
.
reset
(
new
QWaylandTabletManagerV2
(
this
,
id
,
qMin
(1,
int
(
version
))));
697
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
698
inputDevice
->
setTabletSeat
(
699
new
QWaylandTabletSeatV2
(
mGlobals
.
tabletManager
.
get
(),
inputDevice
));
700
#
endif
701
}
else
if
(
interface
==
QLatin1String
(
QWaylandPointerGestures
::
interface
()->
name
)) {
702
mGlobals
.
pointerGestures
.
reset
(
new
QWaylandPointerGestures
(
this
,
id
, 1));
703
#
if
QT_CONFIG
(
wayland_client_primary_selection
)
704
}
else
if
(
interface
==
QLatin1String
(
QWaylandPrimarySelectionDeviceManagerV1
::
interface
()->
name
)) {
705
mGlobals
.
primarySelectionManager
.
reset
(
706
new
QWaylandPrimarySelectionDeviceManagerV1
(
this
,
id
, 1));
707
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
708
inputDevice
->
setPrimarySelectionDevice
(
709
mGlobals
.
primarySelectionManager
->
createDevice
(
inputDevice
));
710
#
endif
711
}
else
if
(
interface
==
QLatin1String
(
QtWayland
::
qt_text_input_method_manager_v1
::
interface
()->
name
)
712
&& (
mTextInputManagerList
.
contains
(
interface
) &&
mTextInputManagerList
.
indexOf
(
interface
) <
mTextInputManagerIndex
)) {
713
qCDebug
(
lcQpaWayland
) <<
"text input: register qt_text_input_method_manager_v1"
;
714
if
(
mTextInputManagerIndex
<
INT_MAX
) {
715
mGlobals
.
textInputManagerv1
.
reset
();
716
mGlobals
.
textInputManagerv2
.
reset
();
717
mGlobals
.
textInputManagerv3
.
reset
();
718
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
719
inputDevice
->
setTextInput
(
nullptr
);
720
}
721
722
mGlobals
.
textInputMethodManager
.
reset
(
723
new
WithDestructor
<
QtWayland
::
qt_text_input_method_manager_v1
,
724
qt_text_input_method_manager_v1_destroy
>(
registry
,
id
, 1));
725
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
726
inputDevice
->
setTextInputMethod
(
new
QWaylandTextInputMethod
(
727
this
,
728
mGlobals
.
textInputMethodManager
->
get_text_input_method
(
729
inputDevice
->
wl_seat
())));
730
mWaylandIntegration
->
reconfigureInputContext
();
731
mTextInputManagerIndex
=
mTextInputManagerList
.
indexOf
(
interface
);
732
}
else
if
(
interface
==
QLatin1String
(
QtWayland
::
zwp_text_input_manager_v1
::
interface
()->
name
)
733
&& (
mTextInputManagerList
.
contains
(
interface
) &&
mTextInputManagerList
.
indexOf
(
interface
) <
mTextInputManagerIndex
)) {
734
qCDebug
(
lcQpaWayland
) <<
"text input: register zwp_text_input_v1"
;
735
if
(
mTextInputManagerIndex
<
INT_MAX
) {
736
mGlobals
.
textInputMethodManager
.
reset
();
737
mGlobals
.
textInputManagerv2
.
reset
();
738
mGlobals
.
textInputManagerv3
.
reset
();
739
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
740
inputDevice
->
setTextInputMethod
(
nullptr
);
741
}
742
743
mGlobals
.
textInputManagerv1
.
reset
(
744
new
WithDestructor
<
QtWayland
::
zwp_text_input_manager_v1
,
745
zwp_text_input_manager_v1_destroy
>(
registry
,
id
, 1));
746
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
)) {
747
auto
textInput
=
748
new
QWaylandTextInputv1
(
this
,
mGlobals
.
textInputManagerv1
->
create_text_input
());
749
textInput
->
setSeat
(
inputDevice
->
wl_seat
());
750
inputDevice
->
setTextInput
(
textInput
);
751
}
752
753
mWaylandIntegration
->
reconfigureInputContext
();
754
mTextInputManagerIndex
=
mTextInputManagerList
.
indexOf
(
interface
);
755
}
else
if
(
interface
==
QLatin1String
(
QtWayland
::
zwp_text_input_manager_v2
::
interface
()->
name
)
756
&& (
mTextInputManagerList
.
contains
(
interface
) &&
mTextInputManagerList
.
indexOf
(
interface
) <
mTextInputManagerIndex
)) {
757
qCDebug
(
lcQpaWayland
) <<
"text input: register zwp_text_input_v2"
;
758
if
(
mTextInputManagerIndex
<
INT_MAX
) {
759
mGlobals
.
textInputMethodManager
.
reset
();
760
mGlobals
.
textInputManagerv1
.
reset
();
761
mGlobals
.
textInputManagerv3
.
reset
();
762
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
763
inputDevice
->
setTextInputMethod
(
nullptr
);
764
}
765
766
mGlobals
.
textInputManagerv2
.
reset
(
767
new
WithDestructor
<
QtWayland
::
zwp_text_input_manager_v2
,
768
zwp_text_input_manager_v2_destroy
>(
registry
,
id
, 1));
769
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
770
inputDevice
->
setTextInput
(
new
QWaylandTextInputv2
(
771
this
,
mGlobals
.
textInputManagerv2
->
get_text_input
(
inputDevice
->
wl_seat
())));
772
mWaylandIntegration
->
reconfigureInputContext
();
773
mTextInputManagerIndex
=
mTextInputManagerList
.
indexOf
(
interface
);
774
}
else
if
(
interface
==
QLatin1String
(
QtWayland
::
zwp_text_input_manager_v3
::
interface
()->
name
)
775
&& (
mTextInputManagerList
.
contains
(
interface
) &&
mTextInputManagerList
.
indexOf
(
interface
) <
mTextInputManagerIndex
)) {
776
qCDebug
(
lcQpaWayland
) <<
"text input: register zwp_text_input_v3"
;
777
if
(
mTextInputManagerIndex
<
INT_MAX
) {
778
mGlobals
.
textInputMethodManager
.
reset
();
779
mGlobals
.
textInputManagerv2
.
reset
();
780
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
781
inputDevice
->
setTextInputMethod
(
nullptr
);
782
}
783
mGlobals
.
textInputManagerv3
.
reset
(
784
new
WithDestructor
<
QtWayland
::
zwp_text_input_manager_v3
,
785
zwp_text_input_manager_v3_destroy
>(
registry
,
id
,
std
::
min
(2u,
version
)));
786
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
787
inputDevice
->
setTextInput
(
new
QWaylandTextInputv3
(
788
this
,
mGlobals
.
textInputManagerv3
->
get_text_input
(
inputDevice
->
wl_seat
())));
789
790
mWaylandIntegration
->
reconfigureInputContext
();
791
mTextInputManagerIndex
=
mTextInputManagerList
.
indexOf
(
interface
);
792
}
else
if
(
interface
==
QLatin1String
(
QWaylandHardwareIntegration
::
interface
()->
name
)) {
793
bool
disableHardwareIntegration
=
qEnvironmentVariableIntValue
(
"QT_WAYLAND_DISABLE_HW_INTEGRATION"
);
794
if
(!
disableHardwareIntegration
) {
795
mGlobals
.
hardwareIntegration
.
reset
(
new
QWaylandHardwareIntegration
(
registry
,
id
));
796
// make a roundtrip here since we need to receive the events sent by
797
// qt_hardware_integration before creating windows
798
forceRoundTrip
();
799
}
800
}
else
if
(
interface
==
QLatin1String
(
QWaylandXdgOutputManagerV1
::
interface
()->
name
)) {
801
mGlobals
.
xdgOutputManager
.
reset
(
new
QWaylandXdgOutputManagerV1
(
this
,
id
,
version
));
802
for
(
auto
*
screen
:
std
::
as_const
(
mWaitingScreens
))
803
screen
->
initXdgOutput
(
xdgOutputManager
());
804
}
else
if
(
interface
==
QLatin1String
(
QtWayland
::
wp_fractional_scale_manager_v1
::
interface
()->
name
)) {
805
mGlobals
.
fractionalScaleManager
.
reset
(
806
new
WithDestructor
<
QtWayland
::
wp_fractional_scale_manager_v1
,
807
wp_fractional_scale_manager_v1_destroy
>(
registry
,
id
, 1));
808
}
else
if
(
interface
==
QLatin1String
(
"wp_viewporter"
)) {
809
mGlobals
.
viewporter
.
reset
(
810
new
WithDestructor
<
QtWayland
::
wp_viewporter
,
wp_viewporter_destroy
>(
811
registry
,
id
,
qMin
(1u,
version
)));
812
}
else
if
(
interface
==
QLatin1String
(
QtWayland
::
wp_cursor_shape_manager_v1
::
interface
()->
name
)) {
813
mGlobals
.
cursorShapeManager
.
reset
(
new
WithDestructor
<
QtWayland
::
wp_cursor_shape_manager_v1
,
814
wp_cursor_shape_manager_v1_destroy
>(
815
registry
,
id
,
std
::
min
(1u,
version
)));
816
}
else
if
(
817
interface
==
QLatin1String
(
QtWayland
::
xdg_toplevel_drag_manager_v1
::
interface
()->
name
)) {
818
mGlobals
.
xdgToplevelDragManager
.
reset
(
819
new
WithDestructor
<
QtWayland
::
xdg_toplevel_drag_manager_v1
,
820
xdg_toplevel_drag_manager_v1_destroy
>(
registry
,
id
, 1));
821
}
else
if
(
interface
==
QLatin1String
(
QtWayland
::
qt_windowmanager
::
interface
()->
name
)) {
822
mGlobals
.
windowManagerIntegration
.
reset
(
823
new
QWaylandWindowManagerIntegration
(
this
,
id
,
version
));
824
}
else
if
(
interface
==
QLatin1String
(
QtWayland
::
xdg_system_bell_v1
::
interface
()->
name
)) {
825
mGlobals
.
systemBell
.
reset
(
new
WithDestructor
<
QtWayland
::
xdg_system_bell_v1
,
xdg_system_bell_v1_destroy
>(
registry
,
id
, 1));
826
}
else
if
(
827
interface
==
QLatin1String
(
QtWayland
::
org_kde_kwin_appmenu_manager
::
interface
()->
name
)) {
828
mGlobals
.
appMenuManager
.
reset
(
new
QWaylandAppMenuManager
(
registry
,
id
, 1));
829
#
if
QT_CONFIG
(
clipboard
)
830
}
else
if
(
mPreferWlrDataControl
&&
interface
==
QLatin1String
(
QWaylandDataControlManagerV1
::
interface
()->
name
)) {
831
mGlobals
.
dataControlManager
.
reset
(
new
QWaylandDataControlManagerV1
(
this
,
id
, 2));
832
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
)) {
833
inputDevice
->
setDataControlDevice
(
mGlobals
.
dataControlManager
->
createDevice
(
inputDevice
));
834
}
835
#
endif
836
}
else
if
(
interface
==
QLatin1String
(
QtWayland
::
wp_color_manager_v1
::
interface
()->
name
)) {
837
mGlobals
.
colorManager
=
std
::
make_unique
<
ColorManager
>(
registry
,
id
, 1);
838
}
else
if
(
interface
==
QLatin1String
(
QtWayland
::
wp_pointer_warp_v1
::
interface
()->
name
)) {
839
mGlobals
.
pointerWarp
.
reset
(
new
WithDestructor
<
QtWayland
::
wp_pointer_warp_v1
,
wp_pointer_warp_v1_destroy
>(
840
registry
,
id
, 1));
841
}
842
#
ifndef
QT_NO_SESSIONMANAGER
843
else
if
(
interface
==
QLatin1String
(
QtWayland
::
xdg_session_manager_v1
::
interface
()->
name
)) {
844
mGlobals
.
xdgSessionManager
.
reset
(
845
new
WithDestructor
<
QtWayland
::
xdg_session_manager_v1
,
xdg_session_manager_v1_destroy
>(
846
registry
,
id
, 1));
847
}
848
#
endif
849
else
if
(
interface
==
QLatin1String
(
QtWayland
::
wl_fixes
::
interface
()->
name
)) {
850
mFixes
.
reset
(
new
WithDestructor
<
QtWayland
::
wl_fixes
,
wl_fixes_destroy
>(
registry
,
id
,
std
::
min
(
version
, 2u)));
851
}
else
if
(
interface
==
QLatin1StringView
(
QtWayland
::
xx_cutouts_manager_v1
::
interface
()->
name
)) {
852
mGlobals
.
cutoutManager
.
reset
(
new
WithDestructor
<
QtWayland
::
xx_cutouts_manager_v1
,
xx_cutouts_manager_v1_destroy
>(
registry
,
id
, 1));
853
}
854
855
856
mRegistryGlobals
.
append
(
RegistryGlobal
(
id
,
interface
,
version
,
registry
));
857
emit
globalAdded
(
mRegistryGlobals
.
back
());
858
859
const
auto
copy
=
mRegistryListeners
;
// be prepared for listeners unregistering on notification
860
for
(
Listener
l
:
copy
)
861
(*
l
.
listener
)(
l
.
data
,
registry
,
id
,
interface
,
version
);
862
}
863
864
void
QWaylandDisplay
::
registry_global_remove
(
uint32_t
id
)
865
{
866
for
(
int
i
= 0,
ie
=
mRegistryGlobals
.
size
();
i
!=
ie
; ++
i
) {
867
RegistryGlobal
&
global
=
mRegistryGlobals
[
i
];
868
if
(
global
.
id
==
id
) {
869
if
(
global
.
interface
==
QLatin1String
(
QtWayland
::
wl_output
::
interface
()->
name
)) {
870
for
(
auto
*
screen
:
mWaitingScreens
) {
871
if
(
screen
->
outputId
() ==
id
) {
872
mWaitingScreens
.
removeOne
(
screen
);
873
delete
screen
;
874
break
;
875
}
876
}
877
878
for
(
QWaylandScreen
*
screen
:
std
::
as_const
(
mScreens
)) {
879
if
(
screen
->
outputId
() ==
id
) {
880
mScreens
.
removeOne
(
screen
);
881
// If this is the last screen, we have to add a fake screen, or Qt will break.
882
ensureScreen
();
883
QWindowSystemInterface
::
handleScreenRemoved
(
screen
);
884
break
;
885
}
886
}
887
}
888
if
(
global
.
interface
==
QLatin1String
(
QtWayland
::
zwp_text_input_manager_v1
::
interface
()->
name
)) {
889
mGlobals
.
textInputManagerv1
.
reset
();
890
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
891
inputDevice
->
setTextInput
(
nullptr
);
892
mWaylandIntegration
->
reconfigureInputContext
();
893
}
894
if
(
global
.
interface
==
QLatin1String
(
QtWayland
::
zwp_text_input_manager_v2
::
interface
()->
name
)) {
895
mGlobals
.
textInputManagerv2
.
reset
();
896
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
897
inputDevice
->
setTextInput
(
nullptr
);
898
mWaylandIntegration
->
reconfigureInputContext
();
899
}
900
if
(
global
.
interface
==
QLatin1String
(
QtWayland
::
zwp_text_input_manager_v3
::
interface
()->
name
)) {
901
mGlobals
.
textInputManagerv3
.
reset
();
902
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
903
inputDevice
->
setTextInput
(
nullptr
);
904
mWaylandIntegration
->
reconfigureInputContext
();
905
}
906
if
(
global
.
interface
==
QLatin1String
(
QtWayland
::
qt_text_input_method_manager_v1
::
interface
()->
name
)) {
907
mGlobals
.
textInputMethodManager
.
reset
();
908
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
909
inputDevice
->
setTextInputMethod
(
nullptr
);
910
mWaylandIntegration
->
reconfigureInputContext
();
911
}
912
#
if
QT_CONFIG
(
wayland_client_primary_selection
)
913
if
(
global
.
interface
==
QLatin1String
(
QtWayland
::
zwp_primary_selection_device_manager_v1
::
interface
()->
name
)) {
914
mGlobals
.
primarySelectionManager
.
reset
();
915
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
916
inputDevice
->
setPrimarySelectionDevice
(
nullptr
);
917
}
918
#
endif
919
#
if
QT_CONFIG
(
clipboard
)
920
if
(
global
.
interface
==
QLatin1String
(
QtWayland
::
zwlr_data_control_manager_v1
::
interface
()->
name
)) {
921
mGlobals
.
dataControlManager
.
reset
();
922
for
(
QWaylandInputDevice
*
inputDevice
:
std
::
as_const
(
mInputDevices
))
923
inputDevice
->
setDataControlDevice
(
nullptr
);
924
}
925
#
endif
926
emit
globalRemoved
(
mRegistryGlobals
.
takeAt
(
i
));
927
break
;
928
}
929
}
930
931
if
(
mFixes
&&
mFixes
->
version
() >=
WL_FIXES_ACK_GLOBAL_REMOVE_SINCE_VERSION
)
932
mFixes
->
ack_global_remove
(
object
(),
id
);
933
}
934
935
bool
QWaylandDisplay
::
hasRegistryGlobal
(
QStringView
interfaceName
)
const
936
{
937
for
(
const
RegistryGlobal
&
global
:
mRegistryGlobals
)
938
if
(
global
.
interface
==
interfaceName
)
939
return
true
;
940
941
return
false
;
942
}
943
944
void
QWaylandDisplay
::
addRegistryListener
(
RegistryListener
listener
,
void
*
data
)
945
{
946
Listener
l
= {
listener
,
data
};
947
mRegistryListeners
.
append
(
l
);
948
for
(
int
i
= 0,
ie
=
mRegistryGlobals
.
size
();
i
!=
ie
; ++
i
)
949
(*
l
.
listener
)(
l
.
data
,
mRegistryGlobals
[
i
].
registry
,
mRegistryGlobals
[
i
].
id
,
950
mRegistryGlobals
[
i
].
interface
,
mRegistryGlobals
[
i
].
version
);
951
}
952
953
void
QWaylandDisplay
::
removeListener
(
RegistryListener
listener
,
void
*
data
)
954
{
955
auto
iter
=
std
::
remove_if
(
mRegistryListeners
.
begin
(),
mRegistryListeners
.
end
(), [=](
Listener
l
){
956
return
(
l
.
listener
==
listener
&&
l
.
data
==
data
);
957
});
958
mRegistryListeners
.
erase
(
iter
,
mRegistryListeners
.
end
());
959
}
960
961
void
QWaylandDisplay
::
forceRoundTrip
()
962
{
963
wl_display_roundtrip
(
mDisplay
);
964
}
965
966
bool
QWaylandDisplay
::
supportsWindowDecoration
()
const
967
{
968
static
bool
disabled
=
qgetenv
(
"QT_WAYLAND_DISABLE_WINDOWDECORATION"
).
toInt
();
969
// Stop early when disabled via the environment. Do not try to load the integration in
970
// order to play nice with SHM-only, buffer integration-less systems.
971
if
(
disabled
)
972
return
false
;
973
974
if
(!
mGlobals
.
subCompositor
)
975
return
false
;
976
977
return
true
;
978
}
979
980
QWaylandWindow
*
QWaylandDisplay
::
lastInputWindow
()
const
981
{
982
return
mLastInputSurface
?
mLastInputSurface
->
waylandWindow
() :
nullptr
;
983
}
984
985
QWaylandSurface
*
QWaylandDisplay
::
lastInputSurface
()
const
986
{
987
return
mLastInputSurface
.
data
();
988
}
989
990
void
QWaylandDisplay
::
setLastInputDevice
(
QWaylandInputDevice
*
device
,
uint32_t
serial
,
QWaylandSurface
*
surface
)
991
{
992
mLastInputDevice
=
device
;
993
mLastInputSerial
=
serial
;
994
mLastInputSurface
=
surface
;
995
}
996
997
bool
QWaylandDisplay
::
isWindowActivated
(
const
QWaylandWindow
*
window
)
998
{
999
return
mActiveWindows
.
contains
(
const_cast
<
QWaylandWindow
*>(
window
)) ||
mActiveSubSurface
==
window
;
1000
}
1001
1002
void
QWaylandDisplay
::
handleWindowActivated
(
QWaylandWindow
*
window
)
1003
{
1004
if
(
mActiveWindows
.
contains
(
window
))
1005
return
;
1006
1007
mActiveWindows
.
append
(
window
);
1008
mActiveSubSurface
.
clear
();
1009
requestWaylandSync
();
1010
1011
if
(
auto
*
decoration
=
window
->
decoration
())
1012
decoration
->
update
();
1013
}
1014
1015
void
QWaylandDisplay
::
handleWindowDeactivated
(
QWaylandWindow
*
window
)
1016
{
1017
Q_ASSERT
(!
mActiveWindows
.
empty
());
1018
1019
if
(
mActiveWindows
.
last
() ==
window
)
1020
requestWaylandSync
();
1021
1022
mActiveWindows
.
removeOne
(
window
);
1023
mActiveSubSurface
.
clear
();
1024
1025
if
(
QCoreApplication
::
closingDown
())
1026
return
;
1027
1028
if
(
auto
*
decoration
=
window
->
decoration
())
1029
decoration
->
update
();
1030
}
1031
1032
void
QWaylandDisplay
::
handleKeyboardFocusChanged
(
QWaylandInputDevice
*
inputDevice
)
1033
{
1034
QWaylandWindow
*
keyboardFocus
=
inputDevice
->
keyboardFocus
();
1035
1036
if
(
mLastKeyboardFocus
==
keyboardFocus
)
1037
return
;
1038
1039
if
(
keyboardFocus
)
1040
handleWindowActivated
(
keyboardFocus
);
1041
if
(
mLastKeyboardFocus
)
1042
handleWindowDeactivated
(
mLastKeyboardFocus
);
1043
1044
mLastKeyboardFocus
=
keyboardFocus
;
1045
}
1046
1047
void
QWaylandDisplay
::
handleWindowDestroyed
(
QWaylandWindow
*
window
)
1048
{
1049
if
(
mActiveWindows
.
contains
(
window
))
1050
handleWindowDeactivated
(
window
);
1051
if
(
mActiveSubSurface
) {
1052
auto
*
parent
=
mActiveSubSurface
.
get
();
1053
while
(
parent
&&
parent
!=
window
)
1054
parent
=
static_cast
<
QWaylandWindow
*>(
parent
->
QPlatformWindow
::
parent
());
1055
if
(
parent
)
1056
mActiveSubSurface
.
clear
();
1057
}
1058
}
1059
1060
void
QWaylandDisplay
::
setActiveSubSurface
(
QWaylandWindow
*
window
)
1061
{
1062
mActiveSubSurface
=
window
;
1063
requestWaylandSync
();
1064
}
1065
1066
QWaylandWindow
*
QWaylandDisplay
::
activeSubSurface
()
const
1067
{
1068
return
mActiveSubSurface
;
1069
}
1070
1071
void
QWaylandDisplay
::
handleWaylandSync
()
1072
{
1073
// This callback is used to set the window activation because we may get an activate/deactivate
1074
// pair, and the latter one would be lost in the QWindowSystemInterface queue, if we issue the
1075
// handleWindowActivated() calls immediately.
1076
QWindow
*
activeWindow
=
mActiveWindows
.
empty
() ?
nullptr
:
mActiveWindows
.
last
()->
window
();
1077
if
(
mActiveSubSurface
)
1078
activeWindow
=
mActiveSubSurface
->
window
();
1079
if
(
activeWindow
!=
QGuiApplication
::
focusWindow
())
1080
QWindowSystemInterface
::
handleFocusWindowChanged
(
activeWindow
,
Qt
::
ActiveWindowFocusReason
);
1081
}
1082
1083
const
wl_callback_listener
QWaylandDisplay
::
syncCallbackListener
= {
1084
[](
void
*
data
,
struct
wl_callback
*
callback
,
uint32_t
time
){
1085
Q_UNUSED
(
time
);
1086
wl_callback_destroy
(
callback
);
1087
QWaylandDisplay
*
display
=
static_cast
<
QWaylandDisplay
*>(
data
);
1088
display
->
mSyncCallback
=
nullptr
;
1089
display
->
handleWaylandSync
();
1090
}
1091
};
1092
1093
void
QWaylandDisplay
::
requestWaylandSync
()
1094
{
1095
if
(
mSyncCallback
)
1096
return
;
1097
1098
mSyncCallback
=
wl_display_sync
(
mDisplay
);
1099
wl_callback_add_listener
(
mSyncCallback
, &
syncCallbackListener
,
this
);
1100
}
1101
1102
QWaylandInputDevice
*
QWaylandDisplay
::
defaultInputDevice
()
const
1103
{
1104
return
mInputDevices
.
isEmpty
() ?
nullptr
:
mInputDevices
.
first
();
1105
}
1106
1107
bool
QWaylandDisplay
::
isKeyboardAvailable
()
const
1108
{
1109
return
std
::
any_of
(
1110
mInputDevices
.
constBegin
(),
mInputDevices
.
constEnd
(),
1111
[](
const
QWaylandInputDevice
*
device
) {
return
device
->
keyboard
() !=
nullptr
; });
1112
}
1113
1114
bool
QWaylandDisplay
::
isWaylandInputContextRequested
()
const
{
1115
return
mWaylandInputContextRequested
;
1116
}
1117
1118
#
if
QT_CONFIG
(
cursor
)
1119
1120
QWaylandCursor
*
QWaylandDisplay
::
waylandCursor
()
1121
{
1122
if
(!
mCursor
)
1123
mCursor
.
reset
(
mWaylandIntegration
->
createPlatformCursor
(
this
));
1124
return
mCursor
.
get
();
1125
}
1126
1127
auto
QWaylandDisplay
::
findExistingCursorTheme
(
const
QString
&
name
,
int
pixelSize
)
const
noexcept
1128
->
FindExistingCursorThemeResult
1129
{
1130
const
auto
byNameAndSize
= [](
const
WaylandCursorTheme
&
lhs
,
const
WaylandCursorTheme
&
rhs
) {
1131
return
std
::
tie
(
lhs
.
pixelSize
,
lhs
.
name
) <
std
::
tie
(
rhs
.
pixelSize
,
rhs
.
name
);
1132
};
1133
1134
const
WaylandCursorTheme
prototype
= {
name
,
pixelSize
,
nullptr
};
1135
1136
const
auto
it
=
std
::
lower_bound
(
mCursorThemes
.
cbegin
(),
mCursorThemes
.
cend
(),
prototype
,
byNameAndSize
);
1137
if
(
it
!=
mCursorThemes
.
cend
() &&
it
->
name
==
name
&&
it
->
pixelSize
==
pixelSize
)
1138
return
{
it
,
true
};
1139
else
1140
return
{
it
,
false
};
1141
}
1142
1143
QWaylandCursorTheme
*
QWaylandDisplay
::
loadCursorTheme
(
const
QString
&
name
,
int
pixelSize
)
1144
{
1145
const
auto
result
=
findExistingCursorTheme
(
name
,
pixelSize
);
1146
if
(
result
.
found
)
1147
return
result
.
theme
();
1148
1149
if
(
auto
theme
=
QWaylandCursorTheme
::
create
(
shm
(),
pixelSize
,
name
))
1150
return
mCursorThemes
.
insert
(
result
.
position
, {
name
,
pixelSize
,
std
::
move
(
theme
)})->
theme
.
get
();
1151
1152
return
nullptr
;
1153
}
1154
1155
#
endif
// QT_CONFIG(cursor)
1156
1157
}
// namespace QtWaylandClient
1158
1159
QT_END_NAMESPACE
1160
1161
#
include
"qwaylanddisplay.moc"
1162
#
include
"moc_qwaylanddisplay_p.cpp"
QtWaylandClient::EventThread
Definition
qwaylanddisplay.cpp:81
QtWaylandClient::EventThread::run
void run() override
Definition
qwaylanddisplay.cpp:183
QtWaylandClient::EventThread::~EventThread
~EventThread() override
Definition
qwaylanddisplay.cpp:110
QtWaylandClient::EventThread::stop
void stop()
Definition
qwaylanddisplay.cpp:160
QtWaylandClient::EventThread::readAndDispatchEvents
void readAndDispatchEvents()
Definition
qwaylanddisplay.cpp:121
QtWaylandClient::EventThread::waylandError
void waylandError()
QtWaylandClient
Definition
qwaylandclientextension.h:16
QtWaylandClient::Q_LOGGING_CATEGORY
Q_LOGGING_CATEGORY(lcQpaWayland, "qt.qpa.wayland")
QtWaylandClient::WithDestructor
Definition
qwaylandxdgshell.cpp:30
QtWaylandClient::WithDestructor::~WithDestructor
~WithDestructor()
Definition
qwaylandxdgshell.cpp:32
qtbase
src
plugins
platforms
wayland
qwaylanddisplay.cpp
Generated on
for Qt by
1.18.0