xcb: Add Xinerama support

This patch makes possible to use Xinerama screens in XCB platform
plugin.

Task-number: QTBUG-48615
Change-Id: Ib4dbfcdfadc46d2875a2fc09e8b852181edfbed2
Reviewed-by: Shawn Rutledge <shawn.rutledge@theqtcompany.com>
This commit is contained in:
Błażej Szczygieł 2015-11-02 00:26:39 +01:00 committed by Shawn Rutledge
parent f7a167223b
commit f48170b479
6 changed files with 75 additions and 19 deletions

View File

@ -3,14 +3,14 @@ Requires libxcb >= 1.5.
PACKAGE DEPENDENCIES
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 libxcb-randr0-dev libxcb-glx0-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 libxcb-glx0-dev libxcb-xinerama0-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 libxcb-randr0-dev libxcb-glx0-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 libxcb-glx0-dev libxcb-xinerama0-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
On Ubuntu 12.04 icccm1 is replaced by icccm4 and xcb-render-util can be installed automatically:
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 libxcb-render-util0 libxcb-render-util0-dev libxcb-glx0-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 libxcb-render-util0 libxcb-render-util0-dev libxcb-glx0-dev libxcb-xinerama0-dev
On Fedora, the following packages are required:

View File

@ -60,6 +60,7 @@
#include <xcb/shm.h>
#include <xcb/sync.h>
#include <xcb/xfixes.h>
#include <xcb/xinerama.h>
#ifdef XCB_USE_XLIB
#include <X11/Xlib.h>
@ -386,6 +387,7 @@ void QXcbConnection::initializeScreens()
xcb_screen_t *xcbScreen = it.data;
QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber);
m_virtualDesktops.append(virtualDesktop);
QList<QPlatformScreen *> siblings;
if (has_randr_extension) {
xcb_generic_error_t *error = NULL;
// RRGetScreenResourcesCurrent is fast but it may return nothing if the
@ -429,7 +431,6 @@ void QXcbConnection::initializeScreens()
qWarning("failed to get the primary output of the screen");
free(error);
} else {
QList<QPlatformScreen *> siblings;
for (int i = 0; i < outputCount; i++) {
QScopedPointer<xcb_randr_get_output_info_reply_t, QScopedPointerPodDeleter> output(
xcb_randr_get_output_info_reply(xcb_connection(),
@ -471,12 +472,30 @@ void QXcbConnection::initializeScreens()
}
}
}
virtualDesktop->setScreens(siblings);
}
}
}
} else if (has_xinerama_extension) {
// Xinerama is available
xcb_xinerama_query_screens_cookie_t cookie = xcb_xinerama_query_screens(m_connection);
xcb_xinerama_query_screens_reply_t *screens = xcb_xinerama_query_screens_reply(m_connection,
cookie,
Q_NULLPTR);
if (screens) {
xcb_xinerama_screen_info_iterator_t it = xcb_xinerama_query_screens_screen_info_iterator(screens);
while (it.rem) {
xcb_xinerama_screen_info_t *screen_info = it.data;
QXcbScreen *screen = new QXcbScreen(this, virtualDesktop,
XCB_NONE, Q_NULLPTR,
screen_info, it.index);
siblings << screen;
m_screens << screen;
xcb_xinerama_screen_info_next(&it);
}
free(screens);
}
}
if (virtualDesktop->screens().isEmpty()) {
if (siblings.isEmpty()) {
// If there are no XRandR outputs or XRandR extension is missing,
// then create a fake/legacy screen.
QXcbScreen *screen = new QXcbScreen(this, virtualDesktop, XCB_NONE, Q_NULLPTR);
@ -486,8 +505,9 @@ void QXcbConnection::initializeScreens()
primaryScreen = screen;
primaryScreen->setPrimary(true);
}
virtualDesktop->addScreen(screen);
siblings << screen;
}
virtualDesktop->setScreens(siblings);
xcb_screen_next(&it);
++xcbScreenNumber;
} // for each xcb screen
@ -529,6 +549,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
, xfixes_first_event(0)
, xrandr_first_event(0)
, xkb_first_event(0)
, has_xinerama_extension(false)
, has_shape_extension(false)
, has_randr_extension(false)
, has_input_shape(false)
@ -583,7 +604,10 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
m_time = XCB_CURRENT_TIME;
m_netWmUserTime = XCB_CURRENT_TIME;
initializeXRandr();
if (!qEnvironmentVariableIsSet("QT_XCB_NO_XRANDR"))
initializeXRandr();
if (!has_randr_extension)
initializeXinerama();
initializeXFixes();
initializeScreens();
@ -2087,6 +2111,22 @@ void QXcbConnection::initializeXRandr()
}
}
void QXcbConnection::initializeXinerama()
{
const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xinerama_id);
if (!reply || !reply->present)
return;
xcb_generic_error_t *error = Q_NULLPTR;
xcb_xinerama_is_active_cookie_t xinerama_query_cookie = xcb_xinerama_is_active(m_connection);
xcb_xinerama_is_active_reply_t *xinerama_is_active = xcb_xinerama_is_active_reply(m_connection,
xinerama_query_cookie,
&error);
has_xinerama_extension = xinerama_is_active && !error && xinerama_is_active->state;
free(error);
free(xinerama_is_active);
}
void QXcbConnection::initializeXShape()
{
const xcb_query_extension_reply_t *xshape_reply = xcb_get_extension_data(m_connection, &xcb_shape_id);
@ -2174,7 +2214,9 @@ void QXcbConnection::initializeXKB()
bool QXcbConnection::xi2MouseEvents() const
{
static bool mouseViaXI2 = !qEnvironmentVariableIsSet("QT_XCB_NO_XI2_MOUSE");
return mouseViaXI2;
// Don't use XInput2 when Xinerama extension is enabled,
// because it causes problems with multi-monitor setup.
return mouseViaXI2 && !has_xinerama_extension;
}
#if defined(XCB_USE_XINPUT2)

View File

@ -515,6 +515,7 @@ private:
void initializeXFixes();
void initializeXRender();
void initializeXRandr();
void initializeXinerama();
void initializeXShape();
void initializeXKB();
void handleClientMessageEvent(const xcb_client_message_event_t *event);
@ -639,6 +640,7 @@ private:
uint32_t xrandr_first_event;
uint32_t xkb_first_event;
bool has_xinerama_extension;
bool has_shape_extension;
bool has_randr_extension;
bool has_input_shape;

View File

@ -155,8 +155,15 @@ void QXcbVirtualDesktop::updateWorkArea()
}
}
static inline QSizeF sizeInMillimeters(const QSize &size, const QDpi &dpi)
{
return QSizeF(Q_MM_PER_INCH * size.width() / dpi.first,
Q_MM_PER_INCH * size.height() / dpi.second);
}
QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output)
xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output,
const xcb_xinerama_screen_info_t *xineramaScreenInfo, int xineramaScreenIdx)
: QXcbObject(connection)
, m_virtualDesktop(virtualDesktop)
, m_output(outputId)
@ -188,8 +195,14 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe
updateRefreshRate(crtc->mode);
free(crtc);
}
} else {
updateGeometry(output ? output->timestamp : 0);
} else if (xineramaScreenInfo) {
m_geometry = QRect(xineramaScreenInfo->x_org, xineramaScreenInfo->y_org,
xineramaScreenInfo->width, xineramaScreenInfo->height);
m_nativeGeometry = m_geometry;
m_availableGeometry = m_geometry & m_virtualDesktop->workArea();
m_sizeMillimeters = sizeInMillimeters(m_geometry.size(), virtualDpi());
if (xineramaScreenIdx > -1)
m_outputName += QLatin1Char('-') + QString::number(xineramaScreenIdx);
}
if (m_geometry.isEmpty()) {
@ -538,11 +551,8 @@ void QXcbScreen::updateGeometry(const QRect &geom, uint8_t rotation)
// It can be that physical size is unknown while virtual size
// is known (probably back-calculated from DPI and resolution),
// e.g. on VNC or with some hardware.
if (m_sizeMillimeters.isEmpty()) {
QDpi dpi = virtualDpi();
m_sizeMillimeters = QSizeF(Q_MM_PER_INCH * xGeometry.width() / dpi.first,
Q_MM_PER_INCH * xGeometry.width() / dpi.second);
}
if (m_sizeMillimeters.isEmpty())
m_sizeMillimeters = sizeInMillimeters(xGeometry.size(), virtualDpi());
qreal dpi = xGeometry.width() / physicalSize().width() * qreal(25.4);
m_pixelDensity = qRound(dpi/96);

View File

@ -40,6 +40,7 @@
#include <xcb/xcb.h>
#include <xcb/randr.h>
#include <xcb/xfixes.h>
#include <xcb/xinerama.h>
#include "qxcbobject.h"
#include "qxcbscreen.h"
@ -102,7 +103,8 @@ class Q_XCB_EXPORT QXcbScreen : public QXcbObject, public QPlatformScreen
{
public:
QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *outputInfo);
xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *outputInfo,
const xcb_xinerama_screen_info_t *xineramaScreenInfo = Q_NULLPTR, int xineramaScreenIdx = -1);
~QXcbScreen();
QString getOutputName(xcb_randr_get_output_info_reply_t *outputInfo);

View File

@ -92,7 +92,7 @@ contains(QT_CONFIG, xcb-qt) {
INCLUDEPATH += $$XCB_DIR/include $$XCB_DIR/sysinclude
LIBS += -lxcb -L$$OUT_PWD/xcb-static -lxcb-static
} else {
LIBS += -lxcb -lxcb-image -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr -lxcb-shape -lxcb-keysyms
LIBS += -lxcb -lxcb-image -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr -lxcb-shape -lxcb-keysyms -lxcb-xinerama
!contains(DEFINES, QT_NO_XKB):LIBS += -lxcb-xkb
}