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 = 0;
71static PtrXcursorLibraryGetTheme ptrXcursorLibraryGetTheme = 0;
72static PtrXcursorLibrarySetTheme ptrXcursorLibrarySetTheme = 0;
73static PtrXcursorLibraryGetDefaultSize ptrXcursorLibraryGetDefaultSize = 0;
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 0, 0, 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 0, 0, 0, 0, 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());
293 Q_ASSERT(c.mask());
294 bitmapCacheKey = c.bitmap()->cacheKey();
295 maskCacheKey = c.mask()->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(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
342QXcbCursor::~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
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(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
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(conn, m_screen->root(), cur_blank_bits, 16, 16,
455 1, 0, 0, 0);
456 xcb_pixmap_t mp = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), cur_blank_bits, 16, 16,
457 1, 0, 0, 0);
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, 0);
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, 0);
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, 0);
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, 0);
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, 0);
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, 0);
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, 0);
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, 0);
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)
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 updateCursorTheme(self->connection()->xlib_display(),property.toByteArray());
538}
539
540static 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
556xcb_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
605xcb_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()->toImage());
617 xcb_pixmap_t mp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->mask()->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*/
634void 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
660QPoint QXcbCursor::pos() const
661{
662 QPoint p;
663 queryPointer(connection(), 0, &p);
664 return p;
665}
666
667void QXcbCursor::setPos(const QPoint &pos)
668{
669 QXcbVirtualDesktop *virtualDesktop = nullptr;
670 queryPointer(connection(), &virtualDesktop, 0);
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
675QT_END_NAMESPACE
676