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:
parent
e6d3657f7f
commit
012132c60d
@ -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>
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user