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