diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 224 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.h | 6 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbintegration.cpp | 4 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbintegration.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbscreen.cpp | 8 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbscreen.h | 1 |
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 ¶meters) 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; } |