summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp224
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h6
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp4
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp8
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h1
6 files changed, 151 insertions, 94 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 26f304b882..9e394d674f 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -50,6 +50,7 @@
#include "qxcbdrag.h"
#include "qxcbwmsupport.h"
#include "qxcbnativeinterface.h"
+#include "qxcbintegration.h"
#include <QtAlgorithms>
#include <QSocketNotifier>
@@ -100,27 +101,147 @@ static int nullErrorHandler(Display *, XErrorEvent *)
}
#endif
-QXcbScreen* QXcbConnection::createScreenWithFabricatedName(int screenNumber, xcb_screen_t* xcbScreen)
+QXcbScreen* QXcbConnection::findOrCreateScreen(QList<QXcbScreen *>& newScreens,
+ int screenNumber, xcb_screen_t* xcbScreen, xcb_randr_get_output_info_reply_t *output)
{
- 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);
+ QString name;
+ if (output)
+ name = QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output),
+ xcb_randr_get_output_info_name_length(output));
+ else {
+ QByteArray displayName = m_displayName;
+ int dotPos = displayName.lastIndexOf('.');
+ if (dotPos != -1)
+ displayName.truncate(dotPos);
+ name = displayName + QLatin1Char('.') + QString::number(screenNumber);
}
- return screen;
+ foreach (QXcbScreen* scr, m_screens)
+ if (scr->name() == name && scr->root() == xcbScreen->root)
+ return scr;
+ QXcbScreen *ret = new QXcbScreen(this, xcbScreen, output, name, screenNumber);
+ newScreens << ret;
+ return ret;
+}
+
+/*!
+ \brief Synchronizes the screen list, adds new screens, removes deleted ones
+*/
+void QXcbConnection::updateScreens()
+{
+ xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
+ int screenNumber = 0; // index of this QScreen in QGuiApplication::screens()
+ int xcbScreenNumber = 0; // screen number in the xcb sense
+ QSet<QXcbScreen *> activeScreens;
+ QList<QXcbScreen *> newScreens;
+ QXcbScreen* primaryScreen = NULL;
+ while (it.rem) {
+ // Each "screen" in xcb terminology is a virtual desktop,
+ // potentially a collection of separate juxtaposed monitors.
+ // But we want a separate QScreen for each output (e.g. DVI-I-1, VGA-1, etc.)
+ // which will become virtual siblings.
+ 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 = findOrCreateScreen(newScreens, xcbScreenNumber, xcbScreen);
+ siblings << screen;
+ activeScreens << screen;
+ if (!primaryScreen)
+ primaryScreen = 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;
+
+#ifdef Q_XCB_DEBUG
+ QString outputName = QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output),
+ xcb_randr_get_output_info_name_length(output));
+#endif
+
+ if (output->crtc == XCB_NONE) {
+#ifdef Q_XCB_DEBUG
+ qDebug("Screen output %s is not connected", qPrintable(outputName));
+#endif
+ continue;
+ }
+
+ QXcbScreen *screen = findOrCreateScreen(newScreens, xcbScreenNumber, xcbScreen, output);
+ siblings << screen;
+ activeScreens << screen;
+ ++screenNumber;
+ if (!primaryScreen && primary) {
+ if (primary->output == XCB_NONE || outputs[i] == primary->output) {
+ primaryScreen = screen;
+ siblings.prepend(siblings.takeLast());
+#ifdef Q_XCB_DEBUG
+ qDebug("Primary output is %d: %s", primary->output, qPrintable(outputName));
+#endif
+ }
+ }
+ free(output);
+ }
+ free(primary);
+ free(resources);
+ } else {
+ QXcbScreen *screen = findOrCreateScreen(newScreens, xcbScreenNumber, xcbScreen);
+ siblings << screen;
+ activeScreens << screen;
+ if (!primaryScreen)
+ primaryScreen = screen;
+ ++screenNumber;
+ }
+ foreach (QPlatformScreen* s, siblings)
+ ((QXcbScreen*)s)->setVirtualSiblings(siblings);
+ xcb_screen_next(&it);
+ ++xcbScreenNumber;
+ }
+
+ // Now activeScreens is the complete set of screens which are active at this time.
+ // Delete any existing screens which are not in activeScreens
+ for (int i = m_screens.count() - 1; i >= 0; --i)
+ if (!activeScreens.contains(m_screens[i])) {
+ delete m_screens[i];
+ m_screens.removeAt(i);
+ }
+
+ // Add any new screens, and make sure the primary screen comes first
+ // since it is used by QGuiApplication::primaryScreen()
+ foreach (QXcbScreen* screen, newScreens) {
+ if (screen == primaryScreen)
+ m_screens.prepend(screen);
+ else
+ m_screens.append(screen);
+ }
+
+ // Now that they are in the right order, emit the added signals for new screens only
+ foreach (QXcbScreen* screen, m_screens)
+ if (newScreens.contains(screen))
+ ((QXcbIntegration*)QGuiApplicationPrivate::platformIntegration())->screenAdded(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
@@ -182,80 +303,8 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char
m_time = XCB_CURRENT_TIME;
- xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
-
initializeXRandr();
-
- int screenNumber = 0;
- while (it.rem) {
- // 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 {
- QXcbScreen *screen = createScreenWithFabricatedName(screenNumber, it.data);
- siblings << screen;
- ++screenNumber;
- }
- foreach (QPlatformScreen* s, siblings)
- ((QXcbScreen*)s)->setVirtualSiblings(siblings);
- xcb_screen_next(&it);
- }
+ updateScreens();
m_connectionEventListener = xcb_generate_id(m_connection);
xcb_create_window(m_connection, XCB_COPY_FROM_PARENT,
@@ -709,6 +758,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
#endif
handled = true;
} else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
+ updateScreens();
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 ) {
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index df91ad6e2f..08dd304b3d 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -66,6 +66,7 @@ struct XInput2MaemoData;
#endif
struct XInput2DeviceData;
#endif
+struct xcb_randr_get_output_info_reply_t;
//#define Q_XCB_DEBUG
@@ -398,7 +399,9 @@ 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);
+ QXcbScreen* findOrCreateScreen(QList<QXcbScreen *>& newScreens, int screenNumber,
+ xcb_screen_t* xcbScreen, xcb_randr_get_output_info_reply_t *output = NULL);
+ void updateScreens();
bool m_xi2Enabled;
int m_xi2Minor;
@@ -443,7 +446,6 @@ 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/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index 0b7f17d321..8784046560 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -110,10 +110,6 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters)
m_connections << new QXcbConnection(m_nativeInterface.data(), display.toLatin1().constData());
}
- foreach (QXcbConnection *connection, m_connections)
- foreach (QXcbScreen *screen, connection->screens())
- screenAdded(screen);
-
m_fontDatabase.reset(new QGenericUnixFontDatabase());
m_inputContext.reset(QPlatformInputContextFactory::create());
#ifndef QT_NO_ACCESSIBILITY
diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h
index 2a7bc603da..7f7c52372c 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.h
+++ b/src/plugins/platforms/xcb/qxcbintegration.h
@@ -106,6 +106,8 @@ private:
#endif
QScopedPointer<QPlatformServices> m_services;
+
+ friend class QXcbConnection; // access QPlatformIntegration::screenAdded()
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 3798bf0050..6452186bbf 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -83,7 +83,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
#ifdef Q_XCB_DEBUG
qDebug();
- qDebug("Screen %s:", m_outputName.toUtf8().constData());
+ qDebug("Screen output %s of xcb screen %d:", m_outputName.toUtf8().constData(), m_number);
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());
@@ -240,6 +240,12 @@ QImage::Format QXcbScreen::format() const
return QImage::Format_RGB32;
}
+QDpi QXcbScreen::logicalDpi() const
+{
+ return QDpi(25.4 * m_virtualSize.width() / m_virtualSizeMillimeters.width(),
+ 25.4 * m_virtualSize.height() / m_virtualSizeMillimeters.height());
+}
+
QPlatformCursor *QXcbScreen::cursor() const
{
return m_cursor;
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index f5439b3a93..d9eee464dc 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -71,6 +71,7 @@ public:
int depth() const { return m_screen->root_depth; }
QImage::Format format() const;
QSizeF physicalSize() const { return m_sizeMillimeters; }
+ QDpi logicalDpi() const;
QPlatformCursor *cursor() const;
qreal refreshRate() const { return m_refreshRate; }
Qt::ScreenOrientation orientation() const { return m_orientation; }