xcb: use libxcb-cursor to replace Xlib/libXcursor

[ChangeLog][Linux/XCB] Used libxcb-cursor to replace Xlib/libXcursor

Fixes: QTBUG-67373
Change-Id: I04a30e401467e48b431a5cc63984f7b70a09faf0
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Liang Qi <liang.qi@qt.io>
This commit is contained in:
Liang Qi 2020-12-17 11:23:30 +01:00
parent e6d3657f7f
commit 012132c60d
5 changed files with 60 additions and 104 deletions

View File

@ -70,6 +70,9 @@ endif()
if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS)
qt_find_package(XCB 1.11 PROVIDED_TARGETS XCB::XCB MODULE_NAME gui QMAKE_LIB xcb) qt_find_package(XCB 1.11 PROVIDED_TARGETS XCB::XCB MODULE_NAME gui QMAKE_LIB xcb)
endif() endif()
if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS)
qt_find_package(XCB 0.1.1 COMPONENTS CURSOR PROVIDED_TARGETS XCB::CURSOR MODULE_NAME gui QMAKE_LIB xcb_cursor)
endif()
if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS) if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS)
qt_find_package(XCB 0.3.9 COMPONENTS ICCCM PROVIDED_TARGETS XCB::ICCCM MODULE_NAME gui QMAKE_LIB xcb_icccm) qt_find_package(XCB 0.3.9 COMPONENTS ICCCM PROVIDED_TARGETS XCB::ICCCM MODULE_NAME gui QMAKE_LIB xcb_icccm)
endif() endif()
@ -482,6 +485,7 @@ glFramebufferTexture(GL_TEXTURE_2D, GL_DEPTH_STENCIL_ATTACHMENT, 1, 0);
qt_config_compile_test(xcb_syslibs qt_config_compile_test(xcb_syslibs
LABEL "XCB (extensions)" LABEL "XCB (extensions)"
LIBRARIES LIBRARIES
XCB::CURSOR
XCB::ICCCM XCB::ICCCM
XCB::IMAGE XCB::IMAGE
XCB::KEYSYMS XCB::KEYSYMS
@ -500,6 +504,7 @@ qt_config_compile_test(xcb_syslibs
#include <xcb/xcb.h> #include <xcb/xcb.h>
#include <xcb/xcb_image.h> #include <xcb/xcb_image.h>
#include <xcb/xcb_keysyms.h> #include <xcb/xcb_keysyms.h>
#include <xcb/xcb_cursor.h>
#include <xcb/randr.h> #include <xcb/randr.h>
#include <xcb/render.h> #include <xcb/render.h>
#include <xcb/shape.h> #include <xcb/shape.h>

View File

@ -47,6 +47,7 @@ qt_internal_add_module(XcbQpaPrivate
PkgConfig::XKB_COMMON_X11 PkgConfig::XKB_COMMON_X11
Qt::CorePrivate Qt::CorePrivate
Qt::GuiPrivate Qt::GuiPrivate
XCB::CURSOR
XCB::ICCCM XCB::ICCCM
XCB::IMAGE XCB::IMAGE
XCB::KEYSYMS XCB::KEYSYMS

View File

@ -1,4 +1,4 @@
// Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbcursor.h" #include "qxcbcursor.h"
@ -7,13 +7,14 @@
#include "qxcbimage.h" #include "qxcbimage.h"
#include "qxcbxsettings.h" #include "qxcbxsettings.h"
#if QT_CONFIG(library)
#include <QtCore/QLibrary>
#endif
#include <QtGui/QWindow> #include <QtGui/QWindow>
#include <QtGui/QBitmap> #include <QtGui/QBitmap>
#include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qguiapplication_p.h>
#if QT_CONFIG(xcb_xlib)
#include <X11/cursorfont.h> #include <X11/cursorfont.h>
#endif
#include <xcb/xfixes.h> #include <xcb/xfixes.h>
#include <xcb/xcb_image.h> #include <xcb/xcb_image.h>
@ -21,24 +22,6 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals; using namespace Qt::StringLiterals;
typedef int (*PtrXcursorLibraryLoadCursor)(void *, const char *);
typedef char *(*PtrXcursorLibraryGetTheme)(void *);
typedef int (*PtrXcursorLibrarySetTheme)(void *, const char *);
typedef int (*PtrXcursorLibraryGetDefaultSize)(void *);
#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
#include <X11/Xlib.h>
enum {
XCursorShape = CursorShape
};
#undef CursorShape
static PtrXcursorLibraryLoadCursor ptrXcursorLibraryLoadCursor = nullptr;
static PtrXcursorLibraryGetTheme ptrXcursorLibraryGetTheme = nullptr;
static PtrXcursorLibrarySetTheme ptrXcursorLibrarySetTheme = nullptr;
static PtrXcursorLibraryGetDefaultSize ptrXcursorLibraryGetDefaultSize = nullptr;
#endif
static xcb_font_t cursorFont = 0; static xcb_font_t cursorFont = 0;
static int cursorCount = 0; static int cursorCount = 0;
@ -266,7 +249,7 @@ QXcbCursorCacheKey::QXcbCursorCacheKey(const QCursor &c)
#endif // !QT_NO_CURSOR #endif // !QT_NO_CURSOR
QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen) QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen)
: QXcbObject(conn), m_screen(screen), m_gtkCursorThemeInitialized(false) : QXcbObject(conn), m_screen(screen), m_cursorContext(nullptr), m_callbackForPropertyRegistered(false)
{ {
#if QT_CONFIG(cursor) #if QT_CONFIG(cursor)
// see NUM_BITMAPS in libXcursor/src/xcursorint.h // see NUM_BITMAPS in libXcursor/src/xcursorint.h
@ -280,36 +263,14 @@ QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen)
const char *cursorStr = "cursor"; const char *cursorStr = "cursor";
xcb_open_font(xcb_connection(), cursorFont, strlen(cursorStr), cursorStr); xcb_open_font(xcb_connection(), cursorFont, strlen(cursorStr), cursorStr);
#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) updateContext();
static bool function_ptrs_not_initialized = true;
if (function_ptrs_not_initialized) {
QLibrary xcursorLib("Xcursor"_L1, 1);
bool xcursorFound = xcursorLib.load();
if (!xcursorFound) { // try without the version number
xcursorLib.setFileName("Xcursor"_L1);
xcursorFound = xcursorLib.load();
}
if (xcursorFound) {
ptrXcursorLibraryLoadCursor =
(PtrXcursorLibraryLoadCursor) xcursorLib.resolve("XcursorLibraryLoadCursor");
ptrXcursorLibraryGetTheme =
(PtrXcursorLibraryGetTheme) xcursorLib.resolve("XcursorGetTheme");
ptrXcursorLibrarySetTheme =
(PtrXcursorLibrarySetTheme) xcursorLib.resolve("XcursorSetTheme");
ptrXcursorLibraryGetDefaultSize =
(PtrXcursorLibraryGetDefaultSize) xcursorLib.resolve("XcursorGetDefaultSize");
}
function_ptrs_not_initialized = false;
}
#endif
} }
QXcbCursor::~QXcbCursor() QXcbCursor::~QXcbCursor()
{ {
xcb_connection_t *conn = xcb_connection(); xcb_connection_t *conn = xcb_connection();
if (m_gtkCursorThemeInitialized) { if (m_callbackForPropertyRegistered) {
m_screen->xSettings()->removeCallbackForHandle(this); m_screen->xSettings()->removeCallbackForHandle(this);
} }
@ -320,6 +281,23 @@ QXcbCursor::~QXcbCursor()
for (xcb_cursor_t cursor : qAsConst(m_cursorHash)) for (xcb_cursor_t cursor : qAsConst(m_cursorHash))
xcb_free_cursor(conn, cursor); xcb_free_cursor(conn, cursor);
#endif #endif
if (m_cursorContext)
xcb_cursor_context_free(m_cursorContext);
}
void QXcbCursor::updateContext()
{
if (m_cursorContext)
xcb_cursor_context_free(m_cursorContext);
m_cursorContext = nullptr;
xcb_connection_t *conn = xcb_connection();
if (xcb_cursor_context_new(conn, m_screen->screen(), &m_cursorContext) < 0) {
qWarning() << "xcb: Could not initialize xcb-cursor";
m_cursorContext = nullptr;
}
} }
#ifndef QT_NO_CURSOR #ifndef QT_NO_CURSOR
@ -482,76 +460,39 @@ xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape)
return cursor; return cursor;
} }
#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) void QXcbCursor::cursorThemePropertyChanged(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &property, void *handle)
bool updateCursorTheme(void *dpy, const QByteArray &theme) {
if (!ptrXcursorLibraryGetTheme
|| !ptrXcursorLibrarySetTheme)
return false;
QByteArray oldTheme = ptrXcursorLibraryGetTheme(dpy);
if (oldTheme == theme)
return false;
int setTheme = ptrXcursorLibrarySetTheme(dpy,theme.constData());
return setTheme;
}
void QXcbCursor::cursorThemePropertyChanged(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &property, void *handle)
{ {
Q_UNUSED(screen); Q_UNUSED(screen);
Q_UNUSED(name); Q_UNUSED(name);
Q_UNUSED(property);
QXcbCursor *self = static_cast<QXcbCursor *>(handle); QXcbCursor *self = static_cast<QXcbCursor *>(handle);
self->m_cursorHash.clear(); self->m_cursorHash.clear();
self->updateContext();
updateCursorTheme(self->connection()->xlib_display(),property.toByteArray());
} }
static xcb_cursor_t loadCursor(void *dpy, int cshape)
{
xcb_cursor_t cursor = XCB_NONE;
if (!ptrXcursorLibraryLoadCursor || !dpy)
return cursor;
for (const char *cursorName: cursorNames[cshape]) {
cursor = ptrXcursorLibraryLoadCursor(dpy, cursorName);
if (cursor != XCB_NONE)
break;
}
return cursor;
}
#endif // QT_CONFIG(xcb_xlib) / QT_CONFIG(library)
xcb_cursor_t QXcbCursor::createFontCursor(int cshape) xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
{ {
if (!m_cursorContext)
return XCB_NONE;
xcb_connection_t *conn = xcb_connection(); xcb_connection_t *conn = xcb_connection();
int cursorId = cursorIdForShape(cshape); int cursorId = cursorIdForShape(cshape);
xcb_cursor_t cursor = XCB_NONE; xcb_cursor_t cursor = XCB_NONE;
#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) if (!m_callbackForPropertyRegistered && m_screen->xSettings()->initialized()) {
if (m_screen->xSettings()->initialized()) m_screen->xSettings()->registerCallbackForProperty("Gtk/CursorThemeName", cursorThemePropertyChanged, this);
m_screen->xSettings()->registerCallbackForProperty("Gtk/CursorThemeName",cursorThemePropertyChanged,this);
// Try Xcursor first m_callbackForPropertyRegistered = true;
}
// Try xcb-cursor first
if (cshape >= 0 && cshape <= Qt::LastCursor) { if (cshape >= 0 && cshape <= Qt::LastCursor) {
void *dpy = connection()->xlib_display(); for (const char *cursorName : cursorNames[cshape]) {
cursor = loadCursor(dpy, cshape); cursor = xcb_cursor_load_cursor(m_cursorContext, cursorName);
if (!cursor && !m_gtkCursorThemeInitialized && m_screen->xSettings()->initialized()) { if (cursor != XCB_NONE)
QByteArray gtkCursorTheme = m_screen->xSettings()->setting("Gtk/CursorThemeName").toByteArray(); return cursor;
if (updateCursorTheme(dpy,gtkCursorTheme)) {
cursor = loadCursor(dpy, cshape);
}
m_gtkCursorThemeInitialized = true;
} }
} }
if (cursor)
return cursor;
if (!cursor && cursorId) {
cursor = XCreateFontCursor(static_cast<Display *>(connection()->xlib_display()), cursorId);
if (cursor)
return cursor;
}
#endif
// Non-standard X11 cursors are created from bitmaps // Non-standard X11 cursors are created from bitmaps
cursor = createNonStandardCursor(cshape); cursor = createNonStandardCursor(cshape);

View File

@ -1,4 +1,4 @@
// Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QXCBCURSOR_H #ifndef QXCBCURSOR_H
@ -6,6 +6,7 @@
#include <qpa/qplatformcursor.h> #include <qpa/qplatformcursor.h>
#include "qxcbscreen.h" #include "qxcbscreen.h"
#include <xcb/xcb_cursor.h>
#include <QtCore/QCache> #include <QtCore/QCache>
@ -47,6 +48,8 @@ public:
QPoint pos() const override; QPoint pos() const override;
void setPos(const QPoint &pos) override; void setPos(const QPoint &pos) override;
void updateContext();
static void queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask = nullptr); static void queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask = nullptr);
#ifndef QT_NO_CURSOR #ifndef QT_NO_CURSOR
@ -75,17 +78,16 @@ private:
#endif #endif
QXcbScreen *m_screen; QXcbScreen *m_screen;
xcb_cursor_context_t *m_cursorContext;
#ifndef QT_NO_CURSOR #ifndef QT_NO_CURSOR
CursorHash m_cursorHash; CursorHash m_cursorHash;
BitmapCursorCache m_bitmapCache; BitmapCursorCache m_bitmapCache;
#endif #endif
#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
static void cursorThemePropertyChanged(QXcbVirtualDesktop *screen, static void cursorThemePropertyChanged(QXcbVirtualDesktop *screen,
const QByteArray &name, const QByteArray &name,
const QVariant &property, const QVariant &property,
void *handle); void *handle);
#endif bool m_callbackForPropertyRegistered;
bool m_gtkCursorThemeInitialized;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -475,6 +475,13 @@ _library_map = [
appendFoundSuffix=False, appendFoundSuffix=False,
), ),
LibraryMapping("xcb_glx", "XCB", "XCB::GLX", components=["GLX"], resultVariable="XCB_GLX"), LibraryMapping("xcb_glx", "XCB", "XCB::GLX", components=["GLX"], resultVariable="XCB_GLX"),
LibraryMapping(
"xcb_cursor",
"XCB",
"XCB::CURSOR",
extra=["0.1.1", "COMPONENTS", "CURSOR"],
resultVariable="XCB_CURSOR",
),
LibraryMapping( LibraryMapping(
"xcb_icccm", "xcb_icccm",
"XCB", "XCB",