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>
bb10
Gatis Paeglis 2018-04-10 11:50:31 +02:00
parent 7286d9d8dd
commit d5ac11891d
3 changed files with 28 additions and 8 deletions

View File

@ -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
}

View File

@ -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;

View File

@ -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);