xcb: convert last screen to fake when no screen

available for xrandr 1.5 like we did before for xrandr 1.4
(since a094af0017).

Tested with following combination:

* qtbase -DECM_ENABLE_SANITIZERS=address cmake build
* examples/widgets/widgets/wiggly with
ASAN_OPTIONS=verify_asan_link_order=0 env
* xrandr --output LastScreen --off and --auto.

Fixes: QTBUG-96247
Task-number: QTBUG-42985
Change-Id: Idd95d1a3aa057d23e3adb6635dd1acbb2c853497
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
bb10
Liang Qi 2021-09-14 21:22:08 +02:00
parent b2c3b3e8fe
commit d8f37d94e5
3 changed files with 57 additions and 17 deletions

View File

@ -378,7 +378,8 @@ void QXcbConnection::initializeScreens(bool initialized)
}
}
qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name();
if (!m_screens.isEmpty())
qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name();
}
}
@ -499,6 +500,8 @@ void QXcbConnection::initializeScreensFromMonitor(xcb_screen_iterator_t *it, int
m_virtualDesktops.append(virtualDesktop);
}
QList<QPlatformScreen*> old = virtualDesktop->m_screens;
if (initialized)
m_screens.clear();
QList<QPlatformScreen *> siblings;
@ -523,6 +526,7 @@ void QXcbConnection::initializeScreensFromMonitor(xcb_screen_iterator_t *it, int
screen = createScreen_monitor(virtualDesktop, monitor_info, monitors_r->timestamp);
QHighDpiScaling::updateHighDpiScaling();
} else {
m_screens << screen;
updateScreen_monitor(screen, monitor_info, monitors_r->timestamp);
old.removeAll(screen);
}
@ -530,14 +534,29 @@ void QXcbConnection::initializeScreensFromMonitor(xcb_screen_iterator_t *it, int
siblings << screen;
if (primaryScreenNumber() == xcbScreenNumber) {
primaryScreen = screen;
primaryScreen->setPrimary(true);
}
xcb_randr_monitor_info_next(&monitor_iter);
}
if (siblings.isEmpty()) {
// If there are no XRandR outputs or XRandR extension is missing,
// then create a fake/legacy screen.
auto screen = new QXcbScreen(this, virtualDesktop, nullptr);
qCDebug(lcQpaScreen) << "created fake screen" << screen;
QXcbScreen *screen = nullptr;
if (initialized && !old.isEmpty()) {
// If there are no other screens on the same virtual desktop,
// then transform the physical screen into a fake screen.
screen = static_cast<QXcbScreen *>(old.takeFirst());
const QString nameWas = screen->name();
screen->setMonitor(nullptr, XCB_NONE);
qCDebug(lcQpaScreen) << "transformed" << nameWas << "to fake" << screen;
} else {
// If there are no XRandR outputs or XRandR extension is missing,
// then create a fake/legacy screen.
screen = new QXcbScreen(this, virtualDesktop, nullptr);
qCDebug(lcQpaScreen) << "create a fake screen: " << screen;
}
if (primaryScreenNumber() == xcbScreenNumber) {
primaryScreen = screen;
@ -548,8 +567,11 @@ void QXcbConnection::initializeScreensFromMonitor(xcb_screen_iterator_t *it, int
}
if (initialized) {
for (QPlatformScreen *ps : old)
destroyScreen(static_cast<QXcbScreen*>(ps));
for (QPlatformScreen *ps : old) {
virtualDesktop->removeScreen(ps);
qCDebug(lcQpaScreen) << "destroy screen: " << ps;
QWindowSystemInterface::handleScreenRemoved(ps);
}
}
virtualDesktop->setScreens(std::move(siblings));

View File

@ -622,18 +622,28 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe
void QXcbScreen::setMonitor(xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
{
if (!connection()->isAtLeastXRandR15() || !monitorInfo)
if (!connection()->isAtLeastXRandR15())
return;
m_outputs.clear();
m_crtcs.clear();
if (!monitorInfo) {
m_monitor = nullptr;
m_output = XCB_NONE;
m_crtc = XCB_NONE;
m_mode = XCB_NONE;
m_outputName = defaultName();
// TODO: Send an event to the QScreen instance that the screen changed its name
return;
}
xcb_randr_select_input(xcb_connection(), screen()->root, true);
m_monitor = monitorInfo;
QRect monitorGeometry = QRect(m_monitor->x, m_monitor->y,
m_monitor->width, m_monitor->height);
m_outputs.clear();
m_crtcs.clear();
int outputCount = xcb_randr_monitor_info_outputs_length(m_monitor);
xcb_randr_output_t *outputs = nullptr;
if (outputCount) {
@ -702,6 +712,18 @@ void QXcbScreen::setMonitor(xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp
m_cursor = new QXcbCursor(connection(), this);
}
QString QXcbScreen::defaultName()
{
QString name;
QByteArray displayName = connection()->displayName();
int dotPos = displayName.lastIndexOf('.');
if (dotPos != -1)
displayName.truncate(dotPos);
name = QString::fromLocal8Bit(displayName) + QLatin1Char('.')
+ QString::number(m_virtualDesktop->number());
return name;
}
QXcbScreen::~QXcbScreen()
{
delete m_cursor;
@ -714,12 +736,7 @@ QString QXcbScreen::getOutputName(xcb_randr_get_output_info_reply_t *outputInfo)
name = QString::fromUtf8((const char*)xcb_randr_get_output_info_name(outputInfo),
xcb_randr_get_output_info_name_length(outputInfo));
} else {
QByteArray displayName = connection()->displayName();
int dotPos = displayName.lastIndexOf('.');
if (dotPos != -1)
displayName.truncate(dotPos);
name = QString::fromLocal8Bit(displayName) + QLatin1Char('.')
+ QString::number(m_virtualDesktop->number());
name = defaultName();
}
return name;
}

View File

@ -196,6 +196,7 @@ public:
xcb_randr_get_output_info_reply_t *outputInfo);
void setCrtc(xcb_randr_crtc_t crtc) { m_crtc = crtc; }
void setMonitor(xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp = XCB_NONE);
QString defaultName();
void windowShown(QXcbWindow *window);
QString windowManagerName() const { return m_virtualDesktop->windowManagerName(); }