From f280efc6201adf8933c9d48a1d5b6983ee9fed9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 4 May 2012 13:10:41 +0200 Subject: Added QScreen::refreshRate() to get the vertical refresh rate. To give applications that want it the option to use a fixed timestep for animations, and to avoid having values of 60 hard-coded (we have a couple of those in qtdeclarative/src/quick already), we need to know the refresh rates of the screens we are rendering to. Change-Id: Ife49162e830440ad7eab563a27e8aebbbafc5fc5 Reviewed-by: Girish Ramakrishnan Reviewed-by: Friedemann Kleint Reviewed-by: Lars Knoll --- src/plugins/platforms/windows/qwindowsscreen.cpp | 6 +++- src/plugins/platforms/windows/qwindowsscreen.h | 2 ++ src/plugins/platforms/xcb/README | 4 +-- src/plugins/platforms/xcb/qxcbconnection.cpp | 39 ++++++++++++++++++++++++ src/plugins/platforms/xcb/qxcbconnection.h | 4 +++ src/plugins/platforms/xcb/qxcbscreen.cpp | 39 ++++++++++++++++++++++++ src/plugins/platforms/xcb/qxcbscreen.h | 4 +++ src/plugins/platforms/xcb/xcb.pro | 2 +- 8 files changed, 96 insertions(+), 4 deletions(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 2476e15169..cc694fe0ea 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -59,7 +59,8 @@ QT_BEGIN_NAMESPACE QWindowsScreenData::QWindowsScreenData() : dpi(96, 96), depth(32), format(QImage::Format_ARGB32_Premultiplied), - flags(VirtualDesktop), orientation(Qt::LandscapeOrientation) + flags(VirtualDesktop), orientation(Qt::LandscapeOrientation), + refreshRateHz(60) { } @@ -103,6 +104,9 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM data.depth = GetDeviceCaps(hdc, BITSPIXEL); data.format = data.depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; data.physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE)); + const int refreshRate = GetDeviceCaps(hdc, VREFRESH); + if (refreshRate > 1) // 0,1 means heardware default. + data.refreshRateHz = refreshRate; DeleteDC(hdc); } else { qWarning("%s: Unable to obtain handle for monitor '%s', defaulting to %g DPI.", diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 56e9ab304e..615d4faf15 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -70,6 +70,7 @@ struct QWindowsScreenData unsigned flags; QString name; Qt::ScreenOrientation orientation; + qreal refreshRateHz; }; class QWindowsScreen : public QPlatformScreen @@ -87,6 +88,7 @@ public: virtual QImage::Format format() const { return m_data.format; } virtual QSizeF physicalSize() const { return m_data.physicalSizeMM; } virtual QDpi logicalDpi() const { return m_data.dpi; } + virtual qreal refreshRate() const { return m_data.refreshRateHz; } virtual QString name() const { return m_data.name; } virtual Qt::ScreenOrientation primaryOrientation() { return m_data.orientation; } virtual QList virtualSiblings() const; diff --git a/src/plugins/platforms/xcb/README b/src/plugins/platforms/xcb/README index eede0cc149..14e98b8145 100644 --- a/src/plugins/platforms/xcb/README +++ b/src/plugins/platforms/xcb/README @@ -1,8 +1,8 @@ Requires libxcb >= 1.5. Required packages: -libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev +libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev On Ubuntu 11.10 icccm1 is replaced by icccm4 and xcb-render-util is not available: -libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev +libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev The packages for xcb-render-util can be installed manually from http://packages.ubuntu.com/natty/libxcb-render-util0 and http://packages.ubuntu.com/natty/libxcb-render-util0-dev diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 76979bf05f..728dd1dd00 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #ifdef XCB_USE_XLIB #include @@ -109,7 +110,9 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char , m_has_support_for_dri2(false) #endif , xfixes_first_event(0) + , xrandr_first_event(0) , has_shape_extension(false) + , has_randr_extension(false) , has_input_shape(false) { m_primaryScreen = 0; @@ -160,6 +163,8 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup); + initializeXRandr(); + int screenNumber = 0; while (it.rem) { m_screens << new QXcbScreen(this, it.data, screenNumber++); @@ -586,6 +591,15 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) setTime(((xcb_xfixes_selection_notify_event_t *)event)->timestamp); m_clipboard->handleXFixesSelectionRequest((xcb_xfixes_selection_notify_event_t *)event); handled = true; + } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { + xcb_randr_screen_change_notify_event_t *change_event = (xcb_randr_screen_change_notify_event_t *)event; + foreach (QXcbScreen *s, m_screens) { + if (s->root() == change_event->root ) { + s->updateRefreshRate(); + break; + } + } + handled = true; } } @@ -1060,6 +1074,31 @@ void QXcbConnection::initializeXRender() #endif } +void QXcbConnection::initializeXRandr() +{ + const xcb_query_extension_reply_t *xrandr_reply = xcb_get_extension_data(m_connection, &xcb_randr_id); + if (!xrandr_reply || !xrandr_reply->present) + return; + + xrandr_first_event = xrandr_reply->first_event; + + xcb_generic_error_t *error = 0; + xcb_randr_query_version_cookie_t xrandr_query_cookie = xcb_randr_query_version(m_connection, + XCB_RANDR_MAJOR_VERSION, + XCB_RANDR_MINOR_VERSION); + + has_randr_extension = true; + + xcb_randr_query_version_reply_t *xrandr_query = xcb_randr_query_version_reply(m_connection, + xrandr_query_cookie, &error); + if (!xrandr_query || error || (xrandr_query->major_version < 1 || (xrandr_query->major_version == 1 && xrandr_query->minor_version < 2))) { + qWarning("QXcbConnection: Failed to initialize XRandr"); + free(error); + has_randr_extension = false; + } + free(xrandr_query); +} + void QXcbConnection::initializeXShape() { const xcb_query_extension_reply_t *xshape_reply = xcb_get_extension_data(m_connection, &xcb_shape_id); diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 34943bfdef..86eaf5d7d9 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -355,6 +355,7 @@ public: bool hasXFixes() const { return xfixes_first_event > 0; } bool hasXShape() const { return has_shape_extension; } + bool hasXRandr() const { return has_randr_extension; } bool hasInputShape() const { return has_input_shape; } private slots: @@ -365,6 +366,7 @@ private: void sendConnectionEvent(QXcbAtom::Atom atom, uint id = 0); void initializeXFixes(); void initializeXRender(); + void initializeXRandr(); void initializeXShape(); #ifdef XCB_USE_DRI2 void initializeDri2(); @@ -432,8 +434,10 @@ private: QVector m_peekFuncs; uint32_t xfixes_first_event; + uint32_t xrandr_first_event; bool has_shape_extension; + bool has_randr_extension; bool has_input_shape; }; diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index ae5e4cce34..fbfaa894eb 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -48,13 +48,23 @@ #include +#include + +#include + QT_BEGIN_NAMESPACE QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int number) : QXcbObject(connection) , m_screen(screen) , m_number(number) + , m_refreshRate(60) { + if (connection->hasXRandr()) + xcb_randr_select_input(xcb_connection(), screen->root, true); + + updateRefreshRate(); + #ifdef Q_XCB_DEBUG qDebug(); qDebug("Information of screen %d:", screen->root); @@ -63,6 +73,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num 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(); #endif @@ -228,6 +239,34 @@ QPlatformCursor *QXcbScreen::cursor() const return m_cursor; } +qreal QXcbScreen::refreshRate() const +{ + return m_refreshRate; +} + +void QXcbScreen::updateRefreshRate() +{ + 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) + return; + + m_refreshRate = rate; + + QWindowSystemInterface::handleScreenRefreshRateChange(QPlatformScreen::screen(), rate); +} + int QXcbScreen::screenNumber() const { return m_number; diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index ba3f4aff8d..7a81d8b43a 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -69,6 +69,7 @@ public: QImage::Format format() const; QSizeF physicalSize() const; QPlatformCursor *cursor() const; + qreal refreshRate() const; int screenNumber() const; @@ -84,6 +85,8 @@ public: QString name() const; + void updateRefreshRate(); + private: xcb_screen_t *m_screen; int m_number; @@ -92,6 +95,7 @@ private: xcb_window_t m_clientLeader; QMap m_visuals; QXcbCursor *m_cursor; + int m_refreshRate; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro index 0da5fb1674..210b770a51 100644 --- a/src/plugins/platforms/xcb/xcb.pro +++ b/src/plugins/platforms/xcb/xcb.pro @@ -91,7 +91,7 @@ contains(DEFINES, XCB_USE_DRI2) { } } -LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shape -lxcb-shm +LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shape -lxcb-shm -lxcb-randr DEFINES += $$QMAKE_DEFINES_XCB LIBS += $$QMAKE_LIBS_XCB -- cgit v1.2.3