7#include <QtGui/private/qhighdpiscaling_p.h>
8#include <QtCore/QString>
11#include <qpa/qwindowsysteminterface.h>
13void QXcbConnection::xrandrSelectEvents()
15 xcb_screen_iterator_t rootIter = xcb_setup_roots_iterator(
setup());
16 for (; rootIter.rem; xcb_screen_next(&rootIter)) {
19 XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE |
20 XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE |
21 XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE |
22 XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY
27QXcbScreen* QXcbConnection::findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc)
const
32 if (
screen->crtcs().contains(crtc))
35 if (
screen->crtc() == crtc)
44QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t
output)
const
61QXcbVirtualDesktop* QXcbConnection::virtualDesktopForRootWindow(xcb_window_t rootWindow)
const
64 if (virtualDesktop->screen()->root ==
rootWindow)
65 return virtualDesktop;
74void QXcbConnection::updateScreens(
const xcb_randr_notify_event_t *
event)
76 if (
event->subCode == XCB_RANDR_NOTIFY_CRTC_CHANGE) {
77 xcb_randr_crtc_change_t crtc =
event->u.cc;
84 qCDebug(lcQpaScreen) <<
"QXcbConnection: XCB_RANDR_NOTIFY_CRTC_CHANGE:" << crtc.crtc
85 <<
"mode" << crtc.mode <<
"relevant screen" <<
screen;
90 if (crtc.rotation == XCB_RANDR_ROTATION_ROTATE_90 ||
91 crtc.rotation == XCB_RANDR_ROTATION_ROTATE_270)
92 std::swap(crtc.width, crtc.height);
93 screen->updateGeometry(
QRect(crtc.x, crtc.y, crtc.width, crtc.height), crtc.rotation);
94 if (
screen->mode() != crtc.mode)
95 screen->updateRefreshRate(crtc.mode);
98 }
else if (
event->subCode == XCB_RANDR_NOTIFY_OUTPUT_CHANGE) {
99 xcb_randr_output_change_t
output =
event->u.oc;
106 qCDebug(lcQpaScreen) <<
"QXcbConnection: XCB_RANDR_NOTIFY_OUTPUT_CHANGE:" <<
output.output;
108 if (
screen &&
output.connection == XCB_RANDR_CONNECTION_DISCONNECTED) {
111 }
else if (!
screen &&
output.connection == XCB_RANDR_CONNECTION_CONNECTED) {
113 if (
output.crtc != XCB_NONE &&
output.mode != XCB_NONE) {
117 const auto scrs = virtualDesktop->
screens();
120 if (xcbScreen->
output() == XCB_NONE) {
132 <<
"is connected and enabled; was fake:" << nameWas;
134 screen = createScreen(virtualDesktop,
output, outputInfo.get());
135 qCDebug(lcQpaScreen) <<
"output" <<
screen->
name() <<
"is connected and enabled";
139 if (
output.crtc == XCB_NONE &&
output.mode == XCB_NONE) {
143 if (outputInfo->crtc == XCB_NONE) {
147 qCDebug(lcQpaScreen) <<
"output" <<
screen->
name() <<
"has been temporarily disabled for the mode switch";
150 screen->setCrtc(XCB_NONE);
158 qCDebug(lcQpaScreen) <<
"updateScreens: primary output is" << std::as_const(m_screens).first()->name();
162bool QXcbConnection::checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t
output)
166 qWarning(
"failed to get the primary output of the screen");
168 const bool isPrimary = primary ? (primary->output ==
output) :
false;
173void QXcbConnection::updateScreen(
QXcbScreen *
screen,
const xcb_randr_output_change_t &outputChange)
175 screen->setCrtc(outputChange.crtc);
176 screen->updateGeometry(outputChange.config_timestamp);
177 if (
screen->mode() != outputChange.mode)
178 screen->updateRefreshRate(outputChange.mode);
181 if (!
screen->isPrimary() && checkOutputIsPrimary(outputChange.window, outputChange.output)) {
187 std::as_const(m_screens).first()->setPrimary(
false);
197 const xcb_randr_output_change_t &outputChange,
198 xcb_randr_get_output_info_reply_t *outputInfo)
203 screen->setPrimary(checkOutputIsPrimary(outputChange.window, outputChange.output));
205 if (
screen->isPrimary()) {
207 std::as_const(m_screens).first()->setPrimary(
false);
226 screen->setOutput(XCB_NONE,
nullptr);
227 qCDebug(lcQpaScreen) <<
"transformed" << nameWas <<
"to fake" <<
screen;
235 if (
screen->isPrimary()) {
238 const int idx = m_screens.
indexOf(newPrimary);
249void QXcbConnection::updateScreen_monitor(
QXcbScreen *
screen, xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
251 screen->setMonitor(monitorInfo, timestamp);
253 if (
screen->isPrimary()) {
256 std::as_const(m_screens).first()->setPrimary(
false);
262 qCDebug(lcQpaScreen) <<
"updateScreen_monitor: update" <<
screen <<
"(Primary:" <<
screen->isPrimary() <<
")";
265QXcbScreen *QXcbConnection::createScreen_monitor(
QXcbVirtualDesktop *virtualDesktop, xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
269 if (
screen->isPrimary()) {
271 std::as_const(m_screens).first()->setPrimary(
false);
277 qCDebug(lcQpaScreen) <<
"createScreen_monitor: adding" <<
screen <<
"(Primary:" <<
screen->isPrimary() <<
")";
286 if (virtualDesktop->
number() ==
n)
287 return virtualDesktop;
299 if (
s->name().toLocal8Bit() == ba2)
307void QXcbConnection::initializeScreens(
bool initialized)
309 xcb_screen_iterator_t
it = xcb_setup_roots_iterator(
setup());
310 int xcbScreenNumber = 0;
317 initializeScreensFromMonitor(&
it, xcbScreenNumber, &
primaryScreen, initialized);
321 qWarning(
"There is no XRandR 1.2 and later version available. There will be only fake screen(s) to use.");
325 xcb_screen_next(&
it);
330 virtualDesktop->subscribeToXFixesSelectionNotify();
332 if (m_virtualDesktops.
isEmpty()) {
333 qFatal(
"QXcbConnection: no screens available");
352 qCDebug(lcQpaScreen) <<
"initializeScreens: primary output is" << std::as_const(m_screens).first()->name();
356void QXcbConnection::initializeScreensWithoutXRandR(xcb_screen_iterator_t *
it,
int xcbScreenNumber,
QXcbScreen **primaryScreen)
359 xcb_screen_t *xcbScreen =
it->data;
361 m_virtualDesktops.
append(virtualDesktop);
370 (*primaryScreen)->setPrimary(
true);
373 virtualDesktop->
setScreens(std::move(siblings));
376void QXcbConnection::initializeScreensFromOutput(xcb_screen_iterator_t *
it,
int xcbScreenNumber,
QXcbScreen **primaryScreen)
382 xcb_screen_t *xcbScreen =
it->data;
384 m_virtualDesktops.
append(virtualDesktop);
390 auto resources_current =
Q_XCB_REPLY(xcb_randr_get_screen_resources_current,
392 decltype(
Q_XCB_REPLY(xcb_randr_get_screen_resources,
394 if (!resources_current) {
395 qWarning(
"failed to get the current screen resources");
397 xcb_timestamp_t timestamp = 0;
398 xcb_randr_output_t *outputs =
nullptr;
399 int outputCount = xcb_randr_get_screen_resources_current_outputs_length(resources_current.get());
401 timestamp = resources_current->config_timestamp;
402 outputs = xcb_randr_get_screen_resources_current_outputs(resources_current.get());
404 resources =
Q_XCB_REPLY(xcb_randr_get_screen_resources,
407 qWarning(
"failed to get the screen resources");
409 timestamp = resources->config_timestamp;
410 outputCount = xcb_randr_get_screen_resources_outputs_length(resources.get());
411 outputs = xcb_randr_get_screen_resources_outputs(resources.get());
418 qWarning(
"failed to get the primary output of the screen");
420 for (
int i = 0;
i < outputCount;
i++) {
427 if (
output->connection != XCB_RANDR_CONNECTION_CONNECTED) {
430 xcb_randr_get_output_info_name_length(
output.get()))));
434 if (
output->crtc == XCB_NONE) {
437 xcb_randr_get_output_info_name_length(
output.get()))));
450 if (!(*
primaryScreen) || (primary && outputs[
i] == primary->output)) {
452 (*primaryScreen)->setPrimary(
false);
454 (*primaryScreen)->setPrimary(
true);
471 (*primaryScreen)->setPrimary(
true);
475 virtualDesktop->
setScreens(std::move(siblings));
478void QXcbConnection::initializeScreensFromMonitor(xcb_screen_iterator_t *
it,
int xcbScreenNumber,
QXcbScreen **primaryScreen,
bool initialized)
484 xcb_screen_t *xcbScreen =
it->data;
487 virtualDesktop = virtualDesktopForNumber(xcbScreenNumber);
488 if (!virtualDesktop) {
490 m_virtualDesktops.
append(virtualDesktop);
500 xcb_randr_get_monitors_cookie_t monitors_c = xcb_randr_get_monitors(
xcb_connection(), xcbScreen->root, 1);
501 xcb_randr_get_monitors_reply_t *monitors_r = xcb_randr_get_monitors_reply(
xcb_connection(), monitors_c,
nullptr);
504 qWarning(
"RANDR GetMonitors failed; this should not be possible");
508 xcb_randr_monitor_info_iterator_t monitor_iter = xcb_randr_get_monitors_monitors_iterator(monitors_r);
509 while (monitor_iter.rem) {
510 xcb_randr_monitor_info_t *monitor_info = monitor_iter.data;
513 screen =
new QXcbScreen(
this, virtualDesktop, monitor_info, monitors_r->timestamp);
515 screen = findScreenForMonitorInfo(old, monitor_info);
517 screen = createScreen_monitor(virtualDesktop, monitor_info, monitors_r->timestamp);
519 updateScreen_monitor(
screen, monitor_info, monitors_r->timestamp);
530 (*primaryScreen)->setPrimary(
false);
532 (*primaryScreen)->setPrimary(
true);
536 xcb_randr_monitor_info_next(&monitor_iter);
542 if (initialized && !old.
isEmpty()) {
547 screen->setMonitor(
nullptr, XCB_NONE);
548 qCDebug(lcQpaScreen) <<
"transformed" << nameWas <<
"to fake" <<
screen;
557 (*primaryScreen)->setPrimary(
true);
566 qCDebug(lcQpaScreen) <<
"destroy screen: " << ps;
571 virtualDesktop->
setScreens(std::move(siblings));
qsizetype size() const noexcept
bool isEmpty() const noexcept
bool removeOne(const AT &t)
void swapItemsAt(qsizetype i, qsizetype j)
const_reference at(qsizetype i) const noexcept
qsizetype removeAll(const AT &t)
void prepend(rvalue_ref t)
void append(parameter_type t)
\inmodule QtCore\reentrant
QString name
a user presentable string representing the screen
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static void handlePrimaryScreenChanged(QPlatformScreen *newPrimary)
Should be called whenever the primary screen changes.
static void handleScreenAdded(QPlatformScreen *screen, bool isPrimary=false)
Should be called by the implementation whenever a new screen is added.
static void handleScreenRemoved(QPlatformScreen *screen)
Should be called by the implementation whenever a screen is removed.
bool isAtLeastXRandR15() const
int primaryScreenNumber() const
QByteArray atomName(xcb_atom_t atom)
xcb_connection_t * xcb_connection() const
const xcb_setup_t * setup() const
bool isAtLeastXRandR12() const
xcb_window_t rootWindow()
QXcbScreen * primaryScreen() const
const QList< QXcbScreen * > & screens() const
xcb_randr_output_t output() const
void setPrimary(bool primary)
void addScreen(QPlatformScreen *s)
QList< QPlatformScreen * > screens() const
void setScreens(QList< QPlatformScreen * > &&sl)
void removeScreen(QPlatformScreen *s)
QSet< QString >::iterator it
#define qCDebug(category,...)
#define qPrintable(string)
QT_BEGIN_NAMESPACE typedef uchar * output
#define Q_XCB_REPLY(call,...)
#define Q_XCB_REPLY_UNCHECKED(call,...)
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
bool contains(const AT &t) const noexcept