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