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