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
qxcbconnection_screens.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 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
6#include "qxcbscreen.h"
8
9#include <QtCore/QString>
10#include <QtCore/QList>
11
12#include <qpa/qwindowsysteminterface.h>
13
14void QXcbConnection::xrandrSelectEvents()
15{
16 xcb_screen_iterator_t rootIter = xcb_setup_roots_iterator(setup());
17 for (; rootIter.rem; xcb_screen_next(&rootIter)) {
18 xcb_randr_select_input(xcb_connection(),
19 rootIter.data->root,
20 XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE |
21 XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE |
22 XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE |
23 XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY
24 );
25 }
26}
27
28QXcbScreen* QXcbConnection::findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc) const
29{
30 for (QXcbScreen *screen : m_screens) {
31 if (screen->root() == rootWindow) {
32 if (screen->m_monitor) {
33 if (screen->crtcs().contains(crtc))
34 return screen;
35 } else {
36 if (screen->crtc() == crtc)
37 return screen;
38 }
39 }
40 }
41
42 return nullptr;
43}
44
45QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output) const
46{
47 for (QXcbScreen *screen : m_screens) {
48 if (screen->root() == rootWindow) {
49 if (screen->m_monitor) {
50 if (screen->outputs().contains(output))
51 return screen;
52 } else {
53 if (screen->output() == output)
54 return screen;
55 }
56 }
57 }
58
59 return nullptr;
60}
61
62QXcbVirtualDesktop* QXcbConnection::virtualDesktopForRootWindow(xcb_window_t rootWindow) const
63{
64 for (QXcbVirtualDesktop *virtualDesktop : m_virtualDesktops) {
65 if (virtualDesktop->screen()->root == rootWindow)
66 return virtualDesktop;
67 }
68
69 return nullptr;
70}
71
72/*!
73 \brief Synchronizes the screen list, adds new screens, removes deleted ones
74*/
75void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
76{
77 if (event->subCode == XCB_RANDR_NOTIFY_CRTC_CHANGE) {
78 xcb_randr_crtc_change_t crtc = event->u.cc;
79 QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(crtc.window);
80 if (!virtualDesktop)
81 // Not for us
82 return;
83
84 QXcbScreen *screen = findScreenForCrtc(crtc.window, crtc.crtc);
85 qCDebug(lcQpaScreen) << "QXcbConnection: XCB_RANDR_NOTIFY_CRTC_CHANGE:" << crtc.crtc
86 << "mode" << crtc.mode << "relevant screen" << screen;
87 // Only update geometry when there's a valid mode on the CRTC
88 // CRTC with node mode could mean that output has been disabled, and we'll
89 // get RRNotifyOutputChange notification for that.
90 if (screen && crtc.mode) {
91 if (crtc.rotation == XCB_RANDR_ROTATION_ROTATE_90 ||
92 crtc.rotation == XCB_RANDR_ROTATION_ROTATE_270)
93 std::swap(crtc.width, crtc.height);
94 screen->updateGeometry(QRect(crtc.x, crtc.y, crtc.width, crtc.height), crtc.rotation);
95 if (screen->mode() != crtc.mode)
96 screen->updateRefreshRate(crtc.mode);
97 }
98
99 } else if (event->subCode == XCB_RANDR_NOTIFY_OUTPUT_CHANGE) {
100 xcb_randr_output_change_t output = event->u.oc;
101 QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(output.window);
102 if (!virtualDesktop)
103 // Not for us
104 return;
105
106 QXcbScreen *screen = findScreenForOutput(output.window, output.output);
107 qCDebug(lcQpaScreen) << "QXcbConnection: XCB_RANDR_NOTIFY_OUTPUT_CHANGE:" << output.output;
108
109 if (screen && output.connection == XCB_RANDR_CONNECTION_DISCONNECTED) {
110 qCDebug(lcQpaScreen) << "screen" << screen->name() << "has been disconnected";
111 destroyScreen(screen);
112 } else if (!screen && output.connection == XCB_RANDR_CONNECTION_CONNECTED) {
113 // New XRandR output is available and it's enabled
114 if (output.crtc != XCB_NONE && output.mode != XCB_NONE) {
115 auto outputInfo = Q_XCB_REPLY(xcb_randr_get_output_info, xcb_connection(),
116 output.output, output.config_timestamp);
117 // Find a fake screen
118 const auto scrs = virtualDesktop->screens();
119 for (QPlatformScreen *scr : scrs) {
120 QXcbScreen *xcbScreen = static_cast<QXcbScreen *>(scr);
121 if (xcbScreen->output() == XCB_NONE) {
122 screen = xcbScreen;
123 break;
124 }
125 }
126
127 if (screen) {
128 QString nameWas = screen->name();
129 // Transform the fake screen into a physical screen
130 screen->setOutput(output.output, outputInfo.get());
131 updateScreen(screen, output);
132 qCDebug(lcQpaScreen) << "output" << screen->name()
133 << "is connected and enabled; was fake:" << nameWas;
134 } else {
135 screen = createScreen(virtualDesktop, output, outputInfo.get());
136 qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled";
137 }
138 }
139 } else if (screen) {
140 if (output.crtc == XCB_NONE && output.mode == XCB_NONE) {
141 // Screen has been disabled
142 auto outputInfo = Q_XCB_REPLY(xcb_randr_get_output_info, xcb_connection(),
143 output.output, output.config_timestamp);
144 if (!outputInfo || outputInfo->crtc == XCB_NONE) {
145 qCDebug(lcQpaScreen) << "output" << screen->name() << "has been disabled";
146 destroyScreen(screen);
147 } else {
148 qCDebug(lcQpaScreen) << "output" << screen->name() << "has been temporarily disabled for the mode switch";
149 // Reset crtc to skip RRCrtcChangeNotify events,
150 // because they may be invalid in the middle of the mode switch
151 screen->setCrtc(XCB_NONE);
152 }
153 } else {
154 updateScreen(screen, output);
155 qCDebug(lcQpaScreen) << "output has changed" << screen;
156 }
157 }
158
159 qCDebug(lcQpaScreen) << "updateScreens: primary output is" << std::as_const(m_screens).first()->name();
160 }
161}
162
163bool QXcbConnection::checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output)
164{
165 auto primary = Q_XCB_REPLY(xcb_randr_get_output_primary, xcb_connection(), rootWindow);
166 if (!primary)
167 qWarning("failed to get the primary output of the screen");
168
169 const bool isPrimary = primary ? (primary->output == output) : false;
170
171 return isPrimary;
172}
173
174void QXcbConnection::updateScreen(QXcbScreen *screen, const xcb_randr_output_change_t &outputChange)
175{
176 screen->setCrtc(outputChange.crtc); // Set the new crtc, because it can be invalid
177 screen->updateGeometry(outputChange.config_timestamp);
178 if (screen->mode() != outputChange.mode)
179 screen->updateRefreshRate(outputChange.mode);
180 // Only screen which belongs to the primary virtual desktop can be a primary screen
181 if (screen->screenNumber() == primaryScreenNumber()) {
182 if (!screen->isPrimary() && checkOutputIsPrimary(outputChange.window, outputChange.output)) {
183 screen->setPrimary(true);
184
185 // If the screen became primary, reshuffle the order in QGuiApplicationPrivate
186 const int idx = m_screens.indexOf(screen);
187 if (idx > 0) {
188 std::as_const(m_screens).first()->setPrimary(false);
189 m_screens.swapItemsAt(0, idx);
190 }
191 screen->virtualDesktop()->setPrimaryScreen(screen);
192 QWindowSystemInterface::handlePrimaryScreenChanged(screen);
193 }
194 }
195}
196
197QXcbScreen *QXcbConnection::createScreen(QXcbVirtualDesktop *virtualDesktop,
198 const xcb_randr_output_change_t &outputChange,
199 xcb_randr_get_output_info_reply_t *outputInfo)
200{
201 QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, outputChange.output, outputInfo);
202 // Only screen which belongs to the primary virtual desktop can be a primary screen
203 if (screen->screenNumber() == primaryScreenNumber())
204 screen->setPrimary(checkOutputIsPrimary(outputChange.window, outputChange.output));
205
206 if (screen->isPrimary()) {
207 if (!m_screens.isEmpty())
208 std::as_const(m_screens).first()->setPrimary(false);
209
210 m_screens.prepend(screen);
211 } else {
212 m_screens.append(screen);
213 }
214 virtualDesktop->addScreen(screen);
215 QWindowSystemInterface::handleScreenAdded(screen, screen->isPrimary());
216
217 return screen;
218}
219
220void QXcbConnection::destroyScreen(QXcbScreen *screen)
221{
222 QXcbVirtualDesktop *virtualDesktop = screen->virtualDesktop();
223 if (virtualDesktop->screens().size() == 1) {
224 // If there are no other screens on the same virtual desktop,
225 // then transform the physical screen into a fake screen.
226 const QString nameWas = screen->name();
227 screen->setOutput(XCB_NONE, nullptr);
228 qCDebug(lcQpaScreen) << "transformed" << nameWas << "to fake" << screen;
229 } else {
230 // There is more than one screen on the same virtual desktop, remove the screen
231 m_screens.removeOne(screen);
232 virtualDesktop->removeScreen(screen);
233
234 // When primary screen is removed, set the new primary screen
235 // which belongs to the primary virtual desktop.
236 if (screen->isPrimary()) {
237 QXcbScreen *newPrimary = static_cast<QXcbScreen *>(virtualDesktop->screens().at(0));
238 newPrimary->setPrimary(true);
239 const int idx = m_screens.indexOf(newPrimary);
240 if (idx > 0)
241 m_screens.swapItemsAt(0, idx);
242 QWindowSystemInterface::handlePrimaryScreenChanged(newPrimary);
243 }
244
245 qCDebug(lcQpaScreen) << "destroyScreen: destroy" << screen;
246 QWindowSystemInterface::handleScreenRemoved(screen);
247 }
248}
249
250QXcbVirtualDesktop *QXcbConnection::virtualDesktopForNumber(int n) const
251{
252 for (QXcbVirtualDesktop *virtualDesktop : m_virtualDesktops) {
253 if (virtualDesktop->number() == n)
254 return virtualDesktop;
255 }
256
257 return nullptr;
258}
259
260QXcbScreen *QXcbConnection::findScreenForMonitorInfo(const QList<QPlatformScreen *> &screens, xcb_randr_monitor_info_t *monitorInfo)
261{
262 for (int i = 0; i < screens.size(); ++i) {
263 auto s = static_cast<QXcbScreen*>(screens[i]);
264 if (monitorInfo) {
265 QByteArray ba2 = atomName(monitorInfo->name);
266 if (s->name().toLocal8Bit() == ba2)
267 return s;
268 }
269 }
270
271 return nullptr;
272}
273
274void QXcbConnection::initializeScreens(bool initialized)
275{
276 xcb_screen_iterator_t it = xcb_setup_roots_iterator(setup());
277 int xcbScreenNumber = 0; // screen number in the xcb sense
278 QXcbScreen *primaryScreen = nullptr;
279 if (isAtLeastXRandR15() && initialized)
280 m_screens.clear();
281
282 while (it.rem) {
283 if (isAtLeastXRandR15())
284 initializeScreensFromMonitor(&it, xcbScreenNumber, &primaryScreen, initialized);
285 else if (isAtLeastXRandR12())
286 initializeScreensFromOutput(&it, xcbScreenNumber, &primaryScreen);
287 else {
288 qWarning("There is no XRandR 1.2 and later version available. There will be only fake screen(s) to use.");
289 initializeScreensWithoutXRandR(&it, xcbScreenNumber, &primaryScreen);
290 }
291
292 xcb_screen_next(&it);
293 ++xcbScreenNumber;
294 }
295
296 for (QXcbVirtualDesktop *virtualDesktop : std::as_const(m_virtualDesktops))
297 virtualDesktop->subscribeToXFixesSelectionNotify();
298
299 if (m_virtualDesktops.isEmpty()) {
300 qFatal("QXcbConnection: no screens available");
301 } else {
302 // Ensure the primary screen is first on the list
303 if (primaryScreen) {
304 if (std::as_const(m_screens).first() != primaryScreen) {
305 m_screens.removeOne(primaryScreen);
306 m_screens.prepend(primaryScreen);
307 }
308 }
309
310 // Push the screens to QGuiApplication
311 if (!initialized) {
312 for (QXcbScreen *screen : std::as_const(m_screens)) {
313 qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ")";
314 QWindowSystemInterface::handleScreenAdded(screen, screen->isPrimary());
315 }
316 }
317
318 if (!m_screens.isEmpty())
319 qCDebug(lcQpaScreen) << "initializeScreens: primary output is" << std::as_const(m_screens).first()->name();
320 }
321}
322
323void QXcbConnection::initializeScreensWithoutXRandR(xcb_screen_iterator_t *it, int xcbScreenNumber, QXcbScreen **primaryScreen)
324{
325 // XRandR extension is missing, then create a fake/legacy screen.
326 xcb_screen_t *xcbScreen = it->data;
327 QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber);
328 m_virtualDesktops.append(virtualDesktop);
329 QList<QPlatformScreen *> siblings;
330
331 QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, XCB_NONE, nullptr);
332 qCDebug(lcQpaScreen) << "created fake screen" << screen;
333 m_screens << screen;
334
335 if (primaryScreenNumber() == xcbScreenNumber) {
336 *primaryScreen = screen;
337 (*primaryScreen)->setPrimary(true);
338 }
339 siblings << screen;
340 virtualDesktop->setScreens(std::move(siblings));
341}
342
343void QXcbConnection::initializeScreensFromOutput(xcb_screen_iterator_t *it, int xcbScreenNumber, QXcbScreen **primaryScreen)
344{
345 // Each "screen" in xcb terminology is a virtual desktop,
346 // potentially a collection of separate juxtaposed monitors.
347 // But we want a separate QScreen for each output (e.g. DVI-I-1, VGA-1, etc.)
348 // which will become virtual siblings.
349 xcb_screen_t *xcbScreen = it->data;
350 QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber);
351 m_virtualDesktops.append(virtualDesktop);
352 QList<QPlatformScreen *> siblings;
353 if (isAtLeastXRandR12()) {
354 // RRGetScreenResourcesCurrent is fast but it may return nothing if the
355 // configuration is not initialized wrt to the hardware. We should call
356 // RRGetScreenResources in this case.
357 auto resources_current = Q_XCB_REPLY(xcb_randr_get_screen_resources_current,
358 xcb_connection(), xcbScreen->root);
359 decltype(Q_XCB_REPLY(xcb_randr_get_screen_resources,
360 xcb_connection(), xcbScreen->root)) resources;
361 if (!resources_current) {
362 qWarning("failed to get the current screen resources");
363 } else {
364 xcb_timestamp_t timestamp = 0;
365 xcb_randr_output_t *outputs = nullptr;
366 int outputCount = xcb_randr_get_screen_resources_current_outputs_length(resources_current.get());
367 if (outputCount) {
368 timestamp = resources_current->config_timestamp;
369 outputs = xcb_randr_get_screen_resources_current_outputs(resources_current.get());
370 } else {
371 resources = Q_XCB_REPLY(xcb_randr_get_screen_resources,
372 xcb_connection(), xcbScreen->root);
373 if (!resources) {
374 qWarning("failed to get the screen resources");
375 } else {
376 timestamp = resources->config_timestamp;
377 outputCount = xcb_randr_get_screen_resources_outputs_length(resources.get());
378 outputs = xcb_randr_get_screen_resources_outputs(resources.get());
379 }
380 }
381
382 if (outputCount) {
383 auto primary = Q_XCB_REPLY(xcb_randr_get_output_primary, xcb_connection(), xcbScreen->root);
384 if (!primary) {
385 qWarning("failed to get the primary output of the screen");
386 } else {
387 for (int i = 0; i < outputCount; i++) {
388 auto output = Q_XCB_REPLY_UNCHECKED(xcb_randr_get_output_info,
389 xcb_connection(), outputs[i], timestamp);
390 // Invalid, disconnected or disabled output
391 if (!output)
392 continue;
393
394 if (output->connection != XCB_RANDR_CONNECTION_CONNECTED) {
395 qCDebug(lcQpaScreen, "Output %s is not connected", qPrintable(
396 QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.get()),
397 xcb_randr_get_output_info_name_length(output.get()))));
398 continue;
399 }
400
401 if (output->crtc == XCB_NONE) {
402 qCDebug(lcQpaScreen, "Output %s is not enabled", qPrintable(
403 QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.get()),
404 xcb_randr_get_output_info_name_length(output.get()))));
405 continue;
406 }
407
408 QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, outputs[i], output.get());
409 siblings << screen;
410 m_screens << screen;
411
412 // There can be multiple outputs per screen, use either
413 // the first or an exact match. An exact match isn't
414 // always available if primary->output is XCB_NONE
415 // or currently disconnected output.
416 if (primaryScreenNumber() == xcbScreenNumber) {
417 if (!(*primaryScreen) || (primary && outputs[i] == primary->output)) {
418 if (*primaryScreen)
419 (*primaryScreen)->setPrimary(false);
420 *primaryScreen = screen;
421 (*primaryScreen)->setPrimary(true);
422 siblings.prepend(siblings.takeLast());
423 }
424 }
425 }
426 }
427 }
428 }
429 }
430 if (siblings.isEmpty()) {
431 // If there are no XRandR outputs or XRandR extension is missing,
432 // then create a fake/legacy screen.
433 QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, XCB_NONE, nullptr);
434 qCDebug(lcQpaScreen) << "created fake screen" << screen;
435 m_screens << screen;
436 if (primaryScreenNumber() == xcbScreenNumber) {
437 *primaryScreen = screen;
438 (*primaryScreen)->setPrimary(true);
439 }
440 siblings << screen;
441 }
442 virtualDesktop->setScreens(std::move(siblings));
443}
444
445void QXcbConnection::initializeScreensFromMonitor(xcb_screen_iterator_t *it, int xcbScreenNumber, QXcbScreen **primaryScreen, bool initialized)
446{
447 // Each "screen" in xcb terminology is a virtual desktop,
448 // potentially a collection of separate juxtaposed monitors.
449 // But we want a separate QScreen for each output (e.g. DVI-I-1, VGA-1, etc.)
450 // which will become virtual siblings.
451 xcb_screen_t *xcbScreen = it->data;
452 QXcbVirtualDesktop *virtualDesktop = nullptr;
453 if (initialized)
454 virtualDesktop = virtualDesktopForNumber(xcbScreenNumber);
455 if (!virtualDesktop) {
456 virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber);
457 m_virtualDesktops.append(virtualDesktop);
458 }
459 QList<QPlatformScreen *> old = virtualDesktop->m_screens;
460 QList<QXcbScreen *> newScreens;
461
462 QList<QPlatformScreen *> siblings;
463
464 xcb_randr_get_monitors_cookie_t monitors_c = xcb_randr_get_monitors(xcb_connection(), xcbScreen->root, 1);
465 xcb_randr_get_monitors_reply_t *monitors_r = xcb_randr_get_monitors_reply(xcb_connection(), monitors_c, nullptr);
466
467 if (!monitors_r) {
468 qWarning("RANDR GetMonitors failed; this should not be possible");
469 return;
470 }
471
472 xcb_randr_monitor_info_iterator_t monitor_iter = xcb_randr_get_monitors_monitors_iterator(monitors_r);
473 while (monitor_iter.rem) {
474 xcb_randr_monitor_info_t *monitor_info = monitor_iter.data;
475 QXcbScreen *screen = nullptr;
476 if (!initialized) {
477 screen = new QXcbScreen(this, virtualDesktop, monitor_info, monitors_r->timestamp);
478 } else {
479 screen = findScreenForMonitorInfo(old, monitor_info);
480 if (!screen) {
481 screen = new QXcbScreen(this, virtualDesktop, monitor_info, monitors_r->timestamp);
482 newScreens.append(screen);
483 } else {
484 screen->setMonitor(monitor_info, monitors_r->timestamp);
485 old.removeAll(screen);
486 }
487 }
488
489 if (screen->isPrimary()) {
490 siblings.prepend (screen);
491 if (primaryScreenNumber() == xcbScreenNumber) {
492 if (*primaryScreen)
493 (*primaryScreen)->setPrimary(false);
494 *primaryScreen = screen;
495 (*primaryScreen)->setPrimary(true);
496 } else { // Only screens on the main virtual desktop can be primary
497 screen->setPrimary(false);
498 }
499 } else {
500 siblings.append(screen);
501 }
502
503 xcb_randr_monitor_info_next(&monitor_iter);
504 }
505 free(monitors_r);
506
507 if (siblings.isEmpty()) {
508 QXcbScreen *screen = nullptr;
509 if (initialized && !old.isEmpty()) {
510 // If there are no other screens on the same virtual desktop,
511 // then transform the physical screen into a fake screen.
512 screen = static_cast<QXcbScreen *>(old.takeFirst());
513 const QString nameWas = screen->name();
514 screen->setMonitor(nullptr, XCB_NONE);
515 qCDebug(lcQpaScreen) << "transformed" << nameWas << "to fake" << screen;
516 } else {
517 // If there are no XRandR outputs or XRandR extension is missing,
518 // then create a fake/legacy screen.
519 screen = new QXcbScreen(this, virtualDesktop, nullptr);
520 qCDebug(lcQpaScreen) << "create a fake screen: " << screen;
521 }
522
523 siblings << screen;
524 }
525
526 if (primaryScreenNumber() == xcbScreenNumber) {
527 // If no screen was reported to be primary, use the first one
528 if (!*primaryScreen) {
529 (*primaryScreen) = static_cast<QXcbScreen *>(siblings.first());
530 (*primaryScreen)->setPrimary(true);
531 }
532
533 // Prepand the siblings to the current list of screens
534 QList<QXcbScreen *> new_m_screens;
535 new_m_screens.reserve( siblings.size() + m_screens.size() );
536 for (QPlatformScreen *ps:siblings) {
537 new_m_screens.append(static_cast<QXcbScreen *>(ps));
538 }
539 new_m_screens.append(std::move(m_screens));
540 m_screens = std::move(new_m_screens);
541 } else {
542 for (QPlatformScreen *ps:siblings) {
543 m_screens.append(static_cast<QXcbScreen *>(ps));
544 }
545 }
546
547 if (initialized) {
548 if (primaryScreenNumber() == xcbScreenNumber && !newScreens.contains(*primaryScreen)) {
549 qCDebug(lcQpaScreen) << "assigning screen as primary: " << *primaryScreen;
550 virtualDesktop->setPrimaryScreen(*primaryScreen);
551 QWindowSystemInterface::handlePrimaryScreenChanged(*primaryScreen);
552 }
553
554 for (QXcbScreen *screen: newScreens) {
555 qCDebug(lcQpaScreen) << "adding screen: " << screen << "(Primary:" << screen->isPrimary() << ")";
556 virtualDesktop->addScreen(screen);
557 QWindowSystemInterface::handleScreenAdded(screen, screen->isPrimary());
558 }
559
560 for (QPlatformScreen *ps : old) {
561 qCDebug(lcQpaScreen) << "destroy screen: " << ps;
562 QWindowSystemInterface::handleScreenRemoved(ps);
563 virtualDesktop->removeScreen(ps);
564 }
565 }
566
567 virtualDesktop->setScreens(std::move(siblings));
568}
#define Q_XCB_REPLY(call,...)
#define Q_XCB_REPLY_UNCHECKED(call,...)