diff options
author | Błażej Szczygieł <spaz16@wp.pl> | 2015-10-16 22:51:59 +0200 |
---|---|---|
committer | Błażej Szczygieł <spaz16@wp.pl> | 2015-12-11 17:32:43 +0000 |
commit | a094af001795c9651b299d700a992150d1aba33a (patch) | |
tree | b5ad6cf63c8a5e5c66ccee91f8ee43c28a7a58e9 /src/plugins/platforms/xcb/qxcbscreen.cpp | |
parent | 0c33a823c560bdf18a513ae460eea4d7bdf9e115 (diff) |
xcb: Use a placeholder QScreen when there are no outputs connected
If no screens are available, windows could disappear, could stop rendering
graphics, or the application could crash. This is a real use case in several
scenarios: with x11vnc, when all monitors are physically disconnected from a
desktop machine, or in some cases even when the monitor sleeps. Now when the
last screen is disconnected, it is transformed into a fake screen. When a
physical screen appears, the fake QScreen is transformed into a representation
of the physical screen. Every virtual desktop has its own fake screen, and
primary screens must belong to the primary virtual desktop. It fixes updating
screen geometry on temporarily disabled screens in the middle of the mode
switch.
Expected results: Windows don't disappear, the application doesn't
crash, and QMenu is displayed on the appropriate screen.
This reverts patch 51ada7734ad780178ecced11e0dff454dfc2e5f2
Change-Id: I6e8eb682b0c8425d08ffdaecbd4c6c7700c914b4
Task-number: QTBUG-42985
Reviewed-by: Shawn Rutledge <shawn.rutledge@theqtcompany.com>
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbscreen.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbscreen.cpp | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 0e99d58679..f05432ef68 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -81,6 +81,13 @@ void QXcbVirtualDesktop::addScreen(QPlatformScreen *s) ((QXcbScreen *) s)->isPrimary() ? m_screens.prepend(s) : m_screens.append(s); } +void QXcbVirtualDesktop::setPrimaryScreen(QPlatformScreen *s) +{ + const int idx = m_screens.indexOf(s); + Q_ASSERT(idx > -1); + m_screens.swap(0, idx); +} + QXcbXSettings *QXcbVirtualDesktop::xSettings() const { if (!m_xSettings) { @@ -149,16 +156,15 @@ void QXcbVirtualDesktop::updateWorkArea() } QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop, - xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output, - QString outputName) + xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output) : QXcbObject(connection) , m_virtualDesktop(virtualDesktop) , m_output(outputId) - , m_crtc(output ? output->crtc : 0) + , m_crtc(output ? output->crtc : XCB_NONE) , m_mode(XCB_NONE) , m_primary(false) , m_rotation(XCB_RANDR_ROTATION_ROTATE_0) - , m_outputName(outputName) + , m_outputName(getOutputName(output)) , m_outputSizeMillimeters(output ? QSize(output->mm_width, output->mm_height) : QSize()) , m_virtualSize(virtualDesktop->size()) , m_virtualSizeMillimeters(virtualDesktop->physicalSize()) @@ -268,6 +274,22 @@ QXcbScreen::~QXcbScreen() delete m_cursor; } +QString QXcbScreen::getOutputName(xcb_randr_get_output_info_reply_t *outputInfo) +{ + QString name; + if (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()); + } + return name; +} QWindow *QXcbScreen::topLevelAt(const QPoint &p) const { @@ -392,6 +414,16 @@ QPlatformCursor *QXcbScreen::cursor() const return m_cursor; } +void QXcbScreen::setOutput(xcb_randr_output_t outputId, + xcb_randr_get_output_info_reply_t *outputInfo) +{ + m_output = outputId; + m_crtc = outputInfo ? outputInfo->crtc : XCB_NONE; + m_mode = XCB_NONE; + m_outputName = getOutputName(outputInfo); + // TODO: Send an event to the QScreen instance that the screen changed its name +} + /*! \brief handle the XCB screen change event and update properties @@ -460,19 +492,10 @@ void QXcbScreen::handleScreenChange(xcb_randr_screen_change_notify_event_t *chan updateGeometry(change_event->timestamp); - QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry()); QWindowSystemInterface::handleScreenOrientationChange(QPlatformScreen::screen(), m_orientation); QDpi ldpi = logicalDpi(); QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(QPlatformScreen::screen(), ldpi.first, ldpi.second); - - // Windows which had null screens have already had expose events by now. - // They need to be told the screen is back, it's OK to render. - foreach (QWindow *window, QGuiApplication::topLevelWindows()) { - QXcbWindow *xcbWin = static_cast<QXcbWindow*>(window->handle()); - if (xcbWin) - xcbWin->maybeSetScreen(this); - } } void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp) |