diff options
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbscreen.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbscreen.cpp | 220 |
1 files changed, 139 insertions, 81 deletions
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 7136455754..383adf9734 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ @@ -48,10 +48,15 @@ QT_BEGIN_NAMESPACE QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, - xcb_randr_get_output_info_reply_t *output, QString outputName, int number) + xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output, + QString outputName, int number) : QXcbObject(connection) , m_screen(scr) + , m_output(outputId) , m_crtc(output ? output->crtc : 0) + , m_mode(XCB_NONE) + , m_primary(false) + , m_rotation(XCB_RANDR_ROTATION_ROTATE_0) , m_outputName(outputName) , m_outputSizeMillimeters(output ? QSize(output->mm_width, output->mm_height) : QSize()) , m_virtualSize(scr->width_in_pixels, scr->height_in_pixels) @@ -67,11 +72,20 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, , m_antialiasingEnabled(-1) , m_xSettings(0) { - if (connection->hasXRandr()) + if (connection->hasXRandr()) { xcb_randr_select_input(xcb_connection(), screen()->root, true); - - updateGeometry(output ? output->timestamp : 0); - updateRefreshRate(); + xcb_randr_get_crtc_info_cookie_t crtcCookie = + xcb_randr_get_crtc_info_unchecked(xcb_connection(), m_crtc, output ? output->timestamp : 0); + xcb_randr_get_crtc_info_reply_t *crtc = + xcb_randr_get_crtc_info_reply(xcb_connection(), crtcCookie, NULL); + if (crtc) { + updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation); + updateRefreshRate(crtc->mode); + free(crtc); + } + } else { + updateGeometry(output ? output->timestamp : 0); + } const int dpr = int(devicePixelRatio()); // On VNC, it can be that physical size is unknown while @@ -93,25 +107,6 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, if (dpr_scaling_enabled) m_noFontHinting = true; -#ifdef Q_XCB_DEBUG - qDebug(); - qDebug("Screen output %s of xcb screen %d:", m_outputName.toUtf8().constData(), m_number); - qDebug(" width..........: %lf", m_sizeMillimeters.width()); - qDebug(" height.........: %lf", m_sizeMillimeters.height()); - qDebug(" geometry.......: %d x %d +%d +%d", m_geometry.width(), m_geometry.height(), m_geometry.x(), m_geometry.y()); - qDebug(" virtual width..: %lf", m_virtualSizeMillimeters.width()); - qDebug(" virtual height.: %lf", m_virtualSizeMillimeters.height()); - qDebug(" virtual geom...: %d x %d", m_virtualSize.width(), m_virtualSize.height()); - qDebug(" avail virt geom: %d x %d +%d +%d", m_availableGeometry.width(), m_availableGeometry.height(), m_availableGeometry.x(), m_availableGeometry.y()); - qDebug(" orientation....: %d", m_orientation); - qDebug(" pixel ratio....: %d", m_devicePixelRatio); - qDebug(" depth..........: %d", screen()->root_depth); - qDebug(" white pixel....: %x", screen()->white_pixel); - qDebug(" black pixel....: %x", screen()->black_pixel); - qDebug(" refresh rate...: %d", m_refreshRate); - qDebug(" root ID........: %x", screen()->root); -#endif - QScopedPointer<xcb_get_window_attributes_reply_t, QScopedPointerPodDeleter> rootAttribs( xcb_get_window_attributes_reply(xcb_connection(), xcb_get_window_attributes_unchecked(xcb_connection(), screen()->root), NULL)); @@ -146,10 +141,6 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, atom(QXcbAtom::UTF8_STRING), 0, 1024), NULL); if (windowManagerReply && windowManagerReply->format == 8 && windowManagerReply->type == atom(QXcbAtom::UTF8_STRING)) { m_windowManagerName = QString::fromUtf8((const char *)xcb_get_property_value(windowManagerReply), xcb_get_property_value_length(windowManagerReply)); -#ifdef Q_XCB_DEBUG - qDebug(" window manager.: %s", qPrintable(m_windowManagerName)); - qDebug(); -#endif } free(windowManagerReply); @@ -337,7 +328,7 @@ QDpi QXcbScreen::logicalDpi() const qreal QXcbScreen::devicePixelRatio() const { - static int override_dpr = qgetenv("QT_DEVICE_PIXEL_RATIO").toInt(); + static int override_dpr = qEnvironmentVariableIntValue("QT_DEVICE_PIXEL_RATIO"); static bool auto_dpr = qgetenv("QT_DEVICE_PIXEL_RATIO").toLower() == "auto"; if (override_dpr > 0) return override_dpr; @@ -375,9 +366,15 @@ QPlatformCursor *QXcbScreen::cursor() const */ void QXcbScreen::handleScreenChange(xcb_randr_screen_change_notify_event_t *change_event) { - updateGeometry(change_event->config_timestamp); + // No need to do anything when screen rotation did not change - if any + // xcb output geometry has changed, we will get RRCrtcChangeNotify and + // RROutputChangeNotify events next + if (change_event->rotation == m_rotation) + return; - switch (change_event->rotation) { + m_rotation = change_event->rotation; + updateGeometry(change_event->timestamp); + switch (m_rotation) { case XCB_RANDR_ROTATION_ROTATE_0: // xrandr --rotate normal m_orientation = Qt::LandscapeOrientation; m_virtualSize.setWidth(change_event->width); @@ -417,39 +414,49 @@ void QXcbScreen::handleScreenChange(xcb_randr_screen_change_notify_event_t *chan 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) { - QRect xGeometry; - QRect xAvailableGeometry; + xcb_randr_get_crtc_info_cookie_t crtcCookie = + xcb_randr_get_crtc_info_unchecked(xcb_connection(), m_crtc, timestamp); + xcb_randr_get_crtc_info_reply_t *crtc = + xcb_randr_get_crtc_info_reply(xcb_connection(), crtcCookie, NULL); + if (crtc) { + updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation); + free(crtc); + } +} - if (connection()->hasXRandr()) { - xcb_randr_get_crtc_info_reply_t *crtc = xcb_randr_get_crtc_info_reply(xcb_connection(), - xcb_randr_get_crtc_info_unchecked(xcb_connection(), m_crtc, timestamp), NULL); - if (crtc) { - xGeometry = QRect(crtc->x, crtc->y, crtc->width, crtc->height); - xAvailableGeometry = xGeometry; - switch (crtc->rotation) { - case XCB_RANDR_ROTATION_ROTATE_0: // xrandr --rotate normal - m_orientation = Qt::LandscapeOrientation; - m_sizeMillimeters = m_outputSizeMillimeters; - break; - case XCB_RANDR_ROTATION_ROTATE_90: // xrandr --rotate left - m_orientation = Qt::PortraitOrientation; - m_sizeMillimeters = m_outputSizeMillimeters.transposed(); - break; - case XCB_RANDR_ROTATION_ROTATE_180: // xrandr --rotate inverted - m_orientation = Qt::InvertedLandscapeOrientation; - m_sizeMillimeters = m_outputSizeMillimeters; - break; - case XCB_RANDR_ROTATION_ROTATE_270: // xrandr --rotate right - m_orientation = Qt::InvertedPortraitOrientation; - m_sizeMillimeters = m_outputSizeMillimeters.transposed(); - break; - } - free(crtc); - } +void QXcbScreen::updateGeometry(const QRect &geom, uint8_t rotation) +{ + QRect xGeometry = geom; + QRect xAvailableGeometry = xGeometry; + switch (rotation) { + case XCB_RANDR_ROTATION_ROTATE_0: // xrandr --rotate normal + m_orientation = Qt::LandscapeOrientation; + m_sizeMillimeters = m_outputSizeMillimeters; + break; + case XCB_RANDR_ROTATION_ROTATE_90: // xrandr --rotate left + m_orientation = Qt::PortraitOrientation; + m_sizeMillimeters = m_outputSizeMillimeters.transposed(); + break; + case XCB_RANDR_ROTATION_ROTATE_180: // xrandr --rotate inverted + m_orientation = Qt::InvertedLandscapeOrientation; + m_sizeMillimeters = m_outputSizeMillimeters; + break; + case XCB_RANDR_ROTATION_ROTATE_270: // xrandr --rotate right + m_orientation = Qt::InvertedPortraitOrientation; + m_sizeMillimeters = m_outputSizeMillimeters.transposed(); + break; } xcb_get_property_reply_t * workArea = @@ -478,31 +485,38 @@ void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp) m_geometry = QRect(xGeometry.topLeft()/dpr, xGeometry.size()/dpr); m_nativeGeometry = QRect(xGeometry.topLeft(), xGeometry.size()); m_availableGeometry = QRect(xAvailableGeometry.topLeft()/dpr, xAvailableGeometry.size()/dpr); - QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry); } -void QXcbScreen::updateRefreshRate() +void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode) { if (!connection()->hasXRandr()) return; - int rate = m_refreshRate; - - xcb_randr_get_screen_info_reply_t *screenInfoReply = - xcb_randr_get_screen_info_reply(xcb_connection(), xcb_randr_get_screen_info_unchecked(xcb_connection(), m_screen->root), 0); - - if (screenInfoReply) { - rate = screenInfoReply->rate; - free(screenInfoReply); - } - - if (rate == m_refreshRate) + if (m_mode == mode) return; - m_refreshRate = rate; + // we can safely use get_screen_resources_current here, because in order to + // get here, we must have called get_screen_resources before + xcb_randr_get_screen_resources_current_cookie_t resourcesCookie = + xcb_randr_get_screen_resources_current_unchecked(xcb_connection(), m_screen->root); + xcb_randr_get_screen_resources_current_reply_t *resources = + xcb_randr_get_screen_resources_current_reply(xcb_connection(), resourcesCookie, NULL); + if (resources) { + xcb_randr_mode_info_iterator_t modesIter = + xcb_randr_get_screen_resources_current_modes_iterator(resources); + for (; modesIter.rem; xcb_randr_mode_info_next(&modesIter)) { + xcb_randr_mode_info_t *modeInfo = modesIter.data; + if (modeInfo->id == mode) { + m_refreshRate = modeInfo->dot_clock / (modeInfo->htotal * modeInfo->vtotal); + m_mode = mode; + break; + } + } - QWindowSystemInterface::handleScreenRefreshRateChange(QPlatformScreen::screen(), rate); + free(resources); + QWindowSystemInterface::handleScreenRefreshRateChange(QPlatformScreen::screen(), m_refreshRate); + } } QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height) const @@ -702,4 +716,48 @@ QXcbXSettings *QXcbScreen::xSettings() const } return m_xSettings; } + +static inline void formatRect(QDebug &debug, const QRect r) +{ + debug << r.width() << 'x' << r.height() + << forcesign << r.x() << r.y() << noforcesign; +} + +static inline void formatSizeF(QDebug &debug, const QSizeF s) +{ + debug << s.width() << 'x' << s.height() << "mm"; +} + +Q_XCB_EXPORT QDebug operator<<(QDebug debug, const QXcbScreen *screen) +{ + const QDebugStateSaver saver(debug); + debug.nospace(); + debug << "QXcbScreen(" << (const void *)screen; + if (screen) { + debug << fixed << qSetRealNumberPrecision(1); + debug << ", name=" << screen->name(); + debug << ", geometry="; + formatRect(debug, screen->geometry()); + debug << ", availableGeometry="; + formatRect(debug, screen->availableGeometry()); + debug << ", devicePixelRatio=" << screen->devicePixelRatio(); + debug << ", logicalDpi=" << screen->logicalDpi(); + debug << ", physicalSize="; + formatSizeF(debug, screen->physicalSize()); + // TODO 5.6 if (debug.verbosity() > 2) { + debug << ", screenNumber=" << screen->screenNumber(); + debug << ", virtualSize=" << screen->virtualSize().width() << "x" << screen->virtualSize().height() << " ("; + formatSizeF(debug, screen->virtualSize()); + debug << "), nativeGeometry="; + formatRect(debug, screen->nativeGeometry()); + debug << ", orientation=" << screen->orientation(); + debug << ", depth=" << screen->depth(); + debug << ", refreshRate=" << screen->refreshRate(); + debug << ", root=" << hex << screen->root(); + debug << ", windowManagerName=" << screen->windowManagerName(); + } + debug << ')'; + return debug; +} + QT_END_NAMESPACE |