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 | |
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 | |
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(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 | |
342 | QXcbCursor::~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 |
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(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 | |
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 | |
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(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) |
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 | |
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 | |
542 | static 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 | |
558 | xcb_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 | |
609 | xcb_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 | */ |
638 | void 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 | |
664 | QPoint QXcbCursor::pos() const |
665 | { |
666 | QPoint p; |
667 | queryPointer(c: connection(), virtualDesktop: nullptr, pos: &p); |
668 | return p; |
669 | } |
670 | |
671 | void 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 | |
680 | QT_END_NAMESPACE |
681 | |