diff options
author | Gatis Paeglis <gatis.paeglis@qt.io> | 2018-04-10 11:50:31 +0200 |
---|---|---|
committer | Gatis Paeglis <gatis.paeglis@qt.io> | 2018-04-14 17:03:10 +0000 |
commit | d5ac11891d8237ca2f02390ffd0ff103578b520e (patch) | |
tree | 2ae7eb99d63bbb9ffed440e88731a8d08399b116 /src | |
parent | 7286d9d8dd1f8543007218a91d5c6767a7a7b152 (diff) |
xcb: prevent crash with pixmap cursors on XRender-less X servers
We were using xcb_render_* APIs without checking if the server even
supports this extension. Attempting to use an extension which is
not present will always result in a crash. This patch adds the required
guards and refactors how we detect presence of XRender extension.
Also instead of falling back to some odd-looking bitmapped version
just leave the current cursor unchanged. That is how we did it in
Qt4 AFAICT.
Task-number: QTBUG-66935
Change-Id: I4f27f1d65a77563ec34f3e0e94492c9236d7f9a6
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 11 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.h | 10 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbcursor.cpp | 15 |
3 files changed, 28 insertions, 8 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 2431f99ab8..444e3a7669 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -2136,17 +2136,22 @@ void QXcbConnection::initializeXRender() { #if QT_CONFIG(xcb_render) const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_render_id); - if (!reply || !reply->present) + if (!reply || !reply->present) { + qCDebug(lcQpaXcb, "XRender extension not present on the X server"); return; + } auto xrender_query = Q_XCB_REPLY(xcb_render_query_version, m_connection, XCB_RENDER_MAJOR_VERSION, XCB_RENDER_MINOR_VERSION); - if (!xrender_query || (xrender_query->major_version == 0 && xrender_query->minor_version < 5)) { - qWarning("QXcbConnection: Failed to initialize XRender"); + if (!xrender_query) { + qCWarning(lcQpaXcb, "xcb_render_query_version failed"); return; } + has_render_extension = true; + m_xrenderVersion.first = xrender_query->major_version; + m_xrenderVersion.second = xrender_query->minor_version; #endif } diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index ced5208c81..d9321d94d0 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -478,7 +478,13 @@ public: bool hasXRandr() const { return has_randr_extension; } bool hasInputShape() const { return has_input_shape; } bool hasXKB() const { return has_xkb; } - bool hasXRender() const { return has_render_extension; } + bool hasXRender(int major = -1, int minor = -1) const + { + if (has_render_extension && major != -1 && minor != -1) + return m_xrenderVersion >= qMakePair(major, minor); + + return has_render_extension; + } bool hasXInput2() const { return m_xi2Enabled; } bool hasShm() const { return has_shm; } bool hasShmFd() const { return has_shm_fd; } @@ -707,6 +713,8 @@ private: bool has_shm = false; bool has_shm_fd = false; + QPair<int, int> m_xrenderVersion; + Qt::MouseButtons m_buttonState = 0; Qt::MouseButton m_button = Qt::NoButton; diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index 70138abede..8d151b760b 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -601,12 +601,19 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor) { - xcb_connection_t *conn = xcb_connection(); QPoint spot = cursor->hotSpot(); xcb_cursor_t c = XCB_NONE; - if (cursor->pixmap().depth() > 1) - c = qt_xcb_createCursorXRender(m_screen, cursor->pixmap().toImage(), spot); - if (!c) { + if (cursor->pixmap().depth() > 1) { +#if QT_CONFIG(xcb_render) + if (connection()->hasXRender(0, 5)) + c = qt_xcb_createCursorXRender(m_screen, cursor->pixmap().toImage(), spot); + else + qCWarning(lcQpaXcb, "xrender >= 0.5 required to create pixmap cursors"); +#else + qCWarning(lcQpaXcb, "This build of Qt does not support pixmap cursors"); +#endif + } else { + xcb_connection_t *conn = xcb_connection(); xcb_pixmap_t cp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->bitmap()->toImage()); xcb_pixmap_t mp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->mask()->toImage()); c = xcb_generate_id(conn); |