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 
56 QT_BEGIN_NAMESPACE
57 
58 typedef int (*PtrXcursorLibraryLoadCursor)(void *, const char *);
59 typedef char *(*PtrXcursorLibraryGetTheme)(void *);
60 typedef int (*PtrXcursorLibrarySetTheme)(void *, const char *);
61 typedef int (*PtrXcursorLibraryGetDefaultSize)(void *);
62 
63 #if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
64 #include <X11/Xlib.h>
65 enum {
66     XCursorShape = CursorShape
67 };
68 #undef CursorShape
69 
70 static PtrXcursorLibraryLoadCursor ptrXcursorLibraryLoadCursor = nullptr;
71 static PtrXcursorLibraryGetTheme ptrXcursorLibraryGetTheme = nullptr;
72 static PtrXcursorLibrarySetTheme ptrXcursorLibrarySetTheme = nullptr;
73 static PtrXcursorLibraryGetDefaultSize ptrXcursorLibraryGetDefaultSize = nullptr;
74 #endif
75 
76 static xcb_font_t cursorFont = 0;
77 static int cursorCount = 0;
78 
79 #ifndef QT_NO_CURSOR
80 
81 static 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 
86 static 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 };
90 static 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 };
94 static 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 };
98 static 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 };
102 static 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 };
106 static 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 };
110 static 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 };
114 static 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 };
118 static 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 
123 static 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 };
135 static 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 };
147 static 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 };
159 static 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 };
171 static 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, };
183 static 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, };
195 static 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};
207 static 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 
220 static 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 
225 static 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 
231 static 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 
237 static 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};
241 static 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};
245 static 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};
249 static 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 
254 static const uint8_t * const cursor_bits20[] = {
255     forbidden_bits, forbiddenm_bits
256 };
257 
258 // ### FIXME This mapping is incomplete - QTBUG-71423
259 static 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 
QXcbCursorCacheKey(const QCursor & c)284 QXcbCursorCacheKey::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 
QXcbCursor(QXcbConnection * conn,QXcbScreen * screen)302 QXcbCursor::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(xcb_connection());
314     const char *cursorStr = "cursor";
315     xcb_open_font(xcb_connection(), cursorFont, strlen(cursorStr), 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("XcursorLibraryLoadCursor");
329             ptrXcursorLibraryGetTheme =
330                     (PtrXcursorLibraryGetTheme) xcursorLib.resolve("XcursorGetTheme");
331             ptrXcursorLibrarySetTheme =
332                     (PtrXcursorLibrarySetTheme) xcursorLib.resolve("XcursorSetTheme");
333             ptrXcursorLibraryGetDefaultSize =
334                     (PtrXcursorLibraryGetDefaultSize) xcursorLib.resolve("XcursorGetDefaultSize");
335         }
336         function_ptrs_not_initialized = false;
337     }
338 
339 #endif
340 }
341 
~QXcbCursor()342 QXcbCursor::~QXcbCursor()
343 {
344     xcb_connection_t *conn = xcb_connection();
345 
346     if (m_gtkCursorThemeInitialized) {
347         m_screen->xSettings()->removeCallbackForHandle(this);
348     }
349 
350     if (!--cursorCount)
351         xcb_close_font(conn, cursorFont);
352 
353 #ifndef QT_NO_CURSOR
354     for (xcb_cursor_t cursor : qAsConst(m_cursorHash))
355         xcb_free_cursor(conn, cursor);
356 #endif
357 }
358 
359 #ifndef QT_NO_CURSOR
changeCursor(QCursor * cursor,QWindow * window)360 void 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(key, new CachedCursor(xcb_connection(), c));
377             }
378         } else {
379             auto it = m_cursorHash.find(key);
380             if (it == m_cursorHash.end()) {
381                 c = createFontCursor(shape);
382                 m_cursorHash.insert(key, c);
383             } else {
384                 c = it.value();
385             }
386         }
387     }
388 
389     auto *w = static_cast<QXcbWindow *>(window->handle());
390     xcb_change_window_attributes(xcb_connection(), w->xcb_window(), XCB_CW_CURSOR, &c);
391     xcb_flush(xcb_connection());
392 }
393 
cursorIdForShape(int cshape)394 static 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 
createNonStandardCursor(int cshape)448 xcb_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(conn, m_screen->root(), cur_blank_bits, 16, 16,
455                                                              1, 0, 0, nullptr);
456         xcb_pixmap_t mp = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), cur_blank_bits, 16, 16,
457                                                              1, 0, 0, nullptr);
458         cursor = xcb_generate_id(conn);
459         xcb_create_cursor(conn, cursor, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 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(conn, m_screen->root(),
463                                                              const_cast<uint8_t*>(cursor_bits16[i]),
464                                                              16, 16, 1, 0, 0, nullptr);
465         xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
466                                                               const_cast<uint8_t*>(cursor_bits16[i + 1]),
467                                                               16, 16, 1, 0, 0, nullptr);
468         cursor = xcb_generate_id(conn);
469         xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 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(conn, m_screen->root(),
474                                                              const_cast<uint8_t*>(cursor_bits32[i]),
475                                                              32, 32, 1, 0, 0, nullptr);
476         xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
477                                                               const_cast<uint8_t*>(cursor_bits32[i + 1]),
478                                                               32, 32, 1, 0, 0, nullptr);
479         int hs = (cshape == Qt::PointingHandCursor || cshape == Qt::WhatsThisCursor
480                   || cshape == Qt::BusyCursor) ? 0 : 16;
481         cursor = xcb_generate_id(conn);
482         xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, hs, 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(conn, m_screen->root(),
486                                                              const_cast<uint8_t*>(cursor_bits20[i]),
487                                                              20, 20, 1, 0, 0, nullptr);
488         xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
489                                                               const_cast<uint8_t*>(cursor_bits20[i + 1]),
490                                                               20, 20, 1, 0, 0, nullptr);
491         cursor = xcb_generate_id(conn);
492         xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 10, 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(conn, m_screen->root(),
496                                                              const_cast<uint8_t*>(open ? openhand_bits : closedhand_bits),
497                                                              16, 16, 1, 0, 0, nullptr);
498         xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(),
499                                                              const_cast<uint8_t*>(open ? openhandm_bits : closedhandm_bits),
500                                                              16, 16, 1, 0, 0, nullptr);
501         cursor = xcb_generate_id(conn);
502         xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8);
503     } else if (cshape == Qt::DragCopyCursor || cshape == Qt::DragMoveCursor
504                || cshape == Qt::DragLinkCursor) {
505         QImage image = QGuiApplicationPrivate::instance()->getPixmapCursor(static_cast<Qt::CursorShape>(cshape)).toImage();
506         if (!image.isNull()) {
507             xcb_pixmap_t pm = qt_xcb_XPixmapFromBitmap(m_screen, image);
508             xcb_pixmap_t pmm = qt_xcb_XPixmapFromBitmap(m_screen, image.createAlphaMask());
509             cursor = xcb_generate_id(conn);
510             xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8);
511             xcb_free_pixmap(conn, pm);
512             xcb_free_pixmap(conn, pmm);
513         }
514     }
515 
516     return cursor;
517 }
518 
519 #if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
updateCursorTheme(void * dpy,const QByteArray & theme)520 bool 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 
cursorThemePropertyChanged(QXcbVirtualDesktop * screen,const QByteArray & name,const QVariant & property,void * handle)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     updateCursorTheme(self->connection()->xlib_display(),property.toByteArray());
538 }
539 
loadCursor(void * dpy,int cshape)540 static xcb_cursor_t loadCursor(void *dpy, int cshape)
541 {
542     xcb_cursor_t cursor = XCB_NONE;
543     if (!ptrXcursorLibraryLoadCursor || !dpy)
544         return cursor;
545 
546     for (const char *cursorName: cursorNames[cshape]) {
547         cursor = ptrXcursorLibraryLoadCursor(dpy, cursorName);
548         if (cursor != XCB_NONE)
549             break;
550     }
551 
552     return cursor;
553 }
554 #endif // QT_CONFIG(xcb_xlib) / QT_CONFIG(library)
555 
createFontCursor(int cshape)556 xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
557 {
558     xcb_connection_t *conn = xcb_connection();
559     int cursorId = cursorIdForShape(cshape);
560     xcb_cursor_t cursor = XCB_NONE;
561 
562     // Try Xcursor first
563 #if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
564     if (cshape >= 0 && cshape <= Qt::LastCursor) {
565         void *dpy = connection()->xlib_display();
566         cursor = loadCursor(dpy, cshape);
567         if (!cursor && !m_gtkCursorThemeInitialized && m_screen->xSettings()->initialized()) {
568             QByteArray gtkCursorTheme = m_screen->xSettings()->setting("Gtk/CursorThemeName").toByteArray();
569             m_screen->xSettings()->registerCallbackForProperty("Gtk/CursorThemeName",cursorThemePropertyChanged,this);
570             if (updateCursorTheme(dpy,gtkCursorTheme)) {
571                 cursor = loadCursor(dpy, cshape);
572             }
573             m_gtkCursorThemeInitialized = true;
574         }
575     }
576     if (cursor)
577         return cursor;
578     if (!cursor && cursorId) {
579         cursor = XCreateFontCursor(static_cast<Display *>(connection()->xlib_display()), cursorId);
580         if (cursor)
581             return cursor;
582     }
583 
584 #endif
585 
586     // Non-standard X11 cursors are created from bitmaps
587     cursor = createNonStandardCursor(cshape);
588 
589     // Create a glpyh cursor if everything else failed
590     if (!cursor && cursorId) {
591         cursor = xcb_generate_id(conn);
592         xcb_create_glyph_cursor(conn, cursor, cursorFont, cursorFont,
593                                 cursorId, cursorId + 1,
594                                 0xFFFF, 0xFFFF, 0xFFFF, 0, 0, 0);
595     }
596 
597     if (cursor && cshape >= 0 && cshape < Qt::LastCursor && connection()->hasXFixes()) {
598         const char *name = cursorNames[cshape].front();
599         xcb_xfixes_set_cursor_name(conn, cursor, strlen(name), name);
600     }
601 
602     return cursor;
603 }
604 
createBitmapCursor(QCursor * cursor)605 xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor)
606 {
607     QPoint spot = cursor->hotSpot();
608     xcb_cursor_t c = XCB_NONE;
609     if (cursor->pixmap().depth() > 1) {
610         if (connection()->hasXRender(0, 5))
611             c = qt_xcb_createCursorXRender(m_screen, cursor->pixmap().toImage(), spot);
612         else
613             qCWarning(lcQpaXcb, "xrender >= 0.5 required to create pixmap cursors");
614     } else {
615         xcb_connection_t *conn = xcb_connection();
616         xcb_pixmap_t cp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->bitmap(Qt::ReturnByValue).toImage());
617         xcb_pixmap_t mp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->mask(Qt::ReturnByValue).toImage());
618         c = xcb_generate_id(conn);
619         xcb_create_cursor(conn, c, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF,
620                           spot.x(), spot.y());
621         xcb_free_pixmap(conn, cp);
622         xcb_free_pixmap(conn, mp);
623     }
624     return c;
625 }
626 #endif
627 
628 /*! \internal
629 
630     Note that the logical state of a device (as seen by means of the protocol) may
631     lag the physical state if device event processing is frozen. See QueryPointer
632     in X11 protocol specification.
633 */
queryPointer(QXcbConnection * c,QXcbVirtualDesktop ** virtualDesktop,QPoint * pos,int * keybMask)634 void QXcbCursor::queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask)
635 {
636     if (pos)
637         *pos = QPoint();
638 
639     xcb_window_t root = c->primaryVirtualDesktop()->root();
640 
641     auto reply = Q_XCB_REPLY(xcb_query_pointer, c->xcb_connection(), root);
642     if (reply) {
643         if (virtualDesktop) {
644             const auto virtualDesktops = c->virtualDesktops();
645             for (QXcbVirtualDesktop *vd : virtualDesktops) {
646                 if (vd->root() == reply->root) {
647                     *virtualDesktop = vd;
648                     break;
649                 }
650             }
651         }
652         if (pos)
653             *pos = QPoint(reply->root_x, reply->root_y);
654         if (keybMask)
655             *keybMask = reply->mask;
656         return;
657     }
658 }
659 
pos() const660 QPoint QXcbCursor::pos() const
661 {
662     QPoint p;
663     queryPointer(connection(), nullptr, &p);
664     return p;
665 }
666 
setPos(const QPoint & pos)667 void QXcbCursor::setPos(const QPoint &pos)
668 {
669     QXcbVirtualDesktop *virtualDesktop = nullptr;
670     queryPointer(connection(), &virtualDesktop, nullptr);
671     xcb_warp_pointer(xcb_connection(), XCB_NONE, virtualDesktop->root(), 0, 0, 0, 0, pos.x(), pos.y());
672     xcb_flush(xcb_connection());
673 }
674 
675 QT_END_NAMESPACE
676