summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@nokia.com>2012-09-05 13:44:44 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2012-09-18 14:12:27 +0200
commitbeab941e1fc11c8fe0914c6a3207ba029eb96112 (patch)
treed8e7a2a56130edbfeef1a6790013815fe99106e5 /src
parent5ea896fbc63593f424a7dfbb11387599c0025c74 (diff)
X11 (xcb) support for QScreen-per-output and runtime changes
QScreen has notifiers for its properties, but they were not being emitted when one changes the resolution or arrangement of individual outputs, e.g. via xrandr. Also there should be one QScreen per "output", e.g. laptop LCD + external monitor means 2 QScreens which will be siblings, rather than just 1 QScreen to represent the whole desktop. Change-Id: Ia61bbc5e6a3506f813ab11f87c03d14cf7f4ce85 Reviewed-by: Uli Schlachter <psychon@znc.in> Reviewed-by: Samuel Rødal <samuel.rodal@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/gui/kernel/qscreen.cpp14
-rw-r--r--src/gui/kernel/qscreen.h8
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp91
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp184
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h31
6 files changed, 263 insertions, 67 deletions
diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp
index 7a3854be81..13740e5c5f 100644
--- a/src/gui/kernel/qscreen.cpp
+++ b/src/gui/kernel/qscreen.cpp
@@ -286,6 +286,9 @@ QList<QScreen *> QScreen::virtualSiblings() const
}
/*!
+ \property QScreen::virtualSize
+ \brief the pixel size of the virtual desktop to which this screen belongs
+
Returns the pixel size of the virtual desktop corresponding to this screen.
This is the combined size of the virtual siblings' individual geometries.
@@ -298,6 +301,9 @@ QSize QScreen::virtualSize() const
}
/*!
+ \property QScreen::virtualGeometry
+ \brief the pixel geometry of the virtual desktop to which this screen belongs
+
Returns the pixel geometry of the virtual desktop corresponding to this screen.
This is the union of the virtual siblings' individual geometries.
@@ -313,6 +319,9 @@ QRect QScreen::virtualGeometry() const
}
/*!
+ \property QScreen::availableVirtualSize
+ \brief the available size of the virtual desktop to which this screen belongs
+
Returns the available pixel size of the virtual desktop corresponding to this screen.
This is the combined size of the virtual siblings' individual available geometries.
@@ -325,7 +334,10 @@ QSize QScreen::availableVirtualSize() const
}
/*!
- Returns the available size of the virtual desktop corresponding to this screen.
+ \property QScreen::availableVirtualGeometry
+ \brief the available geometry of the virtual desktop to which this screen belongs
+
+ Returns the available geometry of the virtual desktop corresponding to this screen.
This is the union of the virtual siblings' individual available geometries.
diff --git a/src/gui/kernel/qscreen.h b/src/gui/kernel/qscreen.h
index 5902d8c757..588a2cb445 100644
--- a/src/gui/kernel/qscreen.h
+++ b/src/gui/kernel/qscreen.h
@@ -71,7 +71,13 @@ class Q_GUI_EXPORT QScreen : public QObject
Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(int depth READ depth CONSTANT)
Q_PROPERTY(QSize size READ size NOTIFY sizeChanged)
+ Q_PROPERTY(QSize availableSize READ availableSize NOTIFY availableSizeChanged)
+ Q_PROPERTY(QSize virtualSize READ virtualSize NOTIFY sizeChanged)
+ Q_PROPERTY(QSize availableVirtualSize READ availableVirtualSize NOTIFY availableSizeChanged)
Q_PROPERTY(QRect geometry READ geometry NOTIFY geometryChanged)
+ Q_PROPERTY(QRect availableGeometry READ availableGeometry NOTIFY availableGeometryChanged)
+ Q_PROPERTY(QRect virtualGeometry READ virtualGeometry NOTIFY sizeChanged)
+ Q_PROPERTY(QRect availableVirtualGeometry READ availableVirtualGeometry NOTIFY availableGeometryChanged)
Q_PROPERTY(QSizeF physicalSize READ physicalSize CONSTANT)
Q_PROPERTY(qreal physicalDotsPerInchX READ physicalDotsPerInchX NOTIFY physicalDotsPerInchXChanged)
Q_PROPERTY(qreal physicalDotsPerInchY READ physicalDotsPerInchY NOTIFY physicalDotsPerInchYChanged)
@@ -79,8 +85,6 @@ class Q_GUI_EXPORT QScreen : public QObject
Q_PROPERTY(qreal logicalDotsPerInchX READ logicalDotsPerInchX NOTIFY logicalDotsPerInchXChanged)
Q_PROPERTY(qreal logicalDotsPerInchY READ logicalDotsPerInchY NOTIFY logicalDotsPerInchYChanged)
Q_PROPERTY(qreal logicalDotsPerInch READ logicalDotsPerInch NOTIFY logicalDotsPerInchChanged)
- Q_PROPERTY(QSize availableSize READ availableSize NOTIFY availableSizeChanged)
- Q_PROPERTY(QRect availableGeometry READ availableGeometry NOTIFY availableGeometryChanged)
Q_PROPERTY(Qt::ScreenOrientation primaryOrientation READ primaryOrientation NOTIFY primaryOrientationChanged)
Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation NOTIFY orientationChanged)
Q_PROPERTY(qreal refreshRate READ refreshRate NOTIFY refreshRateChanged)
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 11e1cc0c17..2d64a30a51 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -60,7 +60,6 @@
#include <stdio.h>
#include <errno.h>
#include <xcb/xfixes.h>
-#include <xcb/randr.h>
#ifdef XCB_USE_XLIB
#include <X11/Xlib.h>
@@ -101,9 +100,27 @@ static int nullErrorHandler(Display *, XErrorEvent *)
}
#endif
+QXcbScreen* QXcbConnection::createScreenWithFabricatedName(int screenNumber, xcb_screen_t* xcbScreen)
+{
+ QByteArray displayName = m_displayName;
+ int dotPos = displayName.lastIndexOf('.');
+ if (dotPos != -1)
+ displayName.truncate(dotPos);
+ QString name = displayName + QLatin1Char('.') + QString::number(screenNumber);
+ QXcbScreen *screen = new QXcbScreen(this, xcbScreen, NULL, name, screenNumber);
+ // make sure the primary screen appears first since it is used by QGuiApplication::primaryScreen()
+ if (m_primaryScreen == screenNumber) {
+ m_screens.prepend(screen);
+ } else {
+ m_screens.append(screen);
+ }
+ return screen;
+}
+
QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char *displayName)
: m_connection(0)
, m_primaryScreen(0)
+ , m_primaryOutput(-1)
, m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY"))
, m_nativeInterface(nativeInterface)
#ifdef XCB_USE_XINPUT2_MAEMO
@@ -171,14 +188,72 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char
int screenNumber = 0;
while (it.rem) {
- QXcbScreen *screen = new QXcbScreen(this, it.data, screenNumber);
- // make sure the primary screen appears first since it is used by QGuiApplication::primaryScreen()
- if (m_primaryScreen == screenNumber) {
- m_screens.prepend(screen);
+ // Each "screen" in xcb terminology is a virtual desktop,
+ // potentially a collection of separate juxtaposed monitors.
+ // Now iterate the individual outputs (e.g. DVI-I-1, VGA-1, etc.)
+ // and make a QScreen instance for each.
+ xcb_screen_t *xcbScreen = it.data;
+ QList<QPlatformScreen *> siblings;
+ if (has_randr_extension) {
+ xcb_randr_get_output_primary_cookie_t primaryCookie =
+ xcb_randr_get_output_primary_unchecked(xcb_connection(), xcbScreen->root);
+ xcb_randr_get_screen_resources_current_cookie_t resourcesCookie =
+ xcb_randr_get_screen_resources_current_unchecked(xcb_connection(), xcbScreen->root);
+ xcb_randr_get_output_primary_reply_t *primary =
+ xcb_randr_get_output_primary_reply(xcb_connection(), primaryCookie, NULL);
+ xcb_randr_get_screen_resources_current_reply_t *resources =
+ xcb_randr_get_screen_resources_current_reply(xcb_connection(), resourcesCookie, NULL);
+ xcb_timestamp_t timestamp = resources->config_timestamp;
+ int outputCount = xcb_randr_get_screen_resources_current_outputs_length(resources);
+ xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_current_outputs(resources);
+
+ if (outputCount == 0) {
+ // This happens on VNC for example. But there is actually a screen anyway.
+#ifdef Q_XCB_DEBUG
+ qDebug("Found a screen with zero outputs");
+#endif
+ QXcbScreen *screen = createScreenWithFabricatedName(screenNumber, it.data);
+ siblings << screen;
+ ++screenNumber;
+ }
+ for (int i = 0; i < outputCount; i++) {
+ xcb_randr_get_output_info_reply_t *output =
+ xcb_randr_get_output_info_reply(xcb_connection(),
+ xcb_randr_get_output_info_unchecked(xcb_connection(), outputs[i], timestamp), NULL);
+ if (output == NULL)
+ continue;
+ QString outputName = QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output),
+ xcb_randr_get_output_info_name_length(output));
+
+ if (output->crtc == XCB_NONE) {
+#ifdef Q_XCB_DEBUG
+ qDebug("Screen output %s is not connected", qPrintable(outputName));
+#endif
+ continue;
+ }
+
+ QXcbScreen *screen = new QXcbScreen(this, xcbScreen, output, outputName, screenNumber);
+ siblings << screen;
+ // make sure the primary screen appears first since it is used by QGuiApplication::primaryScreen()
+ if (outputs[i] == primary->output && m_primaryOutput < 0) {
+ m_primaryOutput = screenNumber;
+ m_screens.prepend(screen);
+ } else {
+ m_screens.append(screen);
+ }
+ ++screenNumber;
+ free(output);
+ }
+
+ free(primary);
+ free(resources);
} else {
- m_screens.append(screen);
+ QXcbScreen *screen = createScreenWithFabricatedName(screenNumber, it.data);
+ siblings << screen;
+ ++screenNumber;
}
- ++screenNumber;
+ foreach (QPlatformScreen* s, siblings)
+ ((QXcbScreen*)s)->setVirtualSiblings(siblings);
xcb_screen_next(&it);
}
@@ -637,8 +712,8 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
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->handleScreenChange(change_event);
s->updateRefreshRate();
- break;
}
}
handled = true;
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index d97db9a74d..8feca95ecc 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -398,6 +398,7 @@ private:
void handleGenericEventMaemo(xcb_ge_event_t *event);
#endif
void handleClientMessageEvent(const xcb_client_message_event_t *event);
+ QXcbScreen* createScreenWithFabricatedName(int screenNumber, xcb_screen_t* xcbScreen);
bool m_xi2Enabled;
int m_xi2Minor;
@@ -442,6 +443,7 @@ private:
QList<QXcbScreen *> m_screens;
int m_primaryScreen;
+ int m_primaryOutput;
xcb_atom_t m_allAtoms[QXcbAtom::NAtoms];
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index d92004b1ac..315c94bb56 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -43,38 +43,59 @@
#include "qxcbwindow.h"
#include "qxcbcursor.h"
#include "qxcbimage.h"
+#include "qnamespace.h"
#include <stdio.h>
#include <QDebug>
-#include <xcb/randr.h>
-
#include <qpa/qwindowsysteminterface.h>
QT_BEGIN_NAMESPACE
-QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int number)
+QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
+ xcb_randr_get_output_info_reply_t *output, QString outputName, int number)
: QXcbObject(connection)
- , m_screen(screen)
+ , m_screen(scr)
+ , m_crtc(output ? output->crtc : 0)
+ , m_outputName(outputName)
+ , m_sizeMillimeters(output ? QSize(output->mm_width, output->mm_height) : QSize())
+ , m_virtualSize(scr->width_in_pixels, scr->height_in_pixels)
+ , m_virtualSizeMillimeters(scr->width_in_millimeters, scr->height_in_millimeters)
+ , m_orientation(Qt::PrimaryOrientation)
, m_number(number)
, m_refreshRate(60)
{
if (connection->hasXRandr())
- xcb_randr_select_input(xcb_connection(), screen->root, true);
+ xcb_randr_select_input(xcb_connection(), screen()->root, true);
+ updateGeometry(output ? output->timestamp : 0);
updateRefreshRate();
+ // On VNC, it can be that physical size is unknown while
+ // virtual size is known (probably back-calculated from DPI and resolution)
+ if (m_sizeMillimeters.isEmpty())
+ m_sizeMillimeters = m_virtualSizeMillimeters;
+ if (m_geometry.isEmpty())
+ m_geometry = QRect(QPoint(), m_virtualSize);
+ if (m_availableGeometry.isEmpty())
+ m_availableGeometry = QRect(QPoint(), m_virtualSize);
+
#ifdef Q_XCB_DEBUG
qDebug();
- qDebug("Information of screen %d:", screen->root);
- qDebug(" width.........: %d", screen->width_in_pixels);
- qDebug(" height........: %d", screen->height_in_pixels);
- qDebug(" depth.........: %d", screen->root_depth);
- qDebug(" white pixel...: %x", screen->white_pixel);
- qDebug(" black pixel...: %x", screen->black_pixel);
+ qDebug("Screen %s:", m_outputName.toUtf8().constData());
+ 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(" 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();
+ qDebug(" root ID........: %x", screen()->root);
#endif
const quint32 mask = XCB_CW_EVENT_MASK;
@@ -85,11 +106,11 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num
| XCB_EVENT_MASK_PROPERTY_CHANGE
};
- xcb_change_window_attributes(xcb_connection(), screen->root, mask, values);
+ xcb_change_window_attributes(xcb_connection(), screen()->root, mask, values);
xcb_get_property_reply_t *reply =
xcb_get_property_reply(xcb_connection(),
- xcb_get_property_unchecked(xcb_connection(), false, screen->root,
+ xcb_get_property_unchecked(xcb_connection(), false, screen()->root,
atom(QXcbAtom::_NET_SUPPORTING_WM_CHECK),
XCB_ATOM_WINDOW, 0, 1024), NULL);
@@ -105,14 +126,14 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num
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("Running window manager: %s", qPrintable(m_windowManagerName));
+ qDebug(" window manager.: %s", qPrintable(m_windowManagerName));
+ qDebug();
#endif
}
free(windowManagerReply);
}
}
-
free(reply);
const xcb_query_extension_reply_t *sync_reply = xcb_get_extension_data(xcb_connection(), &xcb_sync_id);
@@ -125,11 +146,11 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num
Q_XCB_CALL2(xcb_create_window(xcb_connection(),
XCB_COPY_FROM_PARENT,
m_clientLeader,
- m_screen->root,
+ screen()->root,
0, 0, 1, 1,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
- m_screen->root_visual,
+ screen()->root_visual,
0, 0), connection);
Q_XCB_CALL2(xcb_change_property(xcb_connection(),
@@ -142,7 +163,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num
&m_clientLeader), connection);
xcb_depth_iterator_t depth_iterator =
- xcb_screen_allowed_depths_iterator(screen);
+ xcb_screen_allowed_depths_iterator(screen());
while (depth_iterator.rem) {
xcb_depth_t *depth = depth_iterator.data;
@@ -214,34 +235,113 @@ const xcb_visualtype_t *QXcbScreen::visualForId(xcb_visualid_t visualid) const
return &*it;
}
-QRect QXcbScreen::geometry() const
-{
- return QRect(0, 0, m_screen->width_in_pixels, m_screen->height_in_pixels);
-}
-
-int QXcbScreen::depth() const
-{
- return m_screen->root_depth;
-}
-
QImage::Format QXcbScreen::format() const
{
return QImage::Format_RGB32;
}
-QSizeF QXcbScreen::physicalSize() const
+QPlatformCursor *QXcbScreen::cursor() const
{
- return QSizeF(m_screen->width_in_millimeters, m_screen->height_in_millimeters);
+ return m_cursor;
}
-QPlatformCursor *QXcbScreen::cursor() const
+/*!
+ \brief handle the XCB screen change event and update properties
+
+ On a mobile device, the ideal use case is that the accelerometer would
+ drive the orientation. This could be achieved by using QSensors to read the
+ accelerometer and adjusting the rotation in QML, or by reading the
+ orientation from the QScreen object and doing the same, or in many other
+ ways. However, on X we have the XRandR extension, which makes it possible
+ to have the whole screen rotated, so that individual apps DO NOT have to
+ rotate themselves. Apps could optionally use the
+ QScreen::primaryOrientation property to optimize layout though.
+ Furthermore, there is no support in X for accelerometer events anyway. So
+ it makes more sense on a Linux system running X to just run a daemon which
+ monitors the accelerometer and runs xrandr automatically to do the rotation,
+ then apps do not have to be aware of it (but probably the window manager
+ would resize them accordingly). updateGeometry() is written with this
+ design in mind. Therefore the physical geometry, available geometry,
+ virtual geometry, orientation and primaryOrientation should all change at
+ the same time. On a system which cannot rotate the whole screen, it would
+ be correct for only the orientation (not the primary orientation) to
+ change.
+*/
+void QXcbScreen::handleScreenChange(xcb_randr_screen_change_notify_event_t *change_event)
{
- return m_cursor;
+ updateGeometry(change_event->config_timestamp);
+
+ switch (change_event->rotation) {
+ case XCB_RANDR_ROTATION_ROTATE_0: // xrandr --rotate normal
+ m_orientation = Qt::LandscapeOrientation;
+ m_virtualSize.setWidth(change_event->width);
+ m_virtualSize.setHeight(change_event->height);
+ m_virtualSizeMillimeters.setWidth(change_event->mwidth);
+ m_virtualSizeMillimeters.setHeight(change_event->mheight);
+ break;
+ case XCB_RANDR_ROTATION_ROTATE_90: // xrandr --rotate left
+ m_orientation = Qt::PortraitOrientation;
+ m_virtualSize.setWidth(change_event->height);
+ m_virtualSize.setHeight(change_event->width);
+ m_virtualSizeMillimeters.setWidth(change_event->mheight);
+ m_virtualSizeMillimeters.setHeight(change_event->mwidth);
+ break;
+ case XCB_RANDR_ROTATION_ROTATE_180: // xrandr --rotate inverted
+ m_orientation = Qt::InvertedLandscapeOrientation;
+ m_virtualSize.setWidth(change_event->width);
+ m_virtualSize.setHeight(change_event->height);
+ m_virtualSizeMillimeters.setWidth(change_event->mwidth);
+ m_virtualSizeMillimeters.setHeight(change_event->mheight);
+ break;
+ case XCB_RANDR_ROTATION_ROTATE_270: // xrandr --rotate right
+ m_orientation = Qt::InvertedPortraitOrientation;
+ m_virtualSize.setWidth(change_event->height);
+ m_virtualSize.setHeight(change_event->width);
+ m_virtualSizeMillimeters.setWidth(change_event->mheight);
+ m_virtualSizeMillimeters.setHeight(change_event->mwidth);
+ break;
+ // We don't need to do anything with these, since QScreen doesn't store reflection state,
+ // and Qt-based applications probably don't need to care about it anyway.
+ case XCB_RANDR_ROTATION_REFLECT_X: break;
+ case XCB_RANDR_ROTATION_REFLECT_Y: break;
+ }
+
+ QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry());
+ QWindowSystemInterface::handleScreenAvailableGeometryChange(QPlatformScreen::screen(), availableGeometry());
+ QWindowSystemInterface::handleScreenOrientationChange(QPlatformScreen::screen(), m_orientation);
}
-qreal QXcbScreen::refreshRate() const
+void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp)
{
- return m_refreshRate;
+ 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) {
+ m_geometry = QRect(crtc->x, crtc->y, crtc->width, crtc->height);
+ m_availableGeometry = m_geometry;
+ free(crtc);
+ }
+ }
+
+ xcb_get_property_reply_t * workArea =
+ xcb_get_property_reply(xcb_connection(),
+ xcb_get_property_unchecked(xcb_connection(), false, screen()->root,
+ atom(QXcbAtom::_NET_WORKAREA),
+ XCB_ATOM_CARDINAL, 0, 1024), NULL);
+
+ if (workArea && workArea->type == XCB_ATOM_CARDINAL && workArea->format == 32 && workArea->value_len >= 4) {
+ // If workArea->value_len > 4, the remaining ones seem to be for virtual desktops.
+ // But QScreen doesn't know about that concept. In reality there could be a
+ // "docked" panel (with _NET_WM_STRUT_PARTIAL atom set) on just one desktop.
+ // But for now just assume the first 4 values give us the geometry of the
+ // "work area", AKA "available geometry"
+ uint32_t *geom = (uint32_t*)xcb_get_property_value(workArea);
+ QRect virtualAvailableGeometry(geom[0], geom[1], geom[2], geom[3]);
+ // Take the intersection of the desktop's available geometry with this screen's geometry
+ // to get the part of the available geometry which belongs to this screen.
+ m_availableGeometry = m_geometry & virtualAvailableGeometry;
+ }
+ free(workArea);
}
void QXcbScreen::updateRefreshRate()
@@ -267,11 +367,6 @@ void QXcbScreen::updateRefreshRate()
QWindowSystemInterface::handleScreenRefreshRateChange(QPlatformScreen::screen(), rate);
}
-int QXcbScreen::screenNumber() const
-{
- return m_number;
-}
-
QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height) const
{
if (width == 0 || height == 0)
@@ -369,13 +464,4 @@ QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height)
return result;
}
-QString QXcbScreen::name() const
-{
- QByteArray displayName = connection()->displayName();
- int dotPos = displayName.lastIndexOf('.');
- if (dotPos != -1)
- displayName.truncate(dotPos);
- return displayName + QLatin1Char('.') + QString::number(screenNumber());
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index 7a81d8b43a..dfec3609a5 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -46,6 +46,7 @@
#include <QtCore/QString>
#include <xcb/xcb.h>
+#include <xcb/randr.h>
#include "qxcbobject.h"
@@ -57,21 +58,26 @@ class QXcbCursor;
class QXcbScreen : public QXcbObject, public QPlatformScreen
{
public:
- QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int number);
+ QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen,
+ xcb_randr_get_output_info_reply_t *output, QString outputName, int number);
~QXcbScreen();
QPixmap grabWindow(WId window, int x, int y, int width, int height) const;
QWindow *topLevelAt(const QPoint &point) const;
- QRect geometry() const;
- int depth() const;
+ QRect geometry() const { return m_geometry; }
+ QRect availableGeometry() const {return m_availableGeometry;}
+ int depth() const { return m_screen->root_depth; }
QImage::Format format() const;
- QSizeF physicalSize() const;
+ QSizeF physicalSize() const { return m_sizeMillimeters; }
QPlatformCursor *cursor() const;
- qreal refreshRate() const;
+ qreal refreshRate() const { return m_refreshRate; }
+ Qt::ScreenOrientation orientation() const { return m_orientation; }
+ QList<QPlatformScreen *> virtualSiblings() const { return m_siblings; }
+ void setVirtualSiblings(QList<QPlatformScreen *> sl) { m_siblings = sl; }
- int screenNumber() const;
+ int screenNumber() const { return m_number; }
xcb_screen_t *screen() const { return m_screen; }
xcb_window_t root() const { return m_screen->root; }
@@ -83,12 +89,23 @@ public:
const xcb_visualtype_t *visualForId(xcb_visualid_t) const;
- QString name() const;
+ QString name() const { return m_outputName; }
+ void handleScreenChange(xcb_randr_screen_change_notify_event_t *change_event);
+ void updateGeometry(xcb_timestamp_t timestamp);
void updateRefreshRate();
private:
xcb_screen_t *m_screen;
+ xcb_randr_crtc_t m_crtc;
+ QString m_outputName;
+ QSizeF m_sizeMillimeters;
+ QRect m_geometry;
+ QRect m_availableGeometry;
+ QSize m_virtualSize;
+ QSizeF m_virtualSizeMillimeters;
+ QList<QPlatformScreen *> m_siblings;
+ Qt::ScreenOrientation m_orientation;
int m_number;
QString m_windowManagerName;
bool m_syncRequestSupported;