From 67cc8fea106c35c7ca75bf476667d07b3bbf3257 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 19 Feb 2018 11:07:43 +0100 Subject: [PATCH] XCB: Do not create instance of QPlatformIntegration for invalid displays Extract a static factory for QXcbConnection objects and pass potential connection errors to qxcbmain.cpp, which will then return 0. Task-number: QTBUG-68859 Change-Id: I9c0faf82462a78a576360c19bef251ad1d034d84 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbconnection.cpp | 56 ++++++++++++++----- src/plugins/platforms/xcb/qxcbconnection.h | 17 ++++-- src/plugins/platforms/xcb/qxcbintegration.cpp | 26 +++------ src/plugins/platforms/xcb/qxcbintegration.h | 1 + src/plugins/platforms/xcb/qxcbmain.cpp | 12 +++- 5 files changed, 72 insertions(+), 40 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index c14f3f3703..6fe1a121d8 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -544,31 +544,59 @@ void QXcbConnection::initializeScreens() } } -QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName) - : m_canGrabServer(canGrabServer) - , m_defaultVisualId(defaultVisualId) - , m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY")) - , m_nativeInterface(nativeInterface) +QXcbConnection *QXcbConnection::create(QXcbNativeInterface *nativeInterface, bool canGrabServer, + xcb_visualid_t defaultVisualId, + const char *displayNameIn) { + const QByteArray displayName = displayNameIn ? QByteArray(displayNameIn) : qgetenv("DISPLAY"); + int primaryScreenNumber = 0; + void *xlibDisplay = nullptr; + xcb_connection_t *connection = nullptr; #if QT_CONFIG(xcb_xlib) - Display *dpy = XOpenDisplay(m_displayName.constData()); + Display *dpy = XOpenDisplay(displayName.constData()); if (dpy) { - m_primaryScreenNumber = DefaultScreen(dpy); - m_connection = XGetXCBConnection(dpy); + primaryScreenNumber = DefaultScreen(dpy); + connection = XGetXCBConnection(dpy); XSetEventQueueOwner(dpy, XCBOwnsEventQueue); XSetErrorHandler(nullErrorHandler); XSetIOErrorHandler(ioErrorHandler); - m_xlib_display = dpy; + xlibDisplay = dpy; } #else - m_connection = xcb_connect(m_displayName.constData(), &m_primaryScreenNumber); + connection = xcb_connect(displayName.constData(), &primaryScreenNumber); #endif // QT_CONFIG(xcb_xlib) - - if (Q_UNLIKELY(!m_connection || xcb_connection_has_error(m_connection))) { - qCWarning(lcQpaScreen, "QXcbConnection: Could not connect to display %s", m_displayName.constData()); - return; + if (Q_UNLIKELY(connection == nullptr)) { + qWarning("QXcbConnection: Could not connect to display \"%s\"", displayName.constData()); + return nullptr; } + if (Q_UNLIKELY(xcb_connection_has_error(connection))) { +#if QT_CONFIG(xcb_xlib) + XCloseDisplay(static_cast(xlibDisplay)); +#else + xcb_disconnect(connection); +#endif + qWarning("QXcbConnection: Errors occurred connecting to display \"%s\"", displayName.constData()); + return nullptr; + } + return new QXcbConnection(connection, primaryScreenNumber, nativeInterface, + canGrabServer, defaultVisualId, displayName, xlibDisplay); +} + +QXcbConnection::QXcbConnection(xcb_connection_t *c, int primaryScreenNumber, + QXcbNativeInterface *nativeInterface, bool canGrabServer, + xcb_visualid_t defaultVisualId, const QByteArray &displayName, + void *xlibDisplay) + : m_connection(c) + , m_canGrabServer(canGrabServer) + , m_defaultVisualId(defaultVisualId) + , m_primaryScreenNumber(primaryScreenNumber) + , m_displayName(displayName) + , m_nativeInterface(nativeInterface) +#if QT_CONFIG(xcb_xlib) + , m_xlib_display(xlibDisplay) +#endif +{ m_reader = new QXcbEventReader(this); m_reader->start(); diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 0b31e9c3e7..c88100e580 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -377,9 +377,16 @@ class Q_XCB_EXPORT QXcbConnection : public QObject { Q_OBJECT public: - QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName = 0); + explicit QXcbConnection(xcb_connection_t *c, int primaryScreenNumber, + QXcbNativeInterface *nativeInterface, bool canGrabServer, + xcb_visualid_t defaultVisualId, const QByteArray &displayName, + void *xlibDisplay = nullptr); + ~QXcbConnection(); + static QXcbConnection *create(QXcbNativeInterface *nativeInterface, bool canGrabServer, + xcb_visualid_t defaultVisualId, const char *displayName = nullptr); + QXcbConnection *connection() const { return const_cast(this); } bool isConnected() const; @@ -639,21 +646,21 @@ private: static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value); #endif - xcb_connection_t *m_connection = nullptr; + xcb_connection_t *const m_connection; const xcb_setup_t *m_setup = nullptr; const bool m_canGrabServer; const xcb_visualid_t m_defaultVisualId; QList m_virtualDesktops; QList m_screens; - int m_primaryScreenNumber = 0; + const int m_primaryScreenNumber; xcb_atom_t m_allAtoms[QXcbAtom::NAtoms]; xcb_timestamp_t m_time = XCB_CURRENT_TIME; xcb_timestamp_t m_netWmUserTime = XCB_CURRENT_TIME; - QByteArray m_displayName; + const QByteArray m_displayName; QXcbKeyboard *m_keyboard = nullptr; #ifndef QT_NO_CLIPBOARD @@ -666,7 +673,7 @@ private: QXcbNativeInterface *m_nativeInterface = nullptr; #if QT_CONFIG(xcb_xlib) - void *m_xlib_display = nullptr; + void *const m_xlib_display; #endif QXcbEventReader *m_reader = nullptr; diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index e9b36c48b8..1ac5445035 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -192,25 +192,15 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char const int numParameters = parameters.size(); m_connections.reserve(1 + numParameters / 2); - auto conn = new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, displayName); - if (conn->isConnected()) - m_connections << conn; - else - delete conn; - for (int i = 0; i < numParameters - 1; i += 2) { - qCDebug(lcQpaScreen) << "connecting to additional display: " << parameters.at(i) << parameters.at(i+1); - QString display = parameters.at(i) + QLatin1Char(':') + parameters.at(i+1); - conn = new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, display.toLatin1().constData()); - if (conn->isConnected()) - m_connections << conn; - else - delete conn; - } - - if (m_connections.isEmpty()) { - qCritical("Could not connect to any X display."); - exit(1); + if (QXcbConnection *defaultConnection = QXcbConnection::create(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, displayName)) { + m_connections.append(defaultConnection); + for (int i = 0; i < numParameters - 1; i += 2) { + qCDebug(lcQpaScreen) << "connecting to additional display: " << parameters.at(i) << parameters.at(i+1); + QString display = parameters.at(i) + QLatin1Char(':') + parameters.at(i+1); + if (QXcbConnection *connection = QXcbConnection::create(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, display.toLatin1().constData())) + m_connections.append(connection); + } } m_fontDatabase.reset(new QGenericUnixFontDatabase()); diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index 69e49cb7f6..a2de22d53d 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -103,6 +103,7 @@ public: QPlatformTheme *createPlatformTheme(const QString &name) const override; QVariant styleHint(StyleHint hint) const override; + bool hasDefaultConnection() const { return !m_connections.isEmpty(); } QXcbConnection *defaultConnection() const { return m_connections.first(); } QByteArray wmClass() const; diff --git a/src/plugins/platforms/xcb/qxcbmain.cpp b/src/plugins/platforms/xcb/qxcbmain.cpp index f8cb9a9269..539d033ca9 100644 --- a/src/plugins/platforms/xcb/qxcbmain.cpp +++ b/src/plugins/platforms/xcb/qxcbmain.cpp @@ -52,10 +52,16 @@ public: QPlatformIntegration* QXcbIntegrationPlugin::create(const QString& system, const QStringList& parameters, int &argc, char **argv) { - if (!system.compare(QLatin1String("xcb"), Qt::CaseInsensitive)) - return new QXcbIntegration(parameters, argc, argv); + if (!system.compare(QLatin1String("xcb"), Qt::CaseInsensitive)) { + QXcbIntegration *xcbIntegration = new QXcbIntegration(parameters, argc, argv); + if (!xcbIntegration->hasDefaultConnection()) { + delete xcbIntegration; + return nullptr; + } + return xcbIntegration; + } - return 0; + return nullptr; } QT_END_NAMESPACE