xcb: fix for multi-X11Screen systems via xrandr 1.5

Fix support for systems with several X11 screens (or "virtual desktops"
i.e. DISPLAY=":0.0" and ":0.1"). Namely, call
QWindowSystemInterface::handle*() only after we settled on which screen
will be primary. Also cleanup some code logic, particularly, make sure
that  QXcbConnection::m_screens is stores screen in a reliable order:
 - Primary screen for primary virtual desktop
 - Other screens for primary virtual desktop
 - Screens for other virtual desktops (primary screen is first)

Pick-to: 6.5
Fixes: QTBUG-110898
Fixes: QTBUG-130714
Change-Id: I3e78e56466998dff4d7da83db45f0ed61463f041
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
Reviewed-by: Liang Qi <liang.qi@qt.io>
(cherry picked from commit 64590233aff4f7e9797f37484dbdd6d8465a1ea9)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Alexander Golubev 2024-11-07 17:02:23 +03:00 committed by Qt Cherry-pick Bot
parent b63cceb1b0
commit 2b3d867d9f
2 changed files with 44 additions and 52 deletions

View File

@ -226,9 +226,6 @@ private:
void initializeScreensWithoutXRandR(xcb_screen_iterator_t *it, int screenNumber, QXcbScreen **primaryScreen);
void initializeScreensFromOutput(xcb_screen_iterator_t *it, int screenNumber, QXcbScreen **primaryScreen);
void updateScreen_monitor(QXcbScreen *screen, xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp = XCB_NONE);
QXcbScreen *createScreen_monitor(QXcbVirtualDesktop *virtualDesktop,
xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp = XCB_NONE);
QXcbVirtualDesktop* virtualDesktopForNumber(int n) const;
QXcbScreen* findScreenForMonitorInfo(const QList<QPlatformScreen *> &screens, xcb_randr_monitor_info_t *monitorInfo);
void initializeScreensFromMonitor(xcb_screen_iterator_t *it, int screenNumber, QXcbScreen **primaryScreen, bool initialized);

View File

@ -246,40 +246,6 @@ void QXcbConnection::destroyScreen(QXcbScreen *screen)
}
}
void QXcbConnection::updateScreen_monitor(QXcbScreen *screen, xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
{
screen->setMonitor(monitorInfo, timestamp);
if (screen->isPrimary()) {
const int idx = m_screens.indexOf(screen);
if (idx > 0) {
std::as_const(m_screens).first()->setPrimary(false);
m_screens.swapItemsAt(0, idx);
}
screen->virtualDesktop()->setPrimaryScreen(screen);
QWindowSystemInterface::handlePrimaryScreenChanged(screen);
}
qCDebug(lcQpaScreen) << "updateScreen_monitor: update" << screen << "(Primary:" << screen->isPrimary() << ")";
}
QXcbScreen *QXcbConnection::createScreen_monitor(QXcbVirtualDesktop *virtualDesktop, xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
{
QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, monitorInfo, timestamp);
if (screen->isPrimary()) {
if (!m_screens.isEmpty())
std::as_const(m_screens).first()->setPrimary(false);
m_screens.prepend(screen);
} else {
m_screens.append(screen);
}
qCDebug(lcQpaScreen) << "createScreen_monitor: adding" << screen << "(Primary:" << screen->isPrimary() << ")";
virtualDesktop->addScreen(screen);
QWindowSystemInterface::handleScreenAdded(screen, screen->isPrimary());
return screen;
}
QXcbVirtualDesktop *QXcbConnection::virtualDesktopForNumber(int n) const
{
for (QXcbVirtualDesktop *virtualDesktop : m_virtualDesktops) {
@ -490,6 +456,7 @@ void QXcbConnection::initializeScreensFromMonitor(xcb_screen_iterator_t *it, int
m_virtualDesktops.append(virtualDesktop);
}
QList<QPlatformScreen *> old = virtualDesktop->m_screens;
QList<QXcbScreen *> newScreens;
QList<QPlatformScreen *> siblings;
@ -510,25 +477,26 @@ void QXcbConnection::initializeScreensFromMonitor(xcb_screen_iterator_t *it, int
} else {
screen = findScreenForMonitorInfo(old, monitor_info);
if (!screen) {
screen = createScreen_monitor(virtualDesktop, monitor_info, monitors_r->timestamp);
screen = new QXcbScreen(this, virtualDesktop, monitor_info, monitors_r->timestamp);
newScreens.append(screen);
} else {
updateScreen_monitor(screen, monitor_info, monitors_r->timestamp);
screen->setMonitor(monitor_info, monitors_r->timestamp);
old.removeAll(screen);
}
}
if (!m_screens.contains(screen))
m_screens << screen;
siblings << screen;
// similar logic with QXcbConnection::initializeScreensFromOutput()
if (screen->isPrimary()) {
siblings.prepend (screen);
if (primaryScreenNumber() == xcbScreenNumber) {
if (!(*primaryScreen) || monitor_info->primary) {
if (*primaryScreen)
(*primaryScreen)->setPrimary(false);
*primaryScreen = screen;
(*primaryScreen)->setPrimary(true);
siblings.prepend(siblings.takeLast());
} else { // Only screens on the main virtual desktop can be primary
screen->setPrimary(false);
}
} else {
siblings.append(screen);
}
xcb_randr_monitor_info_next(&monitor_iter);
@ -551,20 +519,47 @@ void QXcbConnection::initializeScreensFromMonitor(xcb_screen_iterator_t *it, int
qCDebug(lcQpaScreen) << "create a fake screen: " << screen;
}
siblings << screen;
}
if (primaryScreenNumber() == xcbScreenNumber) {
*primaryScreen = screen;
// If no screen was reported to be primary, use the first one
if (!*primaryScreen) {
(*primaryScreen) = static_cast<QXcbScreen *>(siblings.first());
(*primaryScreen)->setPrimary(true);
}
siblings << screen;
m_screens << screen;
// Prepand the siblings to the current list of screens
QList<QXcbScreen *> new_m_screens;
new_m_screens.reserve( siblings.size() + m_screens.size() );
for (QPlatformScreen *ps:siblings) {
new_m_screens.append(static_cast<QXcbScreen *>(ps));
}
new_m_screens.append(std::move(m_screens));
m_screens = std::move(new_m_screens);
} else {
for (QPlatformScreen *ps:siblings) {
m_screens.append(static_cast<QXcbScreen *>(ps));
}
}
if (initialized) {
if (primaryScreenNumber() == xcbScreenNumber && !newScreens.contains(*primaryScreen)) {
qCDebug(lcQpaScreen) << "assigning screen as primary: " << *primaryScreen;
virtualDesktop->setPrimaryScreen(*primaryScreen);
QWindowSystemInterface::handlePrimaryScreenChanged(*primaryScreen);
}
for (QXcbScreen *screen: newScreens) {
qCDebug(lcQpaScreen) << "adding screen: " << screen << "(Primary:" << screen->isPrimary() << ")";
virtualDesktop->addScreen(screen);
QWindowSystemInterface::handleScreenAdded(screen, screen->isPrimary());
}
for (QPlatformScreen *ps : old) {
virtualDesktop->removeScreen(ps);
qCDebug(lcQpaScreen) << "destroy screen: " << ps;
QWindowSystemInterface::handleScreenRemoved(ps);
virtualDesktop->removeScreen(ps);
}
}