1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the plugins of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qxcbcursor.h"
41#include "qxcbconnection.h"
42#include "qxcbwindow.h"
43#include "qxcbimage.h"
44#include "qxcbxsettings.h"
45
46#if QT_CONFIG(library)
47#include <QtCore/QLibrary>
48#endif
49#include <QtGui/QWindow>
50#include <QtGui/QBitmap>
51#include <QtGui/private/qguiapplication_p.h>
52#include <X11/cursorfont.h>
53#include <xcb/xfixes.h>
54#include <xcb/xcb_image.h>
55
56QT_BEGIN_NAMESPACE
57
58typedef int (*PtrXcursorLibraryLoadCursor)(void *, const char *);
59typedef char *(*PtrXcursorLibraryGetTheme)(void *);
60typedef int (*PtrXcursorLibrarySetTheme)(void *, const char *);
61typedef int (*PtrXcursorLibraryGetDefaultSize)(void *);
62
63#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
64#include <X11/Xlib.h>
65enum {
66 XCursorShape = CursorShape
67};
68#undef CursorShape
69
70static PtrXcursorLibraryLoadCursor ptrXcursorLibraryLoadCursor = nullptr;
71static PtrXcursorLibraryGetTheme ptrXcursorLibraryGetTheme = nullptr;
72static PtrXcursorLibrarySetTheme ptrXcursorLibrarySetTheme = nullptr;
73static PtrXcursorLibraryGetDefaultSize ptrXcursorLibraryGetDefaultSize = nullptr;
74#endif
75
76static xcb_font_t cursorFont = 0;
77static int cursorCount = 0;
78
79#ifndef QT_NO_CURSOR
80
81static uint8_t cur_blank_bits[] = {
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
85
86static const uint8_t cur_ver_bits[] = {
87 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f,
88 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xf0, 0x0f,
89 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00 };
90static const uint8_t mcur_ver_bits[] = {
91 0x00, 0x00, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f,
92 0xfc, 0x7f, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xfc, 0x7f, 0xf8, 0x3f,
93 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03 };
94static const uint8_t cur_hor_bits[] = {
95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x30, 0x18,
96 0x38, 0x38, 0xfc, 0x7f, 0xfc, 0x7f, 0x38, 0x38, 0x30, 0x18, 0x20, 0x08,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
98static const uint8_t mcur_hor_bits[] = {
99 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x60, 0x0c, 0x70, 0x1c, 0x78, 0x3c,
100 0xfc, 0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0x7f, 0x78, 0x3c,
101 0x70, 0x1c, 0x60, 0x0c, 0x40, 0x04, 0x00, 0x00 };
102static const uint8_t cur_bdiag_bits[] = {
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x3e,
104 0x00, 0x37, 0x88, 0x23, 0xd8, 0x01, 0xf8, 0x00, 0x78, 0x00, 0xf8, 0x00,
105 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
106static const uint8_t mcur_bdiag_bits[] = {
107 0x00, 0x00, 0xc0, 0x7f, 0x80, 0x7f, 0x00, 0x7f, 0x00, 0x7e, 0x04, 0x7f,
108 0x8c, 0x7f, 0xdc, 0x77, 0xfc, 0x63, 0xfc, 0x41, 0xfc, 0x00, 0xfc, 0x01,
109 0xfc, 0x03, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00 };
110static const uint8_t cur_fdiag_bits[] = {
111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0xf8, 0x00, 0x78, 0x00,
112 0xf8, 0x00, 0xd8, 0x01, 0x88, 0x23, 0x00, 0x37, 0x00, 0x3e, 0x00, 0x3c,
113 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00 };
114static const uint8_t mcur_fdiag_bits[] = {
115 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0xfc, 0x03, 0xfc, 0x01, 0xfc, 0x00,
116 0xfc, 0x41, 0xfc, 0x63, 0xdc, 0x77, 0x8c, 0x7f, 0x04, 0x7f, 0x00, 0x7e,
117 0x00, 0x7f, 0x80, 0x7f, 0xc0, 0x7f, 0x00, 0x00 };
118static const uint8_t *cursor_bits16[] = {
119 cur_ver_bits, mcur_ver_bits, cur_hor_bits, mcur_hor_bits,
120 cur_bdiag_bits, mcur_bdiag_bits, cur_fdiag_bits, mcur_fdiag_bits,
121 nullptr, nullptr, cur_blank_bits, cur_blank_bits };
122
123static const uint8_t vsplit_bits[] = {
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00,
127 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
128 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
130 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
131 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
132 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 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 vsplitm_bits[] = {
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
138 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00,
139 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
140 0x00, 0xc0, 0x01, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
141 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
142 0x80, 0xff, 0xff, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
143 0x00, 0xc0, 0x01, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00,
144 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 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 hsplit_bits[] = {
148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
151 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
152 0x00, 0x41, 0x82, 0x00, 0x80, 0x41, 0x82, 0x01, 0xc0, 0x7f, 0xfe, 0x03,
153 0x80, 0x41, 0x82, 0x01, 0x00, 0x41, 0x82, 0x00, 0x00, 0x40, 0x02, 0x00,
154 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
155 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 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 hsplitm_bits[] = {
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
163 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe3, 0xc7, 0x00,
164 0x80, 0xe3, 0xc7, 0x01, 0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07,
165 0xc0, 0xff, 0xff, 0x03, 0x80, 0xe3, 0xc7, 0x01, 0x00, 0xe3, 0xc7, 0x00,
166 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
167 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 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 };
171static const uint8_t whatsthis_bits[] = {
172 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0xf0, 0x07, 0x00,
173 0x09, 0x18, 0x0e, 0x00, 0x11, 0x1c, 0x0e, 0x00, 0x21, 0x1c, 0x0e, 0x00,
174 0x41, 0x1c, 0x0e, 0x00, 0x81, 0x1c, 0x0e, 0x00, 0x01, 0x01, 0x07, 0x00,
175 0x01, 0x82, 0x03, 0x00, 0xc1, 0xc7, 0x01, 0x00, 0x49, 0xc0, 0x01, 0x00,
176 0x95, 0xc0, 0x01, 0x00, 0x93, 0xc0, 0x01, 0x00, 0x21, 0x01, 0x00, 0x00,
177 0x20, 0xc1, 0x01, 0x00, 0x40, 0xc2, 0x01, 0x00, 0x40, 0x02, 0x00, 0x00,
178 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
183static const uint8_t whatsthism_bits[] = {
184 0x01, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x07, 0x00, 0x07, 0xf8, 0x0f, 0x00,
185 0x0f, 0xfc, 0x1f, 0x00, 0x1f, 0x3e, 0x1f, 0x00, 0x3f, 0x3e, 0x1f, 0x00,
186 0x7f, 0x3e, 0x1f, 0x00, 0xff, 0x3e, 0x1f, 0x00, 0xff, 0x9d, 0x0f, 0x00,
187 0xff, 0xc3, 0x07, 0x00, 0xff, 0xe7, 0x03, 0x00, 0x7f, 0xe0, 0x03, 0x00,
188 0xf7, 0xe0, 0x03, 0x00, 0xf3, 0xe0, 0x03, 0x00, 0xe1, 0xe1, 0x03, 0x00,
189 0xe0, 0xe1, 0x03, 0x00, 0xc0, 0xe3, 0x03, 0x00, 0xc0, 0xe3, 0x03, 0x00,
190 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
191 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
195static const uint8_t busy_bits[] = {
196 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
197 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
198 0x41, 0xe0, 0xff, 0x00, 0x81, 0x20, 0x80, 0x00, 0x01, 0xe1, 0xff, 0x00,
199 0x01, 0x42, 0x40, 0x00, 0xc1, 0x47, 0x40, 0x00, 0x49, 0x40, 0x55, 0x00,
200 0x95, 0x80, 0x2a, 0x00, 0x93, 0x00, 0x15, 0x00, 0x21, 0x01, 0x0a, 0x00,
201 0x20, 0x01, 0x11, 0x00, 0x40, 0x82, 0x20, 0x00, 0x40, 0x42, 0x44, 0x00,
202 0x80, 0x41, 0x4a, 0x00, 0x00, 0x40, 0x55, 0x00, 0x00, 0xe0, 0xff, 0x00,
203 0x00, 0x20, 0x80, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
204 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
206 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
207static const uint8_t busym_bits[] = {
208 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
209 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
210 0x7f, 0xe0, 0xff, 0x00, 0xff, 0xe0, 0xff, 0x00, 0xff, 0xe1, 0xff, 0x00,
211 0xff, 0xc3, 0x7f, 0x00, 0xff, 0xc7, 0x7f, 0x00, 0x7f, 0xc0, 0x7f, 0x00,
212 0xf7, 0x80, 0x3f, 0x00, 0xf3, 0x00, 0x1f, 0x00, 0xe1, 0x01, 0x0e, 0x00,
213 0xe0, 0x01, 0x1f, 0x00, 0xc0, 0x83, 0x3f, 0x00, 0xc0, 0xc3, 0x7f, 0x00,
214 0x80, 0xc1, 0x7f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0xff, 0x00,
215 0x00, 0xe0, 0xff, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
219
220static const uint8_t * const cursor_bits32[] = {
221 vsplit_bits, vsplitm_bits, hsplit_bits, hsplitm_bits,
222 nullptr, nullptr, nullptr, nullptr, whatsthis_bits, whatsthism_bits, busy_bits, busym_bits
223};
224
225static const uint8_t forbidden_bits[] = {
226 0x00,0x00,0x00,0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xf0,0x00,0x38,0xc0,0x01,
227 0x7c,0x80,0x03,0xec,0x00,0x03,0xce,0x01,0x07,0x86,0x03,0x06,0x06,0x07,0x06,
228 0x06,0x0e,0x06,0x06,0x1c,0x06,0x0e,0x38,0x07,0x0c,0x70,0x03,0x1c,0xe0,0x03,
229 0x38,0xc0,0x01,0xf0,0xe0,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00,0x00,0x00,0x00 };
230
231static const uint8_t forbiddenm_bits[] = {
232 0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xff,0x00,0xf8,0xff,0x01,0xfc,0xf0,0x03,
233 0xfe,0xc0,0x07,0xfe,0x81,0x07,0xff,0x83,0x0f,0xcf,0x07,0x0f,0x8f,0x0f,0x0f,
234 0x0f,0x1f,0x0f,0x0f,0x3e,0x0f,0x1f,0xfc,0x0f,0x1e,0xf8,0x07,0x3e,0xf0,0x07,
235 0xfc,0xe0,0x03,0xf8,0xff,0x01,0xf0,0xff,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00};
236
237static const uint8_t openhand_bits[] = {
238 0x80,0x01,0x58,0x0e,0x64,0x12,0x64,0x52,0x48,0xb2,0x48,0x92,
239 0x16,0x90,0x19,0x80,0x11,0x40,0x02,0x40,0x04,0x40,0x04,0x20,
240 0x08,0x20,0x10,0x10,0x20,0x10,0x00,0x00};
241static const uint8_t openhandm_bits[] = {
242 0x80,0x01,0xd8,0x0f,0xfc,0x1f,0xfc,0x5f,0xf8,0xff,0xf8,0xff,
243 0xf6,0xff,0xff,0xff,0xff,0x7f,0xfe,0x7f,0xfc,0x7f,0xfc,0x3f,
244 0xf8,0x3f,0xf0,0x1f,0xe0,0x1f,0x00,0x00};
245static const uint8_t closedhand_bits[] = {
246 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0x48,0x32,0x08,0x50,
247 0x10,0x40,0x18,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10,
248 0x20,0x10,0x20,0x10,0x00,0x00,0x00,0x00};
249static const uint8_t closedhandm_bits[] = {
250 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0xf8,0x3f,0xf8,0x7f,
251 0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f,
252 0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00};
253
254static const uint8_t * const cursor_bits20[] = {
255 forbidden_bits, forbiddenm_bits
256};
257
258// ### FIXME This mapping is incomplete - QTBUG-71423
259static const std::vector<const char *> cursorNames[] = {
260 { "left_ptr", "default", "top_left_arrow", "left_arrow" },
261 { "up_arrow" },
262 { "cross" },
263 { "wait", "watch", "0426c94ea35c87780ff01dc239897213" },
264 { "ibeam", "text", "xterm" },
265 { "size_ver", "ns-resize", "v_double_arrow", "00008160000006810000408080010102" },
266 { "size_hor", "ew-resize", "h_double_arrow", "028006030e0e7ebffc7f7070c0600140" },
267 { "size_bdiag", "nesw-resize", "50585d75b494802d0151028115016902", "fcf1c3c7cd4491d801f1e1c78f100000" },
268 { "size_fdiag", "nwse-resize", "38c5dff7c7b8962045400281044508d2", "c7088f0f3e6c8088236ef8e1e3e70000" },
269 { "size_all" },
270 { "blank" },
271 { "split_v", "row-resize", "sb_v_double_arrow", "2870a09082c103050810ffdffffe0204", "c07385c7190e701020ff7ffffd08103c" },
272 { "split_h", "col-resize", "sb_h_double_arrow", "043a9f68147c53184671403ffa811cc5", "14fef782d02440884392942c11205230" },
273 { "pointing_hand", "pointer", "hand1", "e29285e634086352946a0e7090d73106" },
274 { "forbidden", "not-allowed", "crossed_circle", "circle", "03b6e0fcb3499374a867c041f52298f0" },
275 { "whats_this", "help", "question_arrow", "5c6cd98b3f3ebcb1f9c7f1c204630408", "d9ce0ab605698f320427677b458ad60b" },
276 { "left_ptr_watch", "half-busy", "progress", "00000000000000020006000e7e9ffc3f", "08e8e1c95fe2fc01f976f1e063a24ccd" },
277 { "openhand", "grab", "fleur", "5aca4d189052212118709018842178c0", "9d800788f1b08800ae810202380a0822" },
278 { "closedhand", "grabbing", "208530c400c041818281048008011002" },
279 { "dnd-copy", "copy" },
280 { "dnd-move", "move" },
281 { "dnd-link", "link" }
282};
283
284QXcbCursorCacheKey::QXcbCursorCacheKey(const QCursor &c)
285 : shape(c.shape()), bitmapCacheKey(0), maskCacheKey(0)
286{
287 if (shape == Qt::BitmapCursor) {
288 const qint64 pixmapCacheKey = c.pixmap().cacheKey();
289 if (pixmapCacheKey) {
290 bitmapCacheKey = pixmapCacheKey;
291 } else {
292 Q_ASSERT(!c.bitmap(Qt::ReturnByValue).isNull());
293 Q_ASSERT(!c.mask(Qt::ReturnByValue).isNull());
294 bitmapCacheKey = c.bitmap(Qt::ReturnByValue).cacheKey();
295 maskCacheKey = c.mask(Qt::ReturnByValue).cacheKey();
296 }
297 }
298}
299
300#endif // !QT_NO_CURSOR
301
302QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen)
303 : QXcbObject(conn), m_screen(screen), m_gtkCursorThemeInitialized(false)
304{
305#if QT_CONFIG(cursor)
306 // see NUM_BITMAPS in libXcursor/src/xcursorint.h
307 m_bitmapCache.setMaxCost(8);
308#endif
309
310 if (cursorCount++)
311 return;
312
313 cursorFont = xcb_generate_id(c: xcb_connection());
314 const char *cursorStr = "cursor";
315 xcb_open_font(c: xcb_connection(), fid: cursorFont, name_len: strlen(s: cursorStr), name: cursorStr);
316
317#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
318 static bool function_ptrs_not_initialized = true;
319 if (function_ptrs_not_initialized) {
320 QLibrary xcursorLib(QLatin1String("Xcursor"), 1);
321 bool xcursorFound = xcursorLib.load();
322 if (!xcursorFound) { // try without the version number
323 xcursorLib.setFileName(QLatin1String("Xcursor"));
324 xcursorFound = xcursorLib.load();
325 }
326 if (xcursorFound) {
327 ptrXcursorLibraryLoadCursor =
328 (PtrXcursorLibraryLoadCursor) xcursorLib.resolve(symbol: "XcursorLibraryLoadCursor");
329 ptrXcursorLibraryGetTheme =
330 (PtrXcursorLibraryGetTheme) xcursorLib.resolve(symbol: "XcursorGetTheme");
331 ptrXcursorLibrarySetTheme =
332 (PtrXcursorLibrarySetTheme) xcursorLib.resolve(symbol: "XcursorSetTheme");
333 ptrXcursorLibraryGetDefaultSize =
334 (PtrXcursorLibraryGetDefaultSize) xcursorLib.resolve(symbol: "XcursorGetDefaultSize");
335 }
336 function_ptrs_not_initialized = false;
337 }
338
339#endif
340}
341
342QXcbCursor::~QXcbCursor()
343{
344 xcb_connection_t *conn = xcb_connection();
345
346 if (m_gtkCursorThemeInitialized) {
347 m_screen->xSettings()->removeCallbackForHandle(handle: this);
348 }
349
350 if (!--cursorCount)
351 xcb_close_font(c: conn, font: cursorFont);
352
353#ifndef QT_NO_CURSOR
354 for (xcb_cursor_t cursor : qAsConst(t&: m_cursorHash))
355 xcb_free_cursor(c: conn, cursor);
356#endif
357}
358
359#ifndef QT_NO_CURSOR
360void QXcbCursor::changeCursor(QCursor *cursor, QWindow *window)
361{
362 if (!window || !window->handle())
363 return;
364
365 xcb_cursor_t c = XCB_CURSOR_NONE;
366 if (cursor) {
367 const QXcbCursorCacheKey key(*cursor);
368 const Qt::CursorShape shape = cursor->shape();
369
370 if (shape == Qt::BitmapCursor) {
371 auto *bitmap = m_bitmapCache.object(key);
372 if (bitmap) {
373 c = bitmap->cursor;
374 } else {
375 c = createBitmapCursor(cursor);
376 m_bitmapCache.insert(akey: key, aobject: new CachedCursor(xcb_connection(), c));
377 }
378 } else {
379 auto it = m_cursorHash.find(akey: key);
380 if (it == m_cursorHash.end()) {
381 c = createFontCursor(cshape: shape);
382 m_cursorHash.insert(akey: key, avalue: c);
383 } else {
384 c = it.value();
385 }
386 }
387 }
388
389 auto *w = static_cast<QXcbWindow *>(window->handle());
390 xcb_change_window_attributes(c: xcb_connection(), window: w->xcb_window(), value_mask: XCB_CW_CURSOR, value_list: &c);
391 xcb_flush(c: xcb_connection());
392}
393
394static int cursorIdForShape(int cshape)
395{
396 int cursorId = 0;
397 switch (cshape) {
398 case Qt::ArrowCursor:
399 cursorId = XC_left_ptr;
400 break;
401 case Qt::UpArrowCursor:
402 cursorId = XC_center_ptr;
403 break;
404 case Qt::CrossCursor:
405 cursorId = XC_crosshair;
406 break;
407 case Qt::WaitCursor:
408 cursorId = XC_watch;
409 break;
410 case Qt::IBeamCursor:
411 cursorId = XC_xterm;
412 break;
413 case Qt::SizeAllCursor:
414 cursorId = XC_fleur;
415 break;
416 case Qt::PointingHandCursor:
417 cursorId = XC_hand2;
418 break;
419 case Qt::SizeBDiagCursor:
420 cursorId = XC_top_right_corner;
421 break;
422 case Qt::SizeFDiagCursor:
423 cursorId = XC_bottom_right_corner;
424 break;
425 case Qt::SizeVerCursor:
426 case Qt::SplitVCursor:
427 cursorId = XC_sb_v_double_arrow;
428 break;
429 case Qt::SizeHorCursor:
430 case Qt::SplitHCursor:
431 cursorId = XC_sb_h_double_arrow;
432 break;
433 case Qt::WhatsThisCursor:
434 cursorId = XC_question_arrow;
435 break;
436 case Qt::ForbiddenCursor:
437 cursorId = XC_circle;
438 break;
439 case Qt::BusyCursor:
440 cursorId = XC_watch;
441 break;
442 default:
443 break;
444 }
445 return cursorId;
446}
447
448xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape)
449{
450 xcb_cursor_t cursor = 0;
451 xcb_connection_t *conn = xcb_connection();
452
453 if (cshape == Qt::BlankCursor) {
454 xcb_pixmap_t cp = xcb_create_pixmap_from_bitmap_data(display: conn, d: m_screen->root(), data: cur_blank_bits, width: 16, height: 16,
455 depth: 1, fg: 0, bg: 0, gcp: nullptr);
456 xcb_pixmap_t mp = xcb_create_pixmap_from_bitmap_data(display: conn, d: m_screen->root(), data: cur_blank_bits, width: 16, height: 16,
457 depth: 1, fg: 0, bg: 0, gcp: nullptr);
458 cursor = xcb_generate_id(c: conn);
459 xcb_create_cursor(c: conn, cid: cursor, source: cp, mask: mp, fore_red: 0, fore_green: 0, fore_blue: 0, back_red: 0xFFFF, back_green: 0xFFFF, back_blue: 0xFFFF, x: 8, y: 8);
460 } else if (cshape >= Qt::SizeVerCursor && cshape < Qt::SizeAllCursor) {
461 int i = (cshape - Qt::SizeVerCursor) * 2;
462 xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(display: conn, d: m_screen->root(),
463 data: const_cast<uint8_t*>(cursor_bits16[i]),
464 width: 16, height: 16, depth: 1, fg: 0, bg: 0, gcp: nullptr);
465 xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(display: conn, d: m_screen->root(),
466 data: const_cast<uint8_t*>(cursor_bits16[i + 1]),
467 width: 16, height: 16, depth: 1, fg: 0, bg: 0, gcp: nullptr);
468 cursor = xcb_generate_id(c: conn);
469 xcb_create_cursor(c: conn, cid: cursor, source: pm, mask: pmm, fore_red: 0, fore_green: 0, fore_blue: 0, back_red: 0xFFFF, back_green: 0xFFFF, back_blue: 0xFFFF, x: 8, y: 8);
470 } else if ((cshape >= Qt::SplitVCursor && cshape <= Qt::SplitHCursor)
471 || cshape == Qt::WhatsThisCursor || cshape == Qt::BusyCursor) {
472 int i = (cshape - Qt::SplitVCursor) * 2;
473 xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(display: conn, d: m_screen->root(),
474 data: const_cast<uint8_t*>(cursor_bits32[i]),
475 width: 32, height: 32, depth: 1, fg: 0, bg: 0, gcp: nullptr);
476 xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(display: conn, d: m_screen->root(),
477 data: const_cast<uint8_t*>(cursor_bits32[i + 1]),
478 width: 32, height: 32, depth: 1, fg: 0, bg: 0, gcp: nullptr);
479 int hs = (cshape == Qt::PointingHandCursor || cshape == Qt::WhatsThisCursor
480 || cshape == Qt::BusyCursor) ? 0 : 16;
481 cursor = xcb_generate_id(c: conn);
482 xcb_create_cursor(c: conn, cid: cursor, source: pm, mask: pmm, fore_red: 0, fore_green: 0, fore_blue: 0, back_red: 0xFFFF, back_green: 0xFFFF, back_blue: 0xFFFF, x: hs, y: hs);
483 } else if (cshape == Qt::ForbiddenCursor) {
484 int i = (cshape - Qt::ForbiddenCursor) * 2;
485 xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(display: conn, d: m_screen->root(),
486 data: const_cast<uint8_t*>(cursor_bits20[i]),
487 width: 20, height: 20, depth: 1, fg: 0, bg: 0, gcp: nullptr);
488 xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(display: conn, d: m_screen->root(),
489 data: const_cast<uint8_t*>(cursor_bits20[i + 1]),
490 width: 20, height: 20, depth: 1, fg: 0, bg: 0, gcp: nullptr);
491 cursor = xcb_generate_id(c: conn);
492 xcb_create_cursor(c: conn, cid: cursor, source: pm, mask: pmm, fore_red: 0, fore_green: 0, fore_blue: 0, back_red: 0xFFFF, back_green: 0xFFFF, back_blue: 0xFFFF, x: 10, y: 10);
493 } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) {
494 bool open = cshape == Qt::OpenHandCursor;
495 xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(display: conn, d: m_screen->root(),
496 data: const_cast<uint8_t*>(open ? openhand_bits : closedhand_bits),
497 width: 16, height: 16, depth: 1, fg: 0, bg: 0, gcp: nullptr);
498 xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(display: conn, d: m_screen->root(),
499 data: const_cast<uint8_t*>(open ? openhandm_bits : closedhandm_bits),
500 width: 16, height: 16, depth: 1, fg: 0, bg: 0, gcp: nullptr);
501 cursor = xcb_generate_id(c: conn);
502 xcb_create_cursor(c: conn, cid: cursor, source: pm, mask: pmm, fore_red: 0, fore_green: 0, fore_blue: 0, back_red: 0xFFFF, back_green: 0xFFFF, back_blue: 0xFFFF, x: 8, y: 8);
503 } else if (cshape == Qt::DragCopyCursor || cshape == Qt::DragMoveCursor
504 || cshape == Qt::DragLinkCursor) {
505 QImage image = QGuiApplicationPrivate::instance()->getPixmapCursor(cshape: static_cast<Qt::CursorShape>(cshape)).toImage();
506 if (!image.isNull()) {
507 xcb_pixmap_t pm = qt_xcb_XPixmapFromBitmap(screen: m_screen, image);
508 xcb_pixmap_t pmm = qt_xcb_XPixmapFromBitmap(screen: m_screen, image: image.createAlphaMask());
509 cursor = xcb_generate_id(c: conn);
510 xcb_create_cursor(c: conn, cid: cursor, source: pm, mask: pmm, fore_red: 0, fore_green: 0, fore_blue: 0, back_red: 0xFFFF, back_green: 0xFFFF, back_blue: 0xFFFF, x: 8, y: 8);
511 xcb_free_pixmap(c: conn, pixmap: pm);
512 xcb_free_pixmap(c: conn, pixmap: pmm);
513 }
514 }
515
516 return cursor;
517}
518
519#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
520bool updateCursorTheme(void *dpy, const QByteArray &theme) {
521 if (!ptrXcursorLibraryGetTheme
522 || !ptrXcursorLibrarySetTheme)
523 return false;
524 QByteArray oldTheme = ptrXcursorLibraryGetTheme(dpy);
525 if (oldTheme == theme)
526 return false;
527
528 int setTheme = ptrXcursorLibrarySetTheme(dpy,theme.constData());
529 return setTheme;
530}
531
532 void QXcbCursor::cursorThemePropertyChanged(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &property, void *handle)
533{
534 Q_UNUSED(screen);
535 Q_UNUSED(name);
536 QXcbCursor *self = static_cast<QXcbCursor *>(handle);
537 self->m_cursorHash.clear();
538
539 updateCursorTheme(dpy: self->connection()->xlib_display(),theme: property.toByteArray());
540}
541
542static xcb_cursor_t loadCursor(void *dpy, int cshape)
543{
544 xcb_cursor_t cursor = XCB_NONE;
545 if (!ptrXcursorLibraryLoadCursor || !dpy)
546 return cursor;
547
548 for (const char *cursorName: cursorNames[cshape]) {
549 cursor = ptrXcursorLibraryLoadCursor(dpy, cursorName);
550 if (cursor != XCB_NONE)
551 break;
552 }
553
554 return cursor;
555}
556#endif // QT_CONFIG(xcb_xlib) / QT_CONFIG(library)
557
558xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
559{
560 xcb_connection_t *conn = xcb_connection();
561 int cursorId = cursorIdForShape(cshape);
562 xcb_cursor_t cursor = XCB_NONE;
563
564#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
565 if (m_screen->xSettings()->initialized())
566 m_screen->xSettings()->registerCallbackForProperty(property: "Gtk/CursorThemeName",func: cursorThemePropertyChanged,handle: this);
567
568 // Try Xcursor first
569 if (cshape >= 0 && cshape <= Qt::LastCursor) {
570 void *dpy = connection()->xlib_display();
571 cursor = loadCursor(dpy, cshape);
572 if (!cursor && !m_gtkCursorThemeInitialized && m_screen->xSettings()->initialized()) {
573 QByteArray gtkCursorTheme = m_screen->xSettings()->setting("Gtk/CursorThemeName").toByteArray();
574 if (updateCursorTheme(dpy,theme: gtkCursorTheme)) {
575 cursor = loadCursor(dpy, cshape);
576 }
577 m_gtkCursorThemeInitialized = true;
578 }
579 }
580 if (cursor)
581 return cursor;
582 if (!cursor && cursorId) {
583 cursor = XCreateFontCursor(static_cast<Display *>(connection()->xlib_display()), cursorId);
584 if (cursor)
585 return cursor;
586 }
587
588#endif
589
590 // Non-standard X11 cursors are created from bitmaps
591 cursor = createNonStandardCursor(cshape);
592
593 // Create a glpyh cursor if everything else failed
594 if (!cursor && cursorId) {
595 cursor = xcb_generate_id(c: conn);
596 xcb_create_glyph_cursor(c: conn, cid: cursor, source_font: cursorFont, mask_font: cursorFont,
597 source_char: cursorId, mask_char: cursorId + 1,
598 fore_red: 0xFFFF, fore_green: 0xFFFF, fore_blue: 0xFFFF, back_red: 0, back_green: 0, back_blue: 0);
599 }
600
601 if (cursor && cshape >= 0 && cshape < Qt::LastCursor && connection()->hasXFixes()) {
602 const char *name = cursorNames[cshape].front();
603 xcb_xfixes_set_cursor_name(c: conn, cursor, nbytes: strlen(s: name), name);
604 }
605
606 return cursor;
607}
608
609xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor)
610{
611 QPoint spot = cursor->hotSpot();
612 xcb_cursor_t c = XCB_NONE;
613 if (cursor->pixmap().depth() > 1) {
614 if (connection()->hasXRender(major: 0, minor: 5))
615 c = qt_xcb_createCursorXRender(screen: m_screen, image: cursor->pixmap().toImage(), spot);
616 else
617 qCWarning(lcQpaXcb, "xrender >= 0.5 required to create pixmap cursors");
618 } else {
619 xcb_connection_t *conn = xcb_connection();
620 xcb_pixmap_t cp = qt_xcb_XPixmapFromBitmap(screen: m_screen, image: cursor->bitmap(Qt::ReturnByValue).toImage());
621 xcb_pixmap_t mp = qt_xcb_XPixmapFromBitmap(screen: m_screen, image: cursor->mask(Qt::ReturnByValue).toImage());
622 c = xcb_generate_id(c: conn);
623 xcb_create_cursor(c: conn, cid: c, source: cp, mask: mp, fore_red: 0, fore_green: 0, fore_blue: 0, back_red: 0xFFFF, back_green: 0xFFFF, back_blue: 0xFFFF,
624 x: spot.x(), y: spot.y());
625 xcb_free_pixmap(c: conn, pixmap: cp);
626 xcb_free_pixmap(c: conn, pixmap: mp);
627 }
628 return c;
629}
630#endif
631
632/*! \internal
633
634 Note that the logical state of a device (as seen by means of the protocol) may
635 lag the physical state if device event processing is frozen. See QueryPointer
636 in X11 protocol specification.
637*/
638void QXcbCursor::queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask)
639{
640 if (pos)
641 *pos = QPoint();
642
643 xcb_window_t root = c->primaryVirtualDesktop()->root();
644
645 auto reply = Q_XCB_REPLY(xcb_query_pointer, c->xcb_connection(), root);
646 if (reply) {
647 if (virtualDesktop) {
648 const auto virtualDesktops = c->virtualDesktops();
649 for (QXcbVirtualDesktop *vd : virtualDesktops) {
650 if (vd->root() == reply->root) {
651 *virtualDesktop = vd;
652 break;
653 }
654 }
655 }
656 if (pos)
657 *pos = QPoint(reply->root_x, reply->root_y);
658 if (keybMask)
659 *keybMask = reply->mask;
660 return;
661 }
662}
663
664QPoint QXcbCursor::pos() const
665{
666 QPoint p;
667 queryPointer(c: connection(), virtualDesktop: nullptr, pos: &p);
668 return p;
669}
670
671void QXcbCursor::setPos(const QPoint &pos)
672{
673 QXcbVirtualDesktop *virtualDesktop = nullptr;
674 queryPointer(c: connection(), virtualDesktop: &virtualDesktop, pos: nullptr);
675 if (virtualDesktop)
676 xcb_warp_pointer(c: xcb_connection(), XCB_NONE, dst_window: virtualDesktop->root(), src_x: 0, src_y: 0, src_width: 0, src_height: 0, dst_x: pos.x(), dst_y: pos.y());
677 xcb_flush(c: xcb_connection());
678}
679
680QT_END_NAMESPACE
681

source code of qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp