Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qxcbcursor.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qxcbcursor.h"
5#include "qxcbconnection.h"
6#include "qxcbwindow.h"
7#include "qxcbimage.h"
8#include "qxcbxsettings.h"
9
10#include <QtGui/QWindow>
11#include <QtGui/QBitmap>
12#include <QtGui/private/qguiapplication_p.h>
13#include <qpa/qplatformtheme.h>
14
15#if QT_CONFIG(xcb_xlib)
16#include <X11/cursorfont.h>
17#else
18#include "qxcbcursorfont.h"
19#endif
20
21#include <xcb/xfixes.h>
22#include <xcb/xcb_image.h>
23
25
26using namespace Qt::StringLiterals;
27
28static xcb_font_t cursorFont = 0;
29static int cursorCount = 0;
30
31#ifndef QT_NO_CURSOR
32
33static uint8_t cur_blank_bits[] = {
34 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
37
38static const uint8_t cur_ver_bits[] = {
39 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f,
40 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xf0, 0x0f,
41 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00 };
42static const uint8_t mcur_ver_bits[] = {
43 0x00, 0x00, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f,
44 0xfc, 0x7f, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xfc, 0x7f, 0xf8, 0x3f,
45 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03 };
46static const uint8_t cur_hor_bits[] = {
47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x30, 0x18,
48 0x38, 0x38, 0xfc, 0x7f, 0xfc, 0x7f, 0x38, 0x38, 0x30, 0x18, 0x20, 0x08,
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
50static const uint8_t mcur_hor_bits[] = {
51 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x60, 0x0c, 0x70, 0x1c, 0x78, 0x3c,
52 0xfc, 0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0x7f, 0x78, 0x3c,
53 0x70, 0x1c, 0x60, 0x0c, 0x40, 0x04, 0x00, 0x00 };
54static const uint8_t cur_bdiag_bits[] = {
55 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x3e,
56 0x00, 0x37, 0x88, 0x23, 0xd8, 0x01, 0xf8, 0x00, 0x78, 0x00, 0xf8, 0x00,
57 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
58static const uint8_t mcur_bdiag_bits[] = {
59 0x00, 0x00, 0xc0, 0x7f, 0x80, 0x7f, 0x00, 0x7f, 0x00, 0x7e, 0x04, 0x7f,
60 0x8c, 0x7f, 0xdc, 0x77, 0xfc, 0x63, 0xfc, 0x41, 0xfc, 0x00, 0xfc, 0x01,
61 0xfc, 0x03, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00 };
62static const uint8_t cur_fdiag_bits[] = {
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0xf8, 0x00, 0x78, 0x00,
64 0xf8, 0x00, 0xd8, 0x01, 0x88, 0x23, 0x00, 0x37, 0x00, 0x3e, 0x00, 0x3c,
65 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00 };
66static const uint8_t mcur_fdiag_bits[] = {
67 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0xfc, 0x03, 0xfc, 0x01, 0xfc, 0x00,
68 0xfc, 0x41, 0xfc, 0x63, 0xdc, 0x77, 0x8c, 0x7f, 0x04, 0x7f, 0x00, 0x7e,
69 0x00, 0x7f, 0x80, 0x7f, 0xc0, 0x7f, 0x00, 0x00 };
74
75static const uint8_t vsplit_bits[] = {
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00,
79 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
80 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
82 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
83 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
84 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
87static const uint8_t vsplitm_bits[] = {
88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
89 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
90 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00,
91 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
92 0x00, 0xc0, 0x01, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
93 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
94 0x80, 0xff, 0xff, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
95 0x00, 0xc0, 0x01, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00,
96 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
99static const uint8_t hsplit_bits[] = {
100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
103 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
104 0x00, 0x41, 0x82, 0x00, 0x80, 0x41, 0x82, 0x01, 0xc0, 0x7f, 0xfe, 0x03,
105 0x80, 0x41, 0x82, 0x01, 0x00, 0x41, 0x82, 0x00, 0x00, 0x40, 0x02, 0x00,
106 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
107 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
111static const uint8_t hsplitm_bits[] = {
112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
115 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe3, 0xc7, 0x00,
116 0x80, 0xe3, 0xc7, 0x01, 0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07,
117 0xc0, 0xff, 0xff, 0x03, 0x80, 0xe3, 0xc7, 0x01, 0x00, 0xe3, 0xc7, 0x00,
118 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
119 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
123static const uint8_t whatsthis_bits[] = {
124 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0xf0, 0x07, 0x00,
125 0x09, 0x18, 0x0e, 0x00, 0x11, 0x1c, 0x0e, 0x00, 0x21, 0x1c, 0x0e, 0x00,
126 0x41, 0x1c, 0x0e, 0x00, 0x81, 0x1c, 0x0e, 0x00, 0x01, 0x01, 0x07, 0x00,
127 0x01, 0x82, 0x03, 0x00, 0xc1, 0xc7, 0x01, 0x00, 0x49, 0xc0, 0x01, 0x00,
128 0x95, 0xc0, 0x01, 0x00, 0x93, 0xc0, 0x01, 0x00, 0x21, 0x01, 0x00, 0x00,
129 0x20, 0xc1, 0x01, 0x00, 0x40, 0xc2, 0x01, 0x00, 0x40, 0x02, 0x00, 0x00,
130 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
135static const uint8_t whatsthism_bits[] = {
136 0x01, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x07, 0x00, 0x07, 0xf8, 0x0f, 0x00,
137 0x0f, 0xfc, 0x1f, 0x00, 0x1f, 0x3e, 0x1f, 0x00, 0x3f, 0x3e, 0x1f, 0x00,
138 0x7f, 0x3e, 0x1f, 0x00, 0xff, 0x3e, 0x1f, 0x00, 0xff, 0x9d, 0x0f, 0x00,
139 0xff, 0xc3, 0x07, 0x00, 0xff, 0xe7, 0x03, 0x00, 0x7f, 0xe0, 0x03, 0x00,
140 0xf7, 0xe0, 0x03, 0x00, 0xf3, 0xe0, 0x03, 0x00, 0xe1, 0xe1, 0x03, 0x00,
141 0xe0, 0xe1, 0x03, 0x00, 0xc0, 0xe3, 0x03, 0x00, 0xc0, 0xe3, 0x03, 0x00,
142 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
147static const uint8_t busy_bits[] = {
148 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
149 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
150 0x41, 0xe0, 0xff, 0x00, 0x81, 0x20, 0x80, 0x00, 0x01, 0xe1, 0xff, 0x00,
151 0x01, 0x42, 0x40, 0x00, 0xc1, 0x47, 0x40, 0x00, 0x49, 0x40, 0x55, 0x00,
152 0x95, 0x80, 0x2a, 0x00, 0x93, 0x00, 0x15, 0x00, 0x21, 0x01, 0x0a, 0x00,
153 0x20, 0x01, 0x11, 0x00, 0x40, 0x82, 0x20, 0x00, 0x40, 0x42, 0x44, 0x00,
154 0x80, 0x41, 0x4a, 0x00, 0x00, 0x40, 0x55, 0x00, 0x00, 0xe0, 0xff, 0x00,
155 0x00, 0x20, 0x80, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
159static const uint8_t busym_bits[] = {
160 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
161 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
162 0x7f, 0xe0, 0xff, 0x00, 0xff, 0xe0, 0xff, 0x00, 0xff, 0xe1, 0xff, 0x00,
163 0xff, 0xc3, 0x7f, 0x00, 0xff, 0xc7, 0x7f, 0x00, 0x7f, 0xc0, 0x7f, 0x00,
164 0xf7, 0x80, 0x3f, 0x00, 0xf3, 0x00, 0x1f, 0x00, 0xe1, 0x01, 0x0e, 0x00,
165 0xe0, 0x01, 0x1f, 0x00, 0xc0, 0x83, 0x3f, 0x00, 0xc0, 0xc3, 0x7f, 0x00,
166 0x80, 0xc1, 0x7f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0xff, 0x00,
167 0x00, 0xe0, 0xff, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
171
172static const uint8_t * const cursor_bits32[] = {
174 nullptr, nullptr, nullptr, nullptr, whatsthis_bits, whatsthism_bits, busy_bits, busym_bits
175};
176
177static const uint8_t forbidden_bits[] = {
178 0x00,0x00,0x00,0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xf0,0x00,0x38,0xc0,0x01,
179 0x7c,0x80,0x03,0xec,0x00,0x03,0xce,0x01,0x07,0x86,0x03,0x06,0x06,0x07,0x06,
180 0x06,0x0e,0x06,0x06,0x1c,0x06,0x0e,0x38,0x07,0x0c,0x70,0x03,0x1c,0xe0,0x03,
181 0x38,0xc0,0x01,0xf0,0xe0,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00,0x00,0x00,0x00 };
182
183static const uint8_t forbiddenm_bits[] = {
184 0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xff,0x00,0xf8,0xff,0x01,0xfc,0xf0,0x03,
185 0xfe,0xc0,0x07,0xfe,0x81,0x07,0xff,0x83,0x0f,0xcf,0x07,0x0f,0x8f,0x0f,0x0f,
186 0x0f,0x1f,0x0f,0x0f,0x3e,0x0f,0x1f,0xfc,0x0f,0x1e,0xf8,0x07,0x3e,0xf0,0x07,
187 0xfc,0xe0,0x03,0xf8,0xff,0x01,0xf0,0xff,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00};
188
189static const uint8_t openhand_bits[] = {
190 0x80,0x01,0x58,0x0e,0x64,0x12,0x64,0x52,0x48,0xb2,0x48,0x92,
191 0x16,0x90,0x19,0x80,0x11,0x40,0x02,0x40,0x04,0x40,0x04,0x20,
192 0x08,0x20,0x10,0x10,0x20,0x10,0x00,0x00};
193static const uint8_t openhandm_bits[] = {
194 0x80,0x01,0xd8,0x0f,0xfc,0x1f,0xfc,0x5f,0xf8,0xff,0xf8,0xff,
195 0xf6,0xff,0xff,0xff,0xff,0x7f,0xfe,0x7f,0xfc,0x7f,0xfc,0x3f,
196 0xf8,0x3f,0xf0,0x1f,0xe0,0x1f,0x00,0x00};
197static const uint8_t closedhand_bits[] = {
198 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0x48,0x32,0x08,0x50,
199 0x10,0x40,0x18,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10,
200 0x20,0x10,0x20,0x10,0x00,0x00,0x00,0x00};
201static const uint8_t closedhandm_bits[] = {
202 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0xf8,0x3f,0xf8,0x7f,
203 0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f,
204 0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00};
205
206static const uint8_t * const cursor_bits20[] = {
208};
209
210// ### FIXME This mapping is incomplete - QTBUG-71423
211static const std::vector<const char *> cursorNames[] = {
212 { "left_ptr", "default", "top_left_arrow", "left_arrow" },
213 { "up_arrow" },
214 { "cross" },
215 { "wait", "watch", "0426c94ea35c87780ff01dc239897213" },
216 { "ibeam", "text", "xterm" },
217 { "size_ver", "ns-resize", "v_double_arrow", "00008160000006810000408080010102" },
218 { "size_hor", "ew-resize", "h_double_arrow", "028006030e0e7ebffc7f7070c0600140" },
219 { "size_bdiag", "nesw-resize", "50585d75b494802d0151028115016902", "fcf1c3c7cd4491d801f1e1c78f100000" },
220 { "size_fdiag", "nwse-resize", "38c5dff7c7b8962045400281044508d2", "c7088f0f3e6c8088236ef8e1e3e70000" },
221 { "size_all" },
222 { "blank" },
223 { "split_v", "row-resize", "sb_v_double_arrow", "2870a09082c103050810ffdffffe0204", "c07385c7190e701020ff7ffffd08103c" },
224 { "split_h", "col-resize", "sb_h_double_arrow", "043a9f68147c53184671403ffa811cc5", "14fef782d02440884392942c11205230" },
225 { "pointing_hand", "pointer", "hand1", "e29285e634086352946a0e7090d73106" },
226 { "forbidden", "not-allowed", "crossed_circle", "circle", "03b6e0fcb3499374a867c041f52298f0" },
227 { "whats_this", "help", "question_arrow", "5c6cd98b3f3ebcb1f9c7f1c204630408", "d9ce0ab605698f320427677b458ad60b" },
228 { "left_ptr_watch", "half-busy", "progress", "00000000000000020006000e7e9ffc3f", "08e8e1c95fe2fc01f976f1e063a24ccd" },
229 { "openhand", "grab", "fleur", "5aca4d189052212118709018842178c0", "9d800788f1b08800ae810202380a0822" },
230 { "closedhand", "grabbing", "208530c400c041818281048008011002" },
231 { "dnd-copy", "copy" },
232 { "dnd-move", "move" },
233 { "dnd-link", "link" }
234};
235
237 : shape(c.shape()), bitmapCacheKey(0), maskCacheKey(0)
238{
239 if (shape == Qt::BitmapCursor) {
240 const qint64 pixmapCacheKey = c.pixmap().cacheKey();
241 if (pixmapCacheKey) {
242 bitmapCacheKey = pixmapCacheKey;
243 } else {
244 Q_ASSERT(!c.bitmap().isNull());
245 Q_ASSERT(!c.mask().isNull());
246 bitmapCacheKey = c.bitmap().cacheKey();
247 maskCacheKey = c.mask().cacheKey();
248 }
249 }
250}
251
252#endif // !QT_NO_CURSOR
253
255 : QXcbObject(conn), m_screen(screen), m_cursorContext(nullptr), m_callbackForPropertyRegistered(false)
256{
257#if QT_CONFIG(cursor)
258 // see NUM_BITMAPS in libXcursor/src/xcursorint.h
259 m_bitmapCache.setMaxCost(8);
260#endif
261
263
264 if (cursorCount++)
265 return;
266
267 cursorFont = xcb_generate_id(xcb_connection());
268 const char *cursorStr = "cursor";
269 xcb_open_font(xcb_connection(), cursorFont, strlen(cursorStr), cursorStr);
270}
271
273{
274 xcb_connection_t *conn = xcb_connection();
275
276 if (m_callbackForPropertyRegistered) {
277 m_screen->xSettings()->removeCallbackForHandle(this);
278 }
279
280 if (!--cursorCount)
281 xcb_close_font(conn, cursorFont);
282
283#ifndef QT_NO_CURSOR
284 for (xcb_cursor_t cursor : std::as_const(m_cursorHash))
285 xcb_free_cursor(conn, cursor);
286#endif
287
288 if (m_cursorContext)
289 xcb_cursor_context_free(m_cursorContext);
290}
291
293{
295 return theme->themeHint(QPlatformTheme::MouseCursorSize).toSize();
296 return QSize(24, 24);
297}
298
300{
301 if (m_cursorContext)
302 xcb_cursor_context_free(m_cursorContext);
303
304 m_cursorContext = nullptr;
305
306 xcb_connection_t *conn = xcb_connection();
307 if (xcb_cursor_context_new(conn, m_screen->screen(), &m_cursorContext) < 0) {
308 qWarning() << "xcb: Could not initialize xcb-cursor";
309 m_cursorContext = nullptr;
310 }
311}
312
313#ifndef QT_NO_CURSOR
315{
316 if (!window || !window->handle())
317 return;
318
319 xcb_cursor_t c = XCB_CURSOR_NONE;
320 if (cursor) {
322 const Qt::CursorShape shape = cursor->shape();
323
324 if (shape == Qt::BitmapCursor) {
325 auto *bitmap = m_bitmapCache.object(key);
326 if (bitmap) {
327 c = bitmap->cursor;
328 } else {
329 c = createBitmapCursor(cursor);
330 m_bitmapCache.insert(key, new CachedCursor(xcb_connection(), c));
331 }
332 } else {
333 auto it = m_cursorHash.find(key);
334 if (it == m_cursorHash.end()) {
335 c = createFontCursor(shape);
336 m_cursorHash.insert(key, c);
337 } else {
338 c = it.value();
339 }
340 }
341 }
342
343 auto *w = static_cast<QXcbWindow *>(window->handle());
344 xcb_change_window_attributes(xcb_connection(), w->xcb_window(), XCB_CW_CURSOR, &c);
345 xcb_flush(xcb_connection());
346}
347
348static int cursorIdForShape(int cshape)
349{
350 int cursorId = 0;
351 switch (cshape) {
352 case Qt::ArrowCursor:
353 cursorId = XC_left_ptr;
354 break;
356 cursorId = XC_center_ptr;
357 break;
358 case Qt::CrossCursor:
359 cursorId = XC_crosshair;
360 break;
361 case Qt::WaitCursor:
362 cursorId = XC_watch;
363 break;
364 case Qt::IBeamCursor:
365 cursorId = XC_xterm;
366 break;
368 cursorId = XC_fleur;
369 break;
371 cursorId = XC_hand2;
372 break;
374 cursorId = XC_top_right_corner;
375 break;
377 cursorId = XC_bottom_right_corner;
378 break;
380 case Qt::SplitVCursor:
381 cursorId = XC_sb_v_double_arrow;
382 break;
384 case Qt::SplitHCursor:
385 cursorId = XC_sb_h_double_arrow;
386 break;
388 cursorId = XC_question_arrow;
389 break;
391 cursorId = XC_circle;
392 break;
393 case Qt::BusyCursor:
394 cursorId = XC_watch;
395 break;
396 default:
397 break;
398 }
399 return cursorId;
400}
401
402xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape)
403{
404 xcb_cursor_t cursor = 0;
405 xcb_connection_t *conn = xcb_connection();
406
407 if (cshape == Qt::BlankCursor) {
408 xcb_pixmap_t cp = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), cur_blank_bits, 16, 16,
409 1, 0, 0, nullptr);
410 xcb_pixmap_t mp = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), cur_blank_bits, 16, 16,
411 1, 0, 0, nullptr);
412 cursor = xcb_generate_id(conn);
413 xcb_create_cursor(conn, cursor, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8);
414 } else if (cshape >= Qt::SizeVerCursor && cshape < Qt::SizeAllCursor) {
415 int i = (cshape - Qt::SizeVerCursor) * 2;
416 xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
417 const_cast<uint8_t*>(cursor_bits16[i]),
418 16, 16, 1, 0, 0, nullptr);
419 xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
420 const_cast<uint8_t*>(cursor_bits16[i + 1]),
421 16, 16, 1, 0, 0, nullptr);
422 cursor = xcb_generate_id(conn);
423 xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8);
424 } else if ((cshape >= Qt::SplitVCursor && cshape <= Qt::SplitHCursor)
425 || cshape == Qt::WhatsThisCursor || cshape == Qt::BusyCursor) {
426 int i = (cshape - Qt::SplitVCursor) * 2;
427 xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
428 const_cast<uint8_t*>(cursor_bits32[i]),
429 32, 32, 1, 0, 0, nullptr);
430 xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
431 const_cast<uint8_t*>(cursor_bits32[i + 1]),
432 32, 32, 1, 0, 0, nullptr);
433 int hs = (cshape == Qt::PointingHandCursor || cshape == Qt::WhatsThisCursor
434 || cshape == Qt::BusyCursor) ? 0 : 16;
435 cursor = xcb_generate_id(conn);
436 xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, hs, hs);
437 } else if (cshape == Qt::ForbiddenCursor) {
438 int i = (cshape - Qt::ForbiddenCursor) * 2;
439 xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
440 const_cast<uint8_t*>(cursor_bits20[i]),
441 20, 20, 1, 0, 0, nullptr);
442 xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
443 const_cast<uint8_t*>(cursor_bits20[i + 1]),
444 20, 20, 1, 0, 0, nullptr);
445 cursor = xcb_generate_id(conn);
446 xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 10, 10);
447 } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) {
448 bool open = cshape == Qt::OpenHandCursor;
449 xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
450 const_cast<uint8_t*>(open ? openhand_bits : closedhand_bits),
451 16, 16, 1, 0, 0, nullptr);
452 xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
453 const_cast<uint8_t*>(open ? openhandm_bits : closedhandm_bits),
454 16, 16, 1, 0, 0, nullptr);
455 cursor = xcb_generate_id(conn);
456 xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8);
457 } else if (cshape == Qt::DragCopyCursor || cshape == Qt::DragMoveCursor
458 || cshape == Qt::DragLinkCursor) {
459 QImage image = QGuiApplicationPrivate::instance()->getPixmapCursor(static_cast<Qt::CursorShape>(cshape)).toImage();
460 if (!image.isNull()) {
461 xcb_pixmap_t pm = qt_xcb_XPixmapFromBitmap(m_screen, image);
462 xcb_pixmap_t pmm = qt_xcb_XPixmapFromBitmap(m_screen, image.createAlphaMask());
463 cursor = xcb_generate_id(conn);
464 xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8);
465 xcb_free_pixmap(conn, pm);
466 xcb_free_pixmap(conn, pmm);
467 }
468 }
469
470 return cursor;
471}
472
473void QXcbCursor::cursorThemePropertyChanged(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &property, void *handle)
474{
476 Q_UNUSED(name);
478 QXcbCursor *self = static_cast<QXcbCursor *>(handle);
479 self->m_cursorHash.clear();
480 self->updateContext();
481}
482
483xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
484{
485 if (!m_cursorContext)
486 return XCB_NONE;
487
488 xcb_connection_t *conn = xcb_connection();
489 int cursorId = cursorIdForShape(cshape);
490 xcb_cursor_t cursor = XCB_NONE;
491
492 if (!m_callbackForPropertyRegistered && m_screen->xSettings()->initialized()) {
493 m_screen->xSettings()->registerCallbackForProperty("Gtk/CursorThemeName", cursorThemePropertyChanged, this);
494
495 m_callbackForPropertyRegistered = true;
496 }
497
498 // Try xcb-cursor first
499 if (cshape >= 0 && cshape <= Qt::LastCursor) {
500 for (const char *cursorName : cursorNames[cshape]) {
501 cursor = xcb_cursor_load_cursor(m_cursorContext, cursorName);
502 if (cursor != XCB_NONE)
503 return cursor;
504 }
505 }
506
507 // Non-standard X11 cursors are created from bitmaps
508 cursor = createNonStandardCursor(cshape);
509
510 // Create a glyph cursor if everything else failed
511 if (!cursor && cursorId) {
512 cursor = xcb_generate_id(conn);
513 xcb_create_glyph_cursor(conn, cursor, cursorFont, cursorFont,
514 cursorId, cursorId + 1,
515 0xFFFF, 0xFFFF, 0xFFFF, 0, 0, 0);
516 }
517
518 if (cursor && cshape >= 0 && cshape < Qt::LastCursor && connection()->hasXFixes()) {
519 const char *name = cursorNames[cshape].front();
520 xcb_xfixes_set_cursor_name(conn, cursor, strlen(name), name);
521 }
522
523 return cursor;
524}
525
526xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor)
527{
528 QPoint spot = cursor->hotSpot();
529 xcb_cursor_t c = XCB_NONE;
530 if (cursor->pixmap().depth() > 1) {
531 if (connection()->hasXRender(0, 5))
532 c = qt_xcb_createCursorXRender(m_screen, cursor->pixmap().toImage(), spot);
533 else
534 qCWarning(lcQpaXcb, "xrender >= 0.5 required to create pixmap cursors");
535 } else {
536 xcb_connection_t *conn = xcb_connection();
537 xcb_pixmap_t cp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->bitmap().toImage());
538 xcb_pixmap_t mp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->mask().toImage());
539 c = xcb_generate_id(conn);
540 xcb_create_cursor(conn, c, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF,
541 spot.x(), spot.y());
542 xcb_free_pixmap(conn, cp);
543 xcb_free_pixmap(conn, mp);
544 }
545 return c;
546}
547#endif
548
555void QXcbCursor::queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask)
556{
557 if (pos)
558 *pos = QPoint();
559
560 xcb_window_t root = c->primaryVirtualDesktop()->root();
561
562 auto reply = Q_XCB_REPLY(xcb_query_pointer, c->xcb_connection(), root);
563 if (reply) {
564 if (virtualDesktop) {
565 const auto virtualDesktops = c->virtualDesktops();
566 for (QXcbVirtualDesktop *vd : virtualDesktops) {
567 if (vd->root() == reply->root) {
568 *virtualDesktop = vd;
569 break;
570 }
571 }
572 }
573 if (pos)
574 *pos = QPoint(reply->root_x, reply->root_y);
575 if (keybMask)
576 *keybMask = reply->mask;
577 return;
578 }
579}
580
582{
583 QPoint p;
584 queryPointer(connection(), nullptr, &p);
585 return p;
586}
587
589{
590 QXcbVirtualDesktop *virtualDesktop = nullptr;
591 queryPointer(connection(), &virtualDesktop, nullptr);
592 if (virtualDesktop)
593 xcb_warp_pointer(xcb_connection(), XCB_NONE, virtualDesktop->root(), 0, 0, 0, 0, pos.x(), pos.y());
594 xcb_flush(xcb_connection());
595}
596
\inmodule QtCore
Definition qbytearray.h:57
void setMaxCost(qsizetype m) noexcept(std::is_nothrow_destructible_v< Node >)
Definition qcache.h:154
T * object(const Key &key) const noexcept
Definition qcache.h:209
bool insert(const Key &key, T *object, qsizetype cost=1)
Definition qcache.h:184
The QCursor class provides a mouse cursor with an arbitrary shape.
Definition qcursor.h:45
QBitmap bitmap() const
Returns the cursor bitmap, or a null bitmap if it is one of the standard cursors.
Definition qcursor.cpp:545
QPixmap pixmap() const
Returns the cursor pixmap.
Definition qcursor.cpp:584
Qt::CursorShape shape() const
Returns the cursor shape identifier.
Definition qcursor.cpp:498
QPoint hotSpot() const
Returns the cursor hot spot, or (0, 0) if it is one of the standard cursors.
Definition qcursor.cpp:595
QBitmap mask() const
Returns the cursor bitmap mask, or a null bitmap if it is one of the standard cursors.
Definition qcursor.cpp:571
static QGuiApplicationPrivate * instance()
static QPlatformTheme * platformTheme()
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition qhash.h:1291
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1216
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
\inmodule QtGui
Definition qimage.h:37
QImage toImage() const
Converts the pixmap to a QImage.
Definition qpixmap.cpp:408
int depth() const
Returns the depth of the pixmap.
Definition qpixmap.cpp:521
The QPlatformTheme class allows customizing the UI based on themes.
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
\inmodule QtCore
Definition qsize.h:25
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1252
\inmodule QtCore
Definition qvariant.h:65
\inmodule QtGui
Definition qwindow.h:63
void updateContext()
void changeCursor(QCursor *cursor, QWindow *window) override
This method is called by Qt whenever the cursor graphic should be changed.
QPoint pos() const override
QXcbCursor(QXcbConnection *conn, QXcbScreen *screen)
static void queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask=nullptr)
void setPos(const QPoint &pos) override
QSize size() const override
Returns the size of the cursor, in native pixels.
QXcbConnection * connection() const
Definition qxcbobject.h:17
xcb_connection_t * xcb_connection() const
Definition qxcbobject.h:20
xcb_screen_t * screen() const
Definition qxcbscreen.h:152
xcb_window_t root() const
Definition qxcbscreen.h:153
QXcbXSettings * xSettings() const
xcb_window_t root() const
Definition qxcbscreen.h:43
void removeCallbackForHandle(const QByteArray &property, void *handle)
void registerCallbackForProperty(const QByteArray &property, PropertyChangeFunc func, void *handle)
bool initialized() const
QCursor cursor
QSet< QString >::iterator it
Combined button and popup list for selecting options.
CursorShape
@ BlankCursor
@ CrossCursor
@ DragCopyCursor
@ BitmapCursor
@ PointingHandCursor
@ SizeHorCursor
@ SizeAllCursor
@ LastCursor
@ WaitCursor
@ SizeVerCursor
@ DragLinkCursor
@ OpenHandCursor
@ SizeFDiagCursor
@ WhatsThisCursor
@ ArrowCursor
@ SplitVCursor
@ UpArrowCursor
@ ClosedHandCursor
@ DragMoveCursor
@ IBeamCursor
@ SizeBDiagCursor
@ ForbiddenCursor
@ BusyCursor
@ SplitHCursor
Definition image.cpp:4
QString self
Definition language.cpp:58
#define qWarning
Definition qlogging.h:166
#define qCWarning(category,...)
GLuint64 GLenum void * handle
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLuint name
const GLubyte * c
GLsizei GLfixed GLfixed GLfixed GLfixed const GLubyte * bitmap
GLfloat GLfloat p
[1]
static const uchar openhandm_bits[]
static const uchar openhand_bits[]
static const uchar closedhandm_bits[]
static const uchar closedhand_bits[]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QScreen * screen
[1]
Definition main.cpp:29
#define Q_UNUSED(x)
long long qint64
Definition qtypes.h:60
const char property[13]
Definition qwizard.cpp:101
#define Q_XCB_REPLY(call,...)
static const uint8_t cur_hor_bits[]
static uint8_t cur_blank_bits[]
static const uint8_t whatsthis_bits[]
static const uint8_t cur_fdiag_bits[]
static int cursorIdForShape(int cshape)
static const uint8_t openhandm_bits[]
static const uint8_t *const cursor_bits32[]
static const uint8_t closedhand_bits[]
static const uint8_t cur_ver_bits[]
static const uint8_t whatsthism_bits[]
static const std::vector< const char * > cursorNames[]
static const uint8_t hsplit_bits[]
static const uint8_t cur_bdiag_bits[]
static const uint8_t closedhandm_bits[]
static xcb_font_t cursorFont
static const uint8_t forbidden_bits[]
static const uint8_t mcur_fdiag_bits[]
static const uint8_t vsplitm_bits[]
static const uint8_t * cursor_bits16[]
static const uint8_t mcur_ver_bits[]
static const uint8_t forbiddenm_bits[]
static int cursorCount
static const uint8_t mcur_bdiag_bits[]
static const uint8_t busy_bits[]
static const uint8_t vsplit_bits[]
static const uint8_t busym_bits[]
static const uint8_t hsplitm_bits[]
static const uint8_t *const cursor_bits20[]
static const uint8_t openhand_bits[]
static const uint8_t mcur_hor_bits[]
#define XC_circle
#define XC_hand2
#define XC_xterm
#define XC_crosshair
#define XC_watch
#define XC_bottom_right_corner
#define XC_fleur
#define XC_center_ptr
#define XC_sb_h_double_arrow
#define XC_left_ptr
#define XC_question_arrow
#define XC_sb_v_double_arrow
#define XC_top_right_corner
xcb_pixmap_t qt_xcb_XPixmapFromBitmap(QXcbScreen *screen, const QImage &image)
xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image, const QPoint &spot)
file open(QIODevice::ReadOnly)
QObject::connect nullptr
aWidget window() -> setWindowTitle("New Window Title")
[2]
QNetworkReply * reply
Qt::CursorShape shape
Definition qxcbcursor.h:23