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:
parent
f7a167223b
commit
f48170b479
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user