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 <girish.1.ramakrishnan@nokia.com>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
bb10
Samuel Rødal 2012-05-04 13:10:41 +02:00 committed by Qt by Nokia
parent 4a58853aea
commit f280efc620
20 changed files with 164 additions and 5 deletions

View File

@ -50,6 +50,7 @@
#include <xcb/xcb_image.h>
#include <xcb/xcb_keysyms.h>
#include <xcb/sync.h>
#include <xcb/randr.h>
#include <xcb/shm.h>
int main(int, char **)

View File

@ -1,5 +1,5 @@
SOURCES = xcb.cpp
CONFIG -= qt
LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync -lxcb-xfixes
LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-randr

View File

@ -1090,6 +1090,10 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv
QGuiApplicationPrivate::reportLogicalDotsPerInchChange(
static_cast<QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *>(e));
break;
case QWindowSystemInterfacePrivate::ScreenRefreshRate:
QGuiApplicationPrivate::reportRefreshRateChange(
static_cast<QWindowSystemInterfacePrivate::ScreenRefreshRateEvent *>(e));
break;
case QWindowSystemInterfacePrivate::ThemeChange:
QGuiApplicationPrivate::processThemeChanged(
static_cast<QWindowSystemInterfacePrivate::ThemeChangeEvent *>(e));
@ -1750,6 +1754,21 @@ void QGuiApplicationPrivate::reportLogicalDotsPerInchChange(QWindowSystemInterfa
emit s->logicalDotsPerInchChanged(s->logicalDotsPerInch());
}
void QGuiApplicationPrivate::reportRefreshRateChange(QWindowSystemInterfacePrivate::ScreenRefreshRateEvent *e)
{
// This operation only makes sense after the QGuiApplication constructor runs
if (QCoreApplication::startingUp())
return;
if (!e->screen)
return;
QScreen *s = e->screen.data();
s->d_func()->refreshRate = e->rate;
emit s->refreshRateChanged(s->refreshRate());
}
void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::ExposeEvent *e)
{
if (!e->exposed)

View File

@ -117,6 +117,7 @@ public:
static void reportGeometryChange(QWindowSystemInterfacePrivate::ScreenGeometryEvent *e);
static void reportAvailableGeometryChange(QWindowSystemInterfacePrivate::ScreenAvailableGeometryEvent *e);
static void reportLogicalDotsPerInchChange(QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *e);
static void reportRefreshRateChange(QWindowSystemInterfacePrivate::ScreenRefreshRateEvent *e);
static void processThemeChanged(QWindowSystemInterfacePrivate::ThemeChangeEvent *tce);
static void processExposeEvent(QWindowSystemInterfacePrivate::ExposeEvent *e);

View File

@ -101,6 +101,8 @@ public:
virtual QSizeF physicalSize() const;
virtual QDpi logicalDpi() const;
virtual qreal refreshRate() const;
virtual Qt::ScreenOrientation orientation() const;
virtual QWindow *topLevelAt(const QPoint &point) const;

View File

@ -160,6 +160,17 @@ QDpi QPlatformScreen::logicalDpi() const
25.4 * s.height() / ps.height());
}
/*!
Reimplement this function in subclass to return the vertical refresh rate
of the screen, in Hz.
The default returns 60, a sensible default for modern displays.
*/
qreal QPlatformScreen::refreshRate() const
{
return 60;
}
/*!
Reimplement this function in subclass to return the current orientation
of the screen, for example based on accelerometer data to determine

View File

@ -363,6 +363,16 @@ Qt::ScreenOrientation QScreen::orientation() const
return d->orientation == Qt::PrimaryOrientation ? primaryOrientation() : d->orientation;
}
/*!
\property QScreen::refreshRate
\brief the approximate vertical refresh rate of the screen in Hz
*/
qreal QScreen::refreshRate() const
{
Q_D(const QScreen);
return d->refreshRate;
}
/*!
\property QScreen::primaryOrientation
\brief the primary screen orientation

View File

@ -83,6 +83,7 @@ class Q_GUI_EXPORT QScreen : public QObject
Q_PROPERTY(QRect availableGeometry READ availableGeometry NOTIFY availableGeometryChanged)
Q_PROPERTY(Qt::ScreenOrientation primaryOrientation READ orientation NOTIFY primaryOrientationChanged)
Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation NOTIFY orientationChanged)
Q_PROPERTY(qreal refreshRate READ refreshRate NOTIFY refreshRateChanged)
public:
QPlatformScreen *handle() const;
@ -127,6 +128,8 @@ public:
QPixmap grabWindow(WId window, int x, int y, int w, int h);
qreal refreshRate() const;
Q_SIGNALS:
void sizeChanged(const QSize &size);
void geometryChanged(const QRect &geometry);
@ -140,6 +143,7 @@ Q_SIGNALS:
void availableGeometryChanged(const QRect &rect);
void primaryOrientationChanged(Qt::ScreenOrientation orientation);
void orientationChanged(Qt::ScreenOrientation orientation);
void refreshRateChanged(qreal refreshRate);
private:
explicit QScreen(QPlatformScreen *screen);

View File

@ -63,6 +63,7 @@ public:
geometry = screen->geometry();
availableGeometry = screen->availableGeometry();
logicalDpi = screen->logicalDpi();
refreshRate = screen->refreshRate();
updatePrimaryOrientation();
}
@ -74,6 +75,7 @@ public:
QRect geometry;
QRect availableGeometry;
QDpi logicalDpi;
qreal refreshRate;
QPlatformScreen *platformScreen;
};

View File

@ -434,6 +434,13 @@ void QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(QScreen *scree
QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
}
void QWindowSystemInterface::handleScreenRefreshRateChange(QScreen *screen, qreal newRefreshRate)
{
QWindowSystemInterfacePrivate::ScreenRefreshRateEvent *e =
new QWindowSystemInterfacePrivate::ScreenRefreshRateEvent(screen, newRefreshRate);
QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
}
void QWindowSystemInterface::handleThemeChange(QWindow *tlw)
{
QWindowSystemInterfacePrivate::ThemeChangeEvent *e = new QWindowSystemInterfacePrivate::ThemeChangeEvent(tlw);

View File

@ -144,6 +144,7 @@ public:
static void handleScreenGeometryChange(QScreen *screen, const QRect &newGeometry);
static void handleScreenAvailableGeometryChange(QScreen *screen, const QRect &newAvailableGeometry);
static void handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal newDpiX, qreal newDpiY);
static void handleScreenRefreshRateChange(QScreen *screen, qreal newRefreshRate);
static void handleThemeChange(QWindow *tlw);

View File

@ -66,6 +66,7 @@ public:
ScreenGeometry,
ScreenAvailableGeometry,
ScreenLogicalDotsPerInch,
ScreenRefreshRate,
ThemeChange,
Expose
};
@ -233,6 +234,14 @@ public:
qreal dpiY;
};
class ScreenRefreshRateEvent : public WindowSystemEvent {
public:
ScreenRefreshRateEvent(QScreen *s, qreal r)
: WindowSystemEvent(ScreenRefreshRate), screen(s), rate(r) { }
QWeakPointer<QScreen> screen;
qreal rate;
};
class ThemeChangeEvent : public WindowSystemEvent {
public:
explicit ThemeChangeEvent(QWindow * w)

View File

@ -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.",

View File

@ -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<QPlatformScreen *> virtualSiblings() const;

View File

@ -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

View File

@ -60,6 +60,7 @@
#include <stdio.h>
#include <errno.h>
#include <xcb/xfixes.h>
#include <xcb/randr.h>
#ifdef XCB_USE_XLIB
#include <X11/Xlib.h>
@ -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);

View File

@ -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<PeekFunc> m_peekFuncs;
uint32_t xfixes_first_event;
uint32_t xrandr_first_event;
bool has_shape_extension;
bool has_randr_extension;
bool has_input_shape;
};

View File

@ -48,13 +48,23 @@
#include <QDebug>
#include <xcb/randr.h>
#include <QtGui/QWindowSystemInterface>
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;

View File

@ -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<xcb_visualid_t, xcb_visualtype_t> m_visuals;
QXcbCursor *m_cursor;
int m_refreshRate;
};
QT_END_NAMESPACE

View File

@ -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