summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb/qxcbcursor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbcursor.cpp')
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.cpp238
1 files changed, 80 insertions, 158 deletions
diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp
index fbadab4d50..dc9ed46956 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.cpp
+++ b/src/plugins/platforms/xcb/qxcbcursor.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// 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
#include "qxcbcursor.h"
#include "qxcbconnection.h"
@@ -43,35 +7,23 @@
#include "qxcbimage.h"
#include "qxcbxsettings.h"
-#if QT_CONFIG(library)
-#include <QtCore/QLibrary>
-#endif
#include <QtGui/QWindow>
#include <QtGui/QBitmap>
#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformtheme.h>
+
+#if QT_CONFIG(xcb_xlib)
#include <X11/cursorfont.h>
+#else
+#include "qxcbcursorfont.h"
+#endif
+
#include <xcb/xfixes.h>
#include <xcb/xcb_image.h>
QT_BEGIN_NAMESPACE
-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 = 0;
-static PtrXcursorLibraryGetTheme ptrXcursorLibraryGetTheme = 0;
-static PtrXcursorLibrarySetTheme ptrXcursorLibrarySetTheme = 0;
-static PtrXcursorLibraryGetDefaultSize ptrXcursorLibraryGetDefaultSize = 0;
-#endif
+using namespace Qt::StringLiterals;
static xcb_font_t cursorFont = 0;
static int cursorCount = 0;
@@ -118,7 +70,7 @@ static const uint8_t mcur_fdiag_bits[] = {
static const uint8_t *cursor_bits16[] = {
cur_ver_bits, mcur_ver_bits, cur_hor_bits, mcur_hor_bits,
cur_bdiag_bits, mcur_bdiag_bits, cur_fdiag_bits, mcur_fdiag_bits,
- 0, 0, cur_blank_bits, cur_blank_bits };
+ nullptr, nullptr, cur_blank_bits, cur_blank_bits };
static const uint8_t vsplit_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -219,7 +171,7 @@ static const uint8_t busym_bits[] = {
static const uint8_t * const cursor_bits32[] = {
vsplit_bits, vsplitm_bits, hsplit_bits, hsplitm_bits,
- 0, 0, 0, 0, whatsthis_bits, whatsthism_bits, busy_bits, busym_bits
+ nullptr, nullptr, nullptr, nullptr, whatsthis_bits, whatsthism_bits, busy_bits, busym_bits
};
static const uint8_t forbidden_bits[] = {
@@ -289,10 +241,10 @@ QXcbCursorCacheKey::QXcbCursorCacheKey(const QCursor &c)
if (pixmapCacheKey) {
bitmapCacheKey = pixmapCacheKey;
} else {
- Q_ASSERT(c.bitmap());
- Q_ASSERT(c.mask());
- bitmapCacheKey = c.bitmap()->cacheKey();
- maskCacheKey = c.mask()->cacheKey();
+ Q_ASSERT(!c.bitmap().isNull());
+ Q_ASSERT(!c.mask().isNull());
+ bitmapCacheKey = c.bitmap().cacheKey();
+ maskCacheKey = c.mask().cacheKey();
}
}
}
@@ -300,50 +252,28 @@ QXcbCursorCacheKey::QXcbCursorCacheKey(const QCursor &c)
#endif // !QT_NO_CURSOR
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)
// see NUM_BITMAPS in libXcursor/src/xcursorint.h
m_bitmapCache.setMaxCost(8);
#endif
+ updateContext();
+
if (cursorCount++)
return;
cursorFont = xcb_generate_id(xcb_connection());
const char *cursorStr = "cursor";
xcb_open_font(xcb_connection(), cursorFont, strlen(cursorStr), cursorStr);
-
-#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
- static bool function_ptrs_not_initialized = true;
- if (function_ptrs_not_initialized) {
- QLibrary xcursorLib(QLatin1String("Xcursor"), 1);
- bool xcursorFound = xcursorLib.load();
- if (!xcursorFound) { // try without the version number
- xcursorLib.setFileName(QLatin1String("Xcursor"));
- 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()
{
xcb_connection_t *conn = xcb_connection();
- if (m_gtkCursorThemeInitialized) {
+ if (m_callbackForPropertyRegistered) {
m_screen->xSettings()->removeCallbackForHandle(this);
}
@@ -351,9 +281,33 @@ QXcbCursor::~QXcbCursor()
xcb_close_font(conn, cursorFont);
#ifndef QT_NO_CURSOR
- for (xcb_cursor_t cursor : qAsConst(m_cursorHash))
+ for (xcb_cursor_t cursor : std::as_const(m_cursorHash))
xcb_free_cursor(conn, cursor);
#endif
+
+ if (m_cursorContext)
+ xcb_cursor_context_free(m_cursorContext);
+}
+
+QSize QXcbCursor::size() const
+{
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ return theme->themeHint(QPlatformTheme::MouseCursorSize).toSize();
+ return QSize(24, 24);
+}
+
+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
@@ -452,19 +406,19 @@ xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape)
if (cshape == Qt::BlankCursor) {
xcb_pixmap_t cp = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), cur_blank_bits, 16, 16,
- 1, 0, 0, 0);
+ 1, 0, 0, nullptr);
xcb_pixmap_t mp = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), cur_blank_bits, 16, 16,
- 1, 0, 0, 0);
+ 1, 0, 0, nullptr);
cursor = xcb_generate_id(conn);
xcb_create_cursor(conn, cursor, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8);
} else if (cshape >= Qt::SizeVerCursor && cshape < Qt::SizeAllCursor) {
int i = (cshape - Qt::SizeVerCursor) * 2;
xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
const_cast<uint8_t*>(cursor_bits16[i]),
- 16, 16, 1, 0, 0, 0);
+ 16, 16, 1, 0, 0, nullptr);
xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
const_cast<uint8_t*>(cursor_bits16[i + 1]),
- 16, 16, 1, 0, 0, 0);
+ 16, 16, 1, 0, 0, nullptr);
cursor = xcb_generate_id(conn);
xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8);
} else if ((cshape >= Qt::SplitVCursor && cshape <= Qt::SplitHCursor)
@@ -472,10 +426,10 @@ xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape)
int i = (cshape - Qt::SplitVCursor) * 2;
xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
const_cast<uint8_t*>(cursor_bits32[i]),
- 32, 32, 1, 0, 0, 0);
+ 32, 32, 1, 0, 0, nullptr);
xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
const_cast<uint8_t*>(cursor_bits32[i + 1]),
- 32, 32, 1, 0, 0, 0);
+ 32, 32, 1, 0, 0, nullptr);
int hs = (cshape == Qt::PointingHandCursor || cshape == Qt::WhatsThisCursor
|| cshape == Qt::BusyCursor) ? 0 : 16;
cursor = xcb_generate_id(conn);
@@ -484,20 +438,20 @@ xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape)
int i = (cshape - Qt::ForbiddenCursor) * 2;
xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
const_cast<uint8_t*>(cursor_bits20[i]),
- 20, 20, 1, 0, 0, 0);
+ 20, 20, 1, 0, 0, nullptr);
xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
const_cast<uint8_t*>(cursor_bits20[i + 1]),
- 20, 20, 1, 0, 0, 0);
+ 20, 20, 1, 0, 0, nullptr);
cursor = xcb_generate_id(conn);
xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 10, 10);
} else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) {
bool open = cshape == Qt::OpenHandCursor;
xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
const_cast<uint8_t*>(open ? openhand_bits : closedhand_bits),
- 16, 16, 1, 0, 0, 0);
+ 16, 16, 1, 0, 0, nullptr);
xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
const_cast<uint8_t*>(open ? openhandm_bits : closedhandm_bits),
- 16, 16, 1, 0, 0, 0);
+ 16, 16, 1, 0, 0, nullptr);
cursor = xcb_generate_id(conn);
xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8);
} else if (cshape == Qt::DragCopyCursor || cshape == Qt::DragMoveCursor
@@ -516,77 +470,44 @@ xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape)
return cursor;
}
-#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
-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)
+void QXcbCursor::cursorThemePropertyChanged(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &property, void *handle)
{
Q_UNUSED(screen);
Q_UNUSED(name);
+ Q_UNUSED(property);
QXcbCursor *self = static_cast<QXcbCursor *>(handle);
- 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;
+ self->m_cursorHash.clear();
+ self->updateContext();
}
-#endif // QT_CONFIG(xcb_xlib) / QT_CONFIG(library)
xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
{
+ if (!m_cursorContext)
+ return XCB_NONE;
+
xcb_connection_t *conn = xcb_connection();
int cursorId = cursorIdForShape(cshape);
xcb_cursor_t cursor = XCB_NONE;
- // Try Xcursor first
-#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
+ if (!m_callbackForPropertyRegistered && m_screen->xSettings()->initialized()) {
+ m_screen->xSettings()->registerCallbackForProperty("Gtk/CursorThemeName", cursorThemePropertyChanged, this);
+
+ m_callbackForPropertyRegistered = true;
+ }
+
+ // Try xcb-cursor first
if (cshape >= 0 && cshape <= Qt::LastCursor) {
- void *dpy = connection()->xlib_display();
- cursor = loadCursor(dpy, cshape);
- if (!cursor && !m_gtkCursorThemeInitialized && m_screen->xSettings()->initialized()) {
- QByteArray gtkCursorTheme = m_screen->xSettings()->setting("Gtk/CursorThemeName").toByteArray();
- m_screen->xSettings()->registerCallbackForProperty("Gtk/CursorThemeName",cursorThemePropertyChanged,this);
- if (updateCursorTheme(dpy,gtkCursorTheme)) {
- cursor = loadCursor(dpy, cshape);
- }
- m_gtkCursorThemeInitialized = true;
+ for (const char *cursorName : cursorNames[cshape]) {
+ cursor = xcb_cursor_load_cursor(m_cursorContext, cursorName);
+ if (cursor != XCB_NONE)
+ return cursor;
}
}
- 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
cursor = createNonStandardCursor(cshape);
- // Create a glpyh cursor if everything else failed
+ // Create a glyph cursor if everything else failed
if (!cursor && cursorId) {
cursor = xcb_generate_id(conn);
xcb_create_glyph_cursor(conn, cursor, cursorFont, cursorFont,
@@ -613,8 +534,8 @@ xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor)
qCWarning(lcQpaXcb, "xrender >= 0.5 required to create pixmap cursors");
} 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());
+ 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);
xcb_create_cursor(conn, c, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF,
spot.x(), spot.y());
@@ -660,15 +581,16 @@ void QXcbCursor::queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDes
QPoint QXcbCursor::pos() const
{
QPoint p;
- queryPointer(connection(), 0, &p);
+ queryPointer(connection(), nullptr, &p);
return p;
}
void QXcbCursor::setPos(const QPoint &pos)
{
QXcbVirtualDesktop *virtualDesktop = nullptr;
- queryPointer(connection(), &virtualDesktop, 0);
- xcb_warp_pointer(xcb_connection(), XCB_NONE, virtualDesktop->root(), 0, 0, 0, 0, pos.x(), pos.y());
+ queryPointer(connection(), &virtualDesktop, nullptr);
+ if (virtualDesktop)
+ xcb_warp_pointer(xcb_connection(), XCB_NONE, virtualDesktop->root(), 0, 0, 0, 0, pos.x(), pos.y());
xcb_flush(xcb_connection());
}