Line data Source code
1 : /**
2 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #include "XLPlatformLinuxWayland.h"
24 : #include "XLPlatformLinuxDbus.h"
25 : #include "SPPlatformUnistd.h"
26 :
27 : #include <sys/mman.h>
28 : #include <dlfcn.h>
29 : #include <poll.h>
30 : #include <fcntl.h>
31 : #include <linux/input.h>
32 :
33 : #ifndef XL_WAYLAND_LOG
34 : #if XL_WAYLAND_DEBUG
35 : #define XL_WAYLAND_LOG(...) log::debug("Wayland", __VA_ARGS__)
36 : #else
37 : #define XL_WAYLAND_LOG(...)
38 : #endif
39 : #endif
40 :
41 : #if XL_LINK
42 : extern "C" {
43 :
44 : extern const struct wl_interface wl_registry_interface;
45 : extern const struct wl_interface wl_compositor_interface;
46 : extern const struct wl_interface wl_output_interface;
47 : extern const struct wl_interface wl_seat_interface;
48 : extern const struct wl_interface wl_surface_interface;
49 : extern const struct wl_interface wl_region_interface;
50 : extern const struct wl_interface wl_callback_interface;
51 : extern const struct wl_interface wl_pointer_interface;
52 : extern const struct wl_interface wl_keyboard_interface;
53 : extern const struct wl_interface wl_touch_interface;
54 : extern const struct wl_interface wl_shm_interface;
55 : extern const struct wl_interface wl_subcompositor_interface;
56 : extern const struct wl_interface wl_subsurface_interface;
57 : extern const struct wl_interface wl_shm_pool_interface;
58 : extern const struct wl_interface wl_buffer_interface;
59 :
60 : extern const struct wl_interface wp_viewporter_interface;
61 : extern const struct wl_interface wp_viewport_interface;
62 :
63 : extern const struct wl_interface xdg_wm_base_interface;
64 : extern const struct wl_interface xdg_positioner_interface;
65 : extern const struct wl_interface xdg_surface_interface;
66 : extern const struct wl_interface xdg_toplevel_interface;
67 : extern const struct wl_interface xdg_popup_interface;
68 :
69 : struct wl_display * wl_display_connect(const char *name);
70 : int wl_display_get_fd (struct wl_display *display);
71 : int wl_display_dispatch (struct wl_display *display);
72 : int wl_display_dispatch_pending (struct wl_display *display);
73 : int wl_display_prepare_read (struct wl_display *display);
74 : int wl_display_flush (struct wl_display *display);
75 : int wl_display_read_events (struct wl_display *display);
76 : void wl_display_disconnect (struct wl_display *display);
77 :
78 : struct wl_proxy* wl_proxy_marshal_flags (struct wl_proxy *proxy, uint32_t opcode,
79 : const struct wl_interface *interface, uint32_t version, uint32_t flags, ...);
80 : uint32_t wl_proxy_get_version (struct wl_proxy *proxy);
81 : int wl_proxy_add_listener (struct wl_proxy *proxy, void (**implementation)(void), void *data);
82 : void wl_proxy_set_user_data (struct wl_proxy *proxy, void *user_data);
83 : void *wl_proxy_get_user_data (struct wl_proxy *proxy);
84 : void wl_proxy_set_tag (struct wl_proxy *proxy, const char * const *tag);
85 : const char * const *wl_proxy_get_tag (struct wl_proxy *proxy);
86 : void wl_proxy_destroy (struct wl_proxy *proxy);
87 : int wl_display_roundtrip (struct wl_display *display);
88 :
89 : wl_cursor_theme * wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm);
90 : void wl_cursor_theme_destroy(wl_cursor_theme *theme);
91 : wl_cursor * wl_cursor_theme_get_cursor(wl_cursor_theme *theme, const char *name);
92 : wl_buffer * wl_cursor_image_get_buffer(wl_cursor_image *image);
93 :
94 : }
95 : #endif
96 :
97 : namespace STAPPLER_VERSIONIZED stappler::xenolith::platform {
98 :
99 : static const char *s_XenolithWaylandTag = "org.stappler.xenolith.wayland";
100 :
101 : static WaylandLibrary *s_WaylandLibrary = nullptr;
102 :
103 : struct ViewporterInterface {
104 : const struct wl_interface *viewporter_types[6];
105 :
106 : const struct wl_message wp_viewporter_requests[2];
107 : const struct wl_message wp_viewport_requests[3];
108 :
109 : const struct wl_interface wp_viewporter_interface;
110 : const struct wl_interface wp_viewport_interface;
111 :
112 10 : ViewporterInterface(const struct wl_interface *wl_surface_interface)
113 10 : : viewporter_types{
114 : NULL,
115 : NULL,
116 : NULL,
117 : NULL,
118 10 : &wp_viewport_interface,
119 : wl_surface_interface
120 10 : }, wp_viewporter_requests{
121 10 : { "destroy", "", viewporter_types + 0 },
122 10 : { "get_viewport", "no", viewporter_types + 4 },
123 10 : }, wp_viewport_requests{
124 10 : { "destroy", "", viewporter_types + 0 },
125 10 : { "set_source", "ffff", viewporter_types + 0 },
126 10 : { "set_destination", "ii", viewporter_types + 0 },
127 10 : }, wp_viewporter_interface{
128 : "wp_viewporter", 1,
129 10 : 2, wp_viewporter_requests,
130 : 0, NULL,
131 10 : }, wp_viewport_interface{
132 : "wp_viewport", 1,
133 10 : 3, wp_viewport_requests,
134 : 0, NULL,
135 10 : } { }
136 : };
137 :
138 : struct XdgInterface {
139 : const struct wl_interface *xdg_shell_types[26];
140 :
141 : const struct wl_message xdg_wm_base_requests[4];
142 : const struct wl_message xdg_wm_base_events[1];
143 : const struct wl_message xdg_positioner_requests[10];
144 : const struct wl_message xdg_surface_requests[5];
145 : const struct wl_message xdg_surface_events[1];
146 : const struct wl_message xdg_toplevel_requests[14];
147 : const struct wl_message xdg_toplevel_events[3];
148 : const struct wl_message xdg_popup_requests[3];
149 : const struct wl_message xdg_popup_events[3];
150 :
151 : const struct wl_interface xdg_wm_base_interface;
152 : const struct wl_interface xdg_positioner_interface;
153 : const struct wl_interface xdg_surface_interface;
154 : const struct wl_interface xdg_toplevel_interface;
155 : const struct wl_interface xdg_popup_interface;
156 :
157 10 : XdgInterface(const struct wl_interface *wl_output_interface, const struct wl_interface *wl_seat_interface,
158 : const struct wl_interface *wl_surface_interface)
159 10 : : xdg_shell_types{
160 : NULL,
161 : NULL,
162 : NULL,
163 : NULL,
164 10 : &xdg_positioner_interface,
165 10 : &xdg_surface_interface,
166 : wl_surface_interface,
167 10 : &xdg_toplevel_interface,
168 10 : &xdg_popup_interface,
169 10 : &xdg_surface_interface,
170 10 : &xdg_positioner_interface,
171 10 : &xdg_toplevel_interface,
172 : wl_seat_interface,
173 : NULL,
174 : NULL,
175 : NULL,
176 : wl_seat_interface,
177 : NULL,
178 : wl_seat_interface,
179 : NULL,
180 : NULL,
181 : wl_output_interface,
182 : wl_seat_interface,
183 : NULL,
184 10 : &xdg_positioner_interface,
185 : NULL,
186 10 : }, xdg_wm_base_requests{
187 10 : { "destroy", "", xdg_shell_types + 0 },
188 10 : { "create_positioner", "n", xdg_shell_types + 4 },
189 10 : { "get_xdg_surface", "no", xdg_shell_types + 5 },
190 10 : { "pong", "u", xdg_shell_types + 0 },
191 10 : }, xdg_wm_base_events{
192 10 : { "ping", "u", xdg_shell_types + 0 },
193 10 : }, xdg_positioner_requests{
194 10 : { "destroy", "", xdg_shell_types + 0 },
195 10 : { "set_size", "ii", xdg_shell_types + 0 },
196 10 : { "set_anchor_rect", "iiii", xdg_shell_types + 0 },
197 10 : { "set_anchor", "u", xdg_shell_types + 0 },
198 10 : { "set_gravity", "u", xdg_shell_types + 0 },
199 10 : { "set_constraint_adjustment", "u", xdg_shell_types + 0 },
200 10 : { "set_offset", "ii", xdg_shell_types + 0 },
201 10 : { "set_reactive", "3", xdg_shell_types + 0 },
202 10 : { "set_parent_size", "3ii", xdg_shell_types + 0 },
203 10 : { "set_parent_configure", "3u", xdg_shell_types + 0 },
204 10 : }, xdg_surface_requests{
205 10 : { "destroy", "", xdg_shell_types + 0 },
206 10 : { "get_toplevel", "n", xdg_shell_types + 7 },
207 10 : { "get_popup", "n?oo", xdg_shell_types + 8 },
208 10 : { "set_window_geometry", "iiii", xdg_shell_types + 0 },
209 10 : { "ack_configure", "u", xdg_shell_types + 0 },
210 10 : }, xdg_surface_events{
211 10 : { "configure", "u", xdg_shell_types + 0 },
212 10 : }, xdg_toplevel_requests{
213 10 : { "destroy", "", xdg_shell_types + 0 },
214 10 : { "set_parent", "?o", xdg_shell_types + 11 },
215 10 : { "set_title", "s", xdg_shell_types + 0 },
216 10 : { "set_app_id", "s", xdg_shell_types + 0 },
217 10 : { "show_window_menu", "ouii", xdg_shell_types + 12 },
218 10 : { "move", "ou", xdg_shell_types + 16 },
219 10 : { "resize", "ouu", xdg_shell_types + 18 },
220 10 : { "set_max_size", "ii", xdg_shell_types + 0 },
221 10 : { "set_min_size", "ii", xdg_shell_types + 0 },
222 10 : { "set_maximized", "", xdg_shell_types + 0 },
223 10 : { "unset_maximized", "", xdg_shell_types + 0 },
224 10 : { "set_fullscreen", "?o", xdg_shell_types + 21 },
225 10 : { "unset_fullscreen", "", xdg_shell_types + 0 },
226 10 : { "set_minimized", "", xdg_shell_types + 0 },
227 10 : }, xdg_toplevel_events{
228 10 : { "configure", "iia", xdg_shell_types + 0 },
229 10 : { "close", "", xdg_shell_types + 0 },
230 10 : { "configure_bounds", "4ii", xdg_shell_types + 0 },
231 10 : }, xdg_popup_requests{
232 10 : { "destroy", "", xdg_shell_types + 0 },
233 10 : { "grab", "ou", xdg_shell_types + 22 },
234 10 : { "reposition", "3ou", xdg_shell_types + 24 },
235 10 : }, xdg_popup_events{
236 10 : { "configure", "iiii", xdg_shell_types + 0 },
237 10 : { "popup_done", "", xdg_shell_types + 0 },
238 10 : { "repositioned", "3u", xdg_shell_types + 0 },
239 10 : }, xdg_wm_base_interface{
240 : "xdg_wm_base", 4,
241 10 : 4, xdg_wm_base_requests,
242 10 : 1, xdg_wm_base_events,
243 10 : }, xdg_positioner_interface{
244 : "xdg_positioner", 4,
245 10 : 10, xdg_positioner_requests,
246 : 0, NULL,
247 10 : }, xdg_surface_interface{
248 : "xdg_surface", 4,
249 10 : 5, xdg_surface_requests,
250 10 : 1, xdg_surface_events,
251 10 : }, xdg_toplevel_interface{
252 : "xdg_toplevel", 4,
253 10 : 14, xdg_toplevel_requests,
254 10 : 3, xdg_toplevel_events,
255 10 : }, xdg_popup_interface{
256 : "xdg_popup", 4,
257 10 : 3, xdg_popup_requests,
258 10 : 3, xdg_popup_events,
259 10 : } { }
260 : };
261 :
262 : static const uint8_t s_iconClose[] = {
263 : 0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
264 : 0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0xff, 0xbd, 0x8f, 0x67, 0x67, 0x67, 0x5c, 0x55, 0x55, 0x55,
265 : 0x6, 0x20, 0x0, 0x5, 0x0, 0x1c, 0x0, 0x0, 0x24, 0x0, 0xf, 0x54, 0x0, 0x1d, 0x8e, 0x67,
266 : 0x67, 0x67, 0xff, 0x67, 0x67, 0x67, 0xb0, 0x5c, 0x0, 0x5, 0x54, 0x0, 0x13, 0xb0, 0x24, 0x0,
267 : 0xf, 0x5c, 0x0, 0x16, 0x83, 0x66, 0x66, 0x66, 0x5, 0x67, 0x67, 0x67, 0xaf, 0x38, 0x0, 0x5b,
268 : 0xb5, 0x6d, 0x6d, 0x6d, 0x7, 0x54, 0x0, 0xe, 0x1c, 0x0, 0xf, 0x5c, 0x0, 0x20, 0x40, 0x68,
269 : 0x68, 0x68, 0xb6, 0x40, 0x0, 0xf, 0x54, 0x0, 0x2d, 0xf, 0xf0, 0x0, 0x4, 0x18, 0xb0, 0xc,
270 : 0x0, 0xf, 0x7c, 0x1, 0x9, 0xf, 0x14, 0x1, 0x20, 0xf, 0xa8, 0x0, 0x2a, 0xe, 0xb4, 0x0,
271 : 0x6, 0x58, 0x0, 0x4, 0x14, 0x1, 0xf, 0x54, 0x0, 0x30, 0x1, 0xfc, 0x0, 0x4f, 0x66, 0x66,
272 : 0x66, 0xb1, 0x8, 0x1, 0x31, 0xf, 0x14, 0x2, 0x1, 0xf, 0xcc, 0x1, 0x1, 0xf, 0x54, 0x0,
273 : 0x2d, 0xf, 0x1c, 0x0, 0x11, 0xf, 0x18, 0x3, 0x15, 0x0, 0xfc, 0x0, 0xf, 0x18, 0x3, 0x39,
274 : 0xf, 0xc8, 0x3, 0x45, 0xf, 0x1, 0x0, 0xff, 0x92, 0xf0, 0x0, 0x66, 0x68, 0x65, 0x69, 0x67,
275 : 0x68, 0x74, 0x16, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x16,
276 : };
277 :
278 : static const uint8_t s_iconCloseActive[] = {
279 : 0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
280 : 0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0x4, 0xf3, 0x5, 0xb8, 0xb8, 0xb8, 0x12, 0xb4, 0xb4, 0xb4,
281 : 0x62, 0xb4, 0xb4, 0xb4, 0xb0, 0xb3, 0xb3, 0xb3, 0xd8, 0xb3, 0xb3, 0xb3, 0xf4, 0x4, 0x0, 0x0,
282 : 0xc, 0x0, 0xaf, 0xaf, 0xb3, 0xb3, 0xb3, 0x61, 0xb4, 0xb4, 0xb4, 0x11, 0x0, 0x1, 0x0, 0x14,
283 : 0xff, 0x1, 0xaa, 0xaa, 0xaa, 0x9, 0xb2, 0xb2, 0xb2, 0x7b, 0xb3, 0xb3, 0xb3, 0xf1, 0xb3, 0xb3,
284 : 0xb3, 0xff, 0x4, 0x0, 0xc, 0x50, 0xf0, 0xb4, 0xb4, 0xb4, 0x7a, 0x34, 0x0, 0xf, 0x54, 0x0,
285 : 0x9, 0x8f, 0xb1, 0xb1, 0xb1, 0x1a, 0xb3, 0xb3, 0xb3, 0xca, 0x50, 0x0, 0x10, 0xc, 0x4, 0x0,
286 : 0x5f, 0xcf, 0xb3, 0xb3, 0xb3, 0x1e, 0x54, 0x0, 0x1, 0x8f, 0xb6, 0xb6, 0xb6, 0x1c, 0xb3, 0xb3,
287 : 0xb3, 0xe4, 0x54, 0x0, 0x20, 0x4, 0x4, 0x0, 0x5c, 0xe3, 0xb3, 0xb3, 0xb3, 0x1b, 0xfc, 0x0,
288 : 0x4f, 0xb3, 0xb3, 0xb3, 0xcd, 0x54, 0x0, 0x28, 0x1, 0x4, 0x0, 0x84, 0xb2, 0xb2, 0xb2, 0xcb,
289 : 0xbf, 0xbf, 0xbf, 0x8, 0x58, 0x0, 0x4c, 0xb4, 0xb4, 0xb4, 0x7d, 0x24, 0x0, 0x7f, 0xce, 0xce,
290 : 0xce, 0xff, 0xb5, 0xb5, 0xb5, 0x44, 0x0, 0x6, 0x0, 0x1c, 0x0, 0x0, 0x24, 0x0, 0x1e, 0xb3,
291 : 0x1c, 0x0, 0x14, 0x78, 0xf8, 0x1, 0xc, 0xa4, 0x1, 0x0, 0x30, 0x0, 0x0, 0x1, 0x0, 0x3e,
292 : 0xe7, 0xe7, 0xe7, 0x5c, 0x0, 0x3, 0x54, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x1, 0x0, 0xe, 0x5c,
293 : 0x0, 0x1, 0xcc, 0x1, 0x5c, 0x11, 0xb2, 0xb2, 0xb2, 0x63, 0x38, 0x0, 0x35, 0xb4, 0xb4, 0xb4,
294 : 0x38, 0x0, 0x39, 0xe9, 0xe9, 0xe9, 0x5c, 0x0, 0x8, 0x54, 0x0, 0xc, 0x1c, 0x0, 0x7, 0x10,
295 : 0x1, 0x13, 0x60, 0xa0, 0x2, 0x1f, 0xff, 0x5c, 0x0, 0x11, 0xf, 0x54, 0x0, 0x11, 0x3, 0x4,
296 : 0x0, 0x5e, 0xae, 0xb3, 0xb3, 0xb3, 0xdb, 0x44, 0x1, 0xe, 0x9c, 0x0, 0x0, 0x8, 0x0, 0x8,
297 : 0xc, 0x0, 0xf, 0x7c, 0x1, 0x9, 0x3, 0x3c, 0x3, 0x1f, 0xf3, 0xe4, 0x1, 0x9, 0x8, 0xb8,
298 : 0x0, 0xf, 0xa8, 0x0, 0x10, 0x4, 0x4, 0x0, 0x1e, 0xf3, 0x58, 0x0, 0xe, 0xb4, 0x0, 0xf,
299 : 0x58, 0x0, 0x20, 0x0, 0x8, 0x2, 0x1f, 0xd9, 0x54, 0x0, 0x11, 0x3f, 0xe8, 0xe8, 0xe8, 0x8,
300 : 0x1, 0x19, 0x13, 0xd7, 0x44, 0x4, 0xf, 0xb8, 0x1, 0x12, 0xf, 0x28, 0x2, 0x9, 0xb, 0x10,
301 : 0x2, 0x10, 0xad, 0x98, 0x4, 0xf, 0x68, 0x2, 0x19, 0xf, 0x5c, 0x0, 0x14, 0x13, 0x5e, 0x18,
302 : 0x3, 0x1e, 0xf0, 0x18, 0x3, 0x2, 0xfc, 0x0, 0xf, 0x18, 0x3, 0x20, 0x53, 0xef, 0xaf, 0xaf,
303 : 0xaf, 0x10, 0xc8, 0x3, 0x1f, 0x7a, 0xc8, 0x3, 0x38, 0x14, 0x76, 0x20, 0x4, 0x0, 0x2c, 0x4,
304 : 0x0, 0x34, 0x4, 0xf, 0x78, 0x4, 0x2c, 0x0, 0x4, 0x0, 0x18, 0xc9, 0x78, 0x4, 0x0, 0x1,
305 : 0x0, 0x0, 0xe4, 0x4, 0x3, 0xec, 0x4, 0xf, 0x54, 0x0, 0x25, 0x10, 0xe2, 0xc0, 0x5, 0xf,
306 : 0xd8, 0x5, 0x8, 0x1f, 0xc9, 0x54, 0x0, 0x20, 0x1f, 0xce, 0xd8, 0x5, 0x5, 0x8, 0x14, 0x1,
307 : 0x0, 0xec, 0x4, 0xc, 0xcc, 0x1, 0xf, 0x4, 0x0, 0x4, 0x10, 0xef, 0x50, 0x1, 0x4f, 0xb6,
308 : 0xb6, 0xb6, 0x7, 0xe8, 0x6, 0x15, 0x3, 0xec, 0x4, 0x13, 0x60, 0xe0, 0x2, 0x17, 0xd7, 0x9c,
309 : 0x3, 0x10, 0xd7, 0x58, 0x4, 0x44, 0xb4, 0xb4, 0xb4, 0x5f, 0xf8, 0x1, 0xf, 0x1, 0x0, 0x1,
310 : 0xf0, 0x0, 0x66, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x16, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68,
311 : 0x16,
312 : };
313 :
314 : static const uint8_t s_iconMaximize[] = {
315 : 0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
316 : 0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0xff, 0xb9, 0x8f, 0x64, 0x64, 0x64, 0x40, 0x66, 0x66, 0x66,
317 : 0x80, 0x4, 0x0, 0x11, 0x0, 0x2c, 0x0, 0xf, 0x58, 0x0, 0x15, 0x0, 0x30, 0x0, 0x8f, 0x65,
318 : 0x65, 0x65, 0xfc, 0x65, 0x65, 0x65, 0xe0, 0x4, 0x0, 0xc, 0x10, 0xfc, 0x2c, 0x0, 0xf, 0x58,
319 : 0x0, 0x1c, 0x1f, 0xe0, 0x28, 0x0, 0xd, 0x0, 0x24, 0x0, 0xf, 0x58, 0x0, 0xff, 0xff, 0x8a,
320 : 0xf, 0x18, 0x3, 0x3e, 0xf, 0xc8, 0x3, 0x45, 0xf, 0x1, 0x0, 0xff, 0x92, 0xf0, 0x0, 0x66,
321 : 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x16, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x16,
322 : };
323 :
324 : static const uint8_t s_iconMaximizeActive[] = {
325 : 0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
326 : 0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0x4, 0xf3, 0x5, 0xb8, 0xb8, 0xb8, 0x12, 0xb4, 0xb4, 0xb4,
327 : 0x62, 0xb4, 0xb4, 0xb4, 0xb0, 0xb3, 0xb3, 0xb3, 0xd8, 0xb3, 0xb3, 0xb3, 0xf4, 0x4, 0x0, 0x0,
328 : 0xc, 0x0, 0xaf, 0xaf, 0xb3, 0xb3, 0xb3, 0x61, 0xb4, 0xb4, 0xb4, 0x11, 0x0, 0x1, 0x0, 0x14,
329 : 0xff, 0x1, 0xaa, 0xaa, 0xaa, 0x9, 0xb2, 0xb2, 0xb2, 0x7b, 0xb3, 0xb3, 0xb3, 0xf1, 0xb3, 0xb3,
330 : 0xb3, 0xff, 0x4, 0x0, 0xc, 0x50, 0xf0, 0xb4, 0xb4, 0xb4, 0x7a, 0x34, 0x0, 0xf, 0x54, 0x0,
331 : 0x9, 0x8f, 0xb1, 0xb1, 0xb1, 0x1a, 0xb3, 0xb3, 0xb3, 0xca, 0x50, 0x0, 0x10, 0xc, 0x4, 0x0,
332 : 0x5f, 0xcf, 0xb3, 0xb3, 0xb3, 0x1e, 0x54, 0x0, 0x1, 0x8f, 0xb6, 0xb6, 0xb6, 0x1c, 0xb3, 0xb3,
333 : 0xb3, 0xe4, 0x54, 0x0, 0x20, 0x4, 0x4, 0x0, 0x5c, 0xe3, 0xb3, 0xb3, 0xb3, 0x1b, 0xfc, 0x0,
334 : 0x4f, 0xb3, 0xb3, 0xb3, 0xcd, 0x54, 0x0, 0x28, 0x1, 0x4, 0x0, 0x84, 0xb2, 0xb2, 0xb2, 0xcb,
335 : 0xbf, 0xbf, 0xbf, 0x8, 0x58, 0x0, 0x48, 0xb4, 0xb4, 0xb4, 0x7d, 0x20, 0x0, 0x7f, 0xc6, 0xc6,
336 : 0xc6, 0xff, 0xd9, 0xd9, 0xd9, 0x4, 0x0, 0x12, 0x0, 0x2c, 0x0, 0xb, 0x60, 0x0, 0x14, 0x78,
337 : 0xf8, 0x1, 0xc, 0xa4, 0x1, 0x0, 0x30, 0x0, 0x7f, 0xfe, 0xfe, 0xfe, 0xff, 0xf6, 0xf6, 0xf6,
338 : 0x4, 0x0, 0xa, 0x0, 0x24, 0x0, 0x0, 0x2c, 0x0, 0x1e, 0xb3, 0xcc, 0x1, 0x5c, 0x11, 0xb2,
339 : 0xb2, 0xb2, 0x63, 0xd0, 0x0, 0x0, 0x2c, 0x0, 0x0, 0x38, 0x0, 0xf, 0xf8, 0x0, 0xd, 0x0,
340 : 0x24, 0x0, 0xe, 0x58, 0x0, 0x1, 0x10, 0x1, 0x13, 0x60, 0xa0, 0x2, 0xf, 0x58, 0x0, 0x39,
341 : 0x0, 0x4, 0x0, 0x5f, 0xae, 0xb3, 0xb3, 0xb3, 0xdb, 0x58, 0x0, 0x40, 0x0, 0x3c, 0x3, 0x1f,
342 : 0xf3, 0x58, 0x0, 0x40, 0x1f, 0xf3, 0x58, 0x0, 0x44, 0x0, 0x8, 0x2, 0x1f, 0xd9, 0x58, 0x0,
343 : 0x40, 0x13, 0xd7, 0x44, 0x4, 0xf, 0x10, 0x2, 0x3d, 0x10, 0xad, 0x98, 0x4, 0xf, 0xb0, 0x0,
344 : 0x40, 0x13, 0x5e, 0x18, 0x3, 0x1f, 0xf0, 0x18, 0x3, 0x38, 0x53, 0xef, 0xaf, 0xaf, 0xaf, 0x10,
345 : 0xc8, 0x3, 0x1f, 0x7a, 0xc8, 0x3, 0x38, 0x14, 0x76, 0x20, 0x4, 0x0, 0x2c, 0x4, 0x0, 0x34,
346 : 0x4, 0xf, 0x78, 0x4, 0x2c, 0x0, 0x4, 0x0, 0x18, 0xc9, 0x78, 0x4, 0x0, 0x1, 0x0, 0x0,
347 : 0xe4, 0x4, 0x3, 0xec, 0x4, 0xf, 0x54, 0x0, 0x25, 0x10, 0xe2, 0xc0, 0x5, 0xf, 0xd8, 0x5,
348 : 0x8, 0x1f, 0xc9, 0x54, 0x0, 0x20, 0x1f, 0xce, 0xd8, 0x5, 0x5, 0x8, 0x14, 0x1, 0x0, 0xec,
349 : 0x4, 0xc, 0xcc, 0x1, 0xf, 0x4, 0x0, 0x4, 0x10, 0xef, 0x50, 0x1, 0x4f, 0xb6, 0xb6, 0xb6,
350 : 0x7, 0xe8, 0x6, 0x15, 0x3, 0xec, 0x4, 0x13, 0x60, 0xe0, 0x2, 0x17, 0xd7, 0x9c, 0x3, 0x10,
351 : 0xd7, 0x58, 0x4, 0x44, 0xb4, 0xb4, 0xb4, 0x5f, 0xf8, 0x1, 0xf, 0x1, 0x0, 0x1, 0xf0, 0x0,
352 : 0x66, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x16, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x16,
353 : };
354 :
355 : static const uint8_t s_iconMinimize[] = {
356 : 0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
357 : 0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0xff, 0xff, 0xff, 0xff, 0x7c, 0x8f, 0x68, 0x68, 0x68, 0x20,
358 : 0x64, 0x64, 0x64, 0x40, 0x4, 0x0, 0x11, 0x0, 0x2c, 0x0, 0xf, 0x58, 0x0, 0x15, 0x8f, 0x66,
359 : 0x66, 0x66, 0x80, 0x65, 0x65, 0x65, 0xff, 0x4, 0x0, 0x11, 0x0, 0x2c, 0x0, 0xf, 0x58, 0x0,
360 : 0x15, 0x40, 0x60, 0x60, 0x60, 0x10, 0x88, 0x0, 0xf, 0x4, 0x0, 0x11, 0x0, 0x2c, 0x0, 0xf,
361 : 0x4, 0x3, 0xff, 0xff, 0x13, 0xf0, 0x0, 0x66, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x16, 0x65,
362 : 0x77, 0x69, 0x64, 0x74, 0x68, 0x16,
363 : };
364 :
365 : static const uint8_t s_iconMinimizeActive[] = {
366 : 0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
367 : 0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0x4, 0xf3, 0x5, 0xb8, 0xb8, 0xb8, 0x12, 0xb4, 0xb4, 0xb4,
368 : 0x62, 0xb4, 0xb4, 0xb4, 0xb0, 0xb3, 0xb3, 0xb3, 0xd8, 0xb3, 0xb3, 0xb3, 0xf4, 0x4, 0x0, 0x0,
369 : 0xc, 0x0, 0xaf, 0xaf, 0xb3, 0xb3, 0xb3, 0x61, 0xb4, 0xb4, 0xb4, 0x11, 0x0, 0x1, 0x0, 0x14,
370 : 0xff, 0x1, 0xaa, 0xaa, 0xaa, 0x9, 0xb2, 0xb2, 0xb2, 0x7b, 0xb3, 0xb3, 0xb3, 0xf1, 0xb3, 0xb3,
371 : 0xb3, 0xff, 0x4, 0x0, 0xc, 0x50, 0xf0, 0xb4, 0xb4, 0xb4, 0x7a, 0x34, 0x0, 0xf, 0x54, 0x0,
372 : 0x9, 0x8f, 0xb1, 0xb1, 0xb1, 0x1a, 0xb3, 0xb3, 0xb3, 0xca, 0x50, 0x0, 0x10, 0xc, 0x4, 0x0,
373 : 0x5f, 0xcf, 0xb3, 0xb3, 0xb3, 0x1e, 0x54, 0x0, 0x1, 0x8f, 0xb6, 0xb6, 0xb6, 0x1c, 0xb3, 0xb3,
374 : 0xb3, 0xe4, 0x54, 0x0, 0x20, 0x4, 0x4, 0x0, 0x5c, 0xe3, 0xb3, 0xb3, 0xb3, 0x1b, 0xfc, 0x0,
375 : 0x4f, 0xb3, 0xb3, 0xb3, 0xcd, 0x54, 0x0, 0x28, 0x1, 0x4, 0x0, 0x84, 0xb2, 0xb2, 0xb2, 0xcb,
376 : 0xbf, 0xbf, 0xbf, 0x8, 0x58, 0x0, 0x4f, 0xb4, 0xb4, 0xb4, 0x7d, 0x54, 0x0, 0x2d, 0x7, 0x4,
377 : 0x0, 0x14, 0x78, 0xf8, 0x1, 0xe, 0xa4, 0x1, 0xf, 0x4, 0x0, 0x2a, 0x10, 0xf0, 0x28, 0x2,
378 : 0x4f, 0xb2, 0xb2, 0xb2, 0x63, 0x54, 0x0, 0x38, 0x4, 0x10, 0x1, 0x13, 0x60, 0xa0, 0x2, 0x1f,
379 : 0xff, 0x4, 0x0, 0x3c, 0x5f, 0xae, 0xb3, 0xb3, 0xb3, 0xdb, 0x58, 0x0, 0x40, 0x0, 0x3c, 0x3,
380 : 0x1f, 0xf3, 0x58, 0x0, 0x40, 0x1f, 0xf3, 0x58, 0x0, 0x44, 0x0, 0x8, 0x2, 0x1f, 0xd9, 0x58,
381 : 0x0, 0x40, 0x13, 0xd7, 0x44, 0x4, 0x9, 0x18, 0x0, 0x7f, 0xbd, 0xbd, 0xbd, 0xff, 0xc6, 0xc6,
382 : 0xc6, 0x4, 0x0, 0x12, 0x0, 0x2c, 0x0, 0x1e, 0xb3, 0x10, 0x2, 0x10, 0xad, 0x98, 0x4, 0xc,
383 : 0x18, 0x0, 0x4f, 0xd9, 0xd9, 0xd9, 0xff, 0x1, 0x0, 0x15, 0x0, 0x2c, 0x0, 0x1e, 0xb3, 0xb0,
384 : 0x0, 0x13, 0x5e, 0x18, 0x3, 0x18, 0xf0, 0x18, 0x0, 0x31, 0xb8, 0xb8, 0xb8, 0x88, 0x0, 0xf,
385 : 0x4, 0x0, 0x11, 0x0, 0x2c, 0x0, 0xb, 0x54, 0x0, 0x53, 0xef, 0xaf, 0xaf, 0xaf, 0x10, 0xc8,
386 : 0x3, 0x1f, 0x7a, 0x5c, 0x1, 0x38, 0x14, 0x76, 0x20, 0x4, 0x0, 0x2c, 0x4, 0x0, 0x34, 0x4,
387 : 0xf, 0x54, 0x0, 0x30, 0x18, 0xc9, 0x78, 0x4, 0x0, 0x1, 0x0, 0x0, 0xe4, 0x4, 0x3, 0xec,
388 : 0x4, 0xf, 0x54, 0x0, 0x25, 0x10, 0xe2, 0xc0, 0x5, 0xf, 0xd8, 0x5, 0x8, 0x1f, 0xc9, 0x54,
389 : 0x0, 0x20, 0x1f, 0xce, 0xd8, 0x5, 0x5, 0x8, 0x14, 0x1, 0x0, 0xec, 0x4, 0xc, 0xcc, 0x1,
390 : 0xf, 0x4, 0x0, 0x4, 0x10, 0xef, 0x50, 0x1, 0x4f, 0xb6, 0xb6, 0xb6, 0x7, 0xe8, 0x6, 0x15,
391 : 0x3, 0xec, 0x4, 0x13, 0x60, 0xe0, 0x2, 0x17, 0xd7, 0x9c, 0x3, 0x10, 0xd7, 0x58, 0x4, 0x44,
392 : 0xb4, 0xb4, 0xb4, 0x5f, 0xf8, 0x1, 0xf, 0x1, 0x0, 0x1, 0xf0, 0x0, 0x66, 0x68, 0x65, 0x69,
393 : 0x67, 0x68, 0x74, 0x16, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x16,
394 : };
395 :
396 : static const uint8_t s_iconRestore[] = {
397 : 0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
398 : 0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0xff, 0xc5, 0x8f, 0x65, 0x65, 0x65, 0x30, 0x68, 0x68, 0x68,
399 : 0x40, 0x4, 0x0, 0x8, 0x1f, 0x20, 0x58, 0x0, 0x21, 0x8f, 0x67, 0x67, 0x67, 0x54, 0x66, 0x66,
400 : 0x66, 0x70, 0x4, 0x0, 0x1, 0x40, 0x65, 0x65, 0x65, 0x7e, 0x5c, 0x0, 0xf, 0xcc, 0x0, 0x3d,
401 : 0x0, 0x5c, 0x0, 0xf, 0x58, 0x0, 0x18, 0x0, 0xfc, 0x0, 0x5f, 0x60, 0x65, 0x65, 0x65, 0xc0,
402 : 0x4, 0x0, 0x8, 0x1f, 0x90, 0x58, 0x0, 0x20, 0x0, 0x30, 0x0, 0x9c, 0x80, 0x65, 0x65, 0x65,
403 : 0xf4, 0x64, 0x64, 0x64, 0xa0, 0x4, 0x0, 0x40, 0x65, 0x65, 0x65, 0xdc, 0x5c, 0x0, 0xf, 0x58,
404 : 0x0, 0x28, 0x1f, 0xe0, 0x1c, 0x0, 0x1, 0x3, 0x5c, 0x0, 0xf, 0x58, 0x0, 0xfa, 0x0, 0x84,
405 : 0x2, 0x0, 0xe0, 0x2, 0xf, 0x58, 0x0, 0x3d, 0xf, 0x98, 0x2, 0x20, 0x0, 0x58, 0x0, 0x10,
406 : 0xfc, 0x5c, 0x0, 0x1e, 0x65, 0x4, 0x0, 0x1f, 0xf4, 0x58, 0x0, 0x24, 0x0, 0x94, 0x0, 0x10,
407 : 0x40, 0x5c, 0x0, 0xf, 0x4, 0x0, 0x5, 0x0, 0xe0, 0x2, 0xf, 0xb8, 0x5, 0xff, 0xc6, 0xf0,
408 : 0x0, 0x66, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x16, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x16,
409 : };
410 :
411 : static const uint8_t s_iconRestoreActive[] = {
412 : 0x4c, 0x5a, 0x34, 0x53, 0xab, 0x7, 0xdf, 0xd9, 0xd9, 0xf7, 0xa3, 0x64, 0x64, 0x61, 0x74, 0x61,
413 : 0x59, 0x7, 0x90, 0x0, 0x1, 0x0, 0x4, 0xf3, 0x5, 0xb8, 0xb8, 0xb8, 0x12, 0xb1, 0xb1, 0xb1,
414 : 0x62, 0xb2, 0xb2, 0xb2, 0xb0, 0xb2, 0xb2, 0xb2, 0xd8, 0xb2, 0xb2, 0xb2, 0xf4, 0x4, 0x0, 0x0,
415 : 0xc, 0x0, 0xaf, 0xaf, 0xb3, 0xb3, 0xb3, 0x61, 0xb4, 0xb4, 0xb4, 0x11, 0x0, 0x1, 0x0, 0x14,
416 : 0xff, 0x1, 0xaa, 0xaa, 0xaa, 0x9, 0xb2, 0xb2, 0xb2, 0x7b, 0xb2, 0xb2, 0xb2, 0xf1, 0xb2, 0xb2,
417 : 0xb2, 0xff, 0x4, 0x0, 0x9, 0x80, 0xb3, 0xb3, 0xb3, 0xf0, 0xb2, 0xb2, 0xb2, 0x7a, 0x34, 0x0,
418 : 0xf, 0x54, 0x0, 0x9, 0x8f, 0xb1, 0xb1, 0xb1, 0x1a, 0xb2, 0xb2, 0xb2, 0xca, 0x50, 0x0, 0xd,
419 : 0xc, 0x4, 0x0, 0x8f, 0xb1, 0xb1, 0xb1, 0xcf, 0xb3, 0xb3, 0xb3, 0x1e, 0x54, 0x0, 0x1, 0x8f,
420 : 0xb6, 0xb6, 0xb6, 0x1c, 0xb2, 0xb2, 0xb2, 0xe4, 0x54, 0x0, 0x1d, 0x7, 0x5c, 0x0, 0x6e, 0xe3,
421 : 0xb3, 0xb3, 0xb3, 0x1b, 0x0, 0xfc, 0x0, 0x1f, 0xcd, 0x54, 0x0, 0x25, 0x7, 0x4, 0x0, 0x57,
422 : 0xcb, 0xbf, 0xbf, 0xbf, 0x8, 0x0, 0x1, 0x1f, 0x7d, 0x2c, 0x0, 0x5, 0x7f, 0xc0, 0xc0, 0xc0,
423 : 0xff, 0xc5, 0xc5, 0xc5, 0x4, 0x0, 0x6, 0x3c, 0xbc, 0xbc, 0xbc, 0x74, 0x1, 0x14, 0x78, 0xf8,
424 : 0x1, 0xf, 0xa4, 0x1, 0x9, 0x7f, 0xcb, 0xcb, 0xcb, 0xff, 0xd4, 0xd4, 0xd4, 0x4, 0x0, 0x2,
425 : 0x31, 0xd8, 0xd8, 0xd8, 0x5c, 0x0, 0xc, 0xcc, 0x1, 0x0, 0x28, 0x2, 0x4f, 0xb2, 0xb2, 0xb2,
426 : 0x63, 0xf8, 0x0, 0x25, 0x0, 0x5c, 0x0, 0xc, 0x58, 0x0, 0x3, 0x4, 0x0, 0x13, 0x60, 0xa0,
427 : 0x2, 0x9, 0x18, 0x0, 0x7f, 0xcf, 0xcf, 0xcf, 0xff, 0xec, 0xec, 0xec, 0x4, 0x0, 0x6, 0x3e,
428 : 0xdd, 0xdd, 0xdd, 0x58, 0x0, 0xa, 0xc4, 0x1, 0x5c, 0xae, 0xb2, 0xb2, 0xb2, 0xdb, 0x18, 0x0,
429 : 0xbd, 0xd9, 0xd9, 0xd9, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0xe2, 0xe2, 0xe2, 0x4, 0x0, 0x31, 0xf4,
430 : 0xf4, 0xf4, 0x5c, 0x0, 0xf, 0xb0, 0x0, 0xc, 0x0, 0x3c, 0x3, 0x1f, 0xf3, 0x58, 0x0, 0x1,
431 : 0x3f, 0xf6, 0xf6, 0xf6, 0xfc, 0x0, 0x2, 0x0, 0x5c, 0x0, 0xf, 0x58, 0x0, 0x10, 0x1f, 0xf3,
432 : 0x58, 0x0, 0x44, 0x5f, 0xf1, 0xb1, 0xb1, 0xb1, 0xd9, 0x58, 0x0, 0x40, 0x10, 0xd7, 0x44, 0x4,
433 : 0xf, 0x58, 0x0, 0x25, 0x0, 0x84, 0x2, 0x0, 0xe0, 0x2, 0x1e, 0xb2, 0x28, 0x0, 0x10, 0xad,
434 : 0x98, 0x4, 0xf, 0x58, 0x0, 0x25, 0xf, 0x90, 0x4, 0x8, 0x10, 0x5e, 0x18, 0x3, 0x3, 0x98,
435 : 0x4, 0x9, 0x58, 0x0, 0x31, 0xfe, 0xfe, 0xfe, 0x5c, 0x0, 0xc, 0x4, 0x0, 0x0, 0x28, 0x2,
436 : 0xf, 0x58, 0x0, 0xc, 0x50, 0xef, 0xaf, 0xaf, 0xaf, 0x10, 0x74, 0x3, 0x0, 0xec, 0x4, 0x8,
437 : 0x1c, 0x0, 0x0, 0x34, 0x1, 0x0, 0x5c, 0x0, 0xf, 0x4, 0x0, 0x5, 0x0, 0xe0, 0x2, 0xf,
438 : 0x80, 0x4, 0x8, 0x14, 0x76, 0x20, 0x4, 0x0, 0x2c, 0x4, 0x0, 0x34, 0x4, 0xf, 0x78, 0x4,
439 : 0x30, 0x18, 0xc9, 0x78, 0x4, 0x0, 0x1, 0x0, 0x0, 0xe4, 0x4, 0x0, 0xec, 0x4, 0xf, 0x54,
440 : 0x0, 0x28, 0x10, 0xe2, 0xc0, 0x5, 0xf, 0xd8, 0x5, 0x8, 0x1f, 0xc9, 0x54, 0x0, 0x20, 0x1f,
441 : 0xce, 0xd8, 0x5, 0x5, 0x8, 0x14, 0x1, 0x0, 0xec, 0x4, 0xc, 0xcc, 0x1, 0xf, 0xa4, 0x1,
442 : 0x5, 0x0, 0x50, 0x1, 0x4f, 0xb6, 0xb6, 0xb6, 0x7, 0xe8, 0x6, 0x15, 0x3, 0xec, 0x4, 0x13,
443 : 0x60, 0xe0, 0x2, 0x17, 0xd7, 0x9c, 0x3, 0x10, 0xd7, 0x58, 0x4, 0x44, 0xb1, 0xb1, 0xb1, 0x5f,
444 : 0xf8, 0x1, 0xf, 0x1, 0x0, 0x1, 0xf0, 0x0, 0x66, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x16,
445 : 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, 0x16,
446 : };
447 :
448 0 : WaylandLibrary *WaylandLibrary::getInstance() {
449 0 : return s_WaylandLibrary;
450 : }
451 :
452 20 : WaylandLibrary::~WaylandLibrary() {
453 10 : close();
454 20 : }
455 :
456 10 : WaylandLibrary::WaylandLibrary() {
457 :
458 10 : }
459 :
460 10 : bool WaylandLibrary::init() {
461 : #ifndef XL_LINK
462 10 : _handle = Dso("libwayland-client.so");
463 10 : if (!_handle) {
464 0 : return false;
465 : }
466 : #endif
467 10 : if (open(_handle)) {
468 10 : s_WaylandLibrary = this;
469 10 : openConnection(_pending);
470 10 : return _pending.display != nullptr;
471 : } else {
472 0 : _handle = Dso();
473 : }
474 0 : return false;
475 : }
476 :
477 10 : void WaylandLibrary::close() {
478 10 : if (_pending.display) {
479 0 : wl_display_disconnect(_pending.display);
480 0 : _pending.display = nullptr;
481 : }
482 :
483 10 : if (viewporter) {
484 10 : delete viewporter;
485 10 : viewporter = nullptr;
486 : }
487 :
488 10 : if (xdg) {
489 10 : delete xdg;
490 10 : xdg = nullptr;
491 : }
492 :
493 10 : if (s_WaylandLibrary == this) {
494 10 : s_WaylandLibrary = nullptr;
495 : }
496 10 : }
497 :
498 0 : WaylandLibrary::ConnectionData WaylandLibrary::acquireConnection() {
499 0 : if (_pending.display) {
500 0 : _current = _pending;
501 0 : _pending = ConnectionData({nullptr});
502 0 : return _current;
503 : } else {
504 0 : openConnection(_current);
505 0 : return _current;
506 : }
507 : }
508 :
509 0 : WaylandLibrary::ConnectionData WaylandLibrary::getActiveConnection() const {
510 0 : if (_pending.display) {
511 0 : return _pending;
512 : } else {
513 0 : return _current;
514 : }
515 : }
516 :
517 0 : bool WaylandLibrary::ownsProxy(wl_proxy *proxy) {
518 0 : auto tag = getInstance()->wl_proxy_get_tag(proxy);
519 0 : return tag == &s_XenolithWaylandTag;
520 : }
521 :
522 0 : bool WaylandLibrary::ownsProxy(wl_output *output) {
523 0 : return ownsProxy((struct wl_proxy *) output);
524 : }
525 :
526 0 : bool WaylandLibrary::ownsProxy(wl_surface *surface) {
527 0 : return ownsProxy((struct wl_proxy *) surface);
528 : }
529 :
530 10 : bool WaylandLibrary::open(Dso &handle) {
531 : #if XL_LINK
532 : this->wl_registry_interface = &::wl_registry_interface;
533 : this->wl_compositor_interface = &::wl_compositor_interface;
534 : this->wl_output_interface = &::wl_output_interface;
535 : this->wl_seat_interface = &::wl_seat_interface;
536 : this->wl_surface_interface = &::wl_surface_interface;
537 : this->wl_region_interface = &::wl_region_interface;
538 : this->wl_callback_interface = &::wl_callback_interface;
539 : this->wl_pointer_interface = &::wl_pointer_interface;
540 : this->wl_keyboard_interface = &::wl_keyboard_interface;
541 : this->wl_touch_interface = &::wl_touch_interface;
542 : this->wl_shm_interface = &::wl_shm_interface;
543 : this->wl_subcompositor_interface = &::wl_subcompositor_interface;
544 : this->wl_subsurface_interface = &::wl_subsurface_interface;
545 : this->wl_shm_pool_interface = &::wl_shm_pool_interface;
546 : this->wl_buffer_interface = &::wl_buffer_interface;
547 :
548 : this->wl_display_connect = &::wl_display_connect;
549 : this->wl_display_get_fd = &::wl_display_get_fd;
550 : this->wl_display_dispatch = &::wl_display_dispatch;
551 : this->wl_display_dispatch_pending = &::wl_display_dispatch_pending;
552 : this->wl_display_prepare_read = &::wl_display_prepare_read;
553 : this->wl_display_flush = &::wl_display_flush;
554 : this->wl_display_read_events = &::wl_display_read_events;
555 : this->wl_display_disconnect = &::wl_display_disconnect;
556 : this->wl_proxy_marshal_flags = &::wl_proxy_marshal_flags;
557 : this->wl_proxy_get_version = &::wl_proxy_get_version;
558 : this->wl_proxy_add_listener = &::wl_proxy_add_listener;
559 : this->wl_proxy_set_user_data = &::wl_proxy_set_user_data;
560 : this->wl_proxy_get_user_data = &::wl_proxy_get_user_data;
561 : this->wl_proxy_set_tag = &::wl_proxy_set_tag;
562 : this->wl_proxy_get_tag = &::wl_proxy_get_tag;
563 : this->wl_proxy_destroy = &::wl_proxy_destroy;
564 : this->wl_display_roundtrip = &::wl_display_roundtrip;
565 : #else
566 10 : this->wl_registry_interface = handle.sym<decltype(this->wl_registry_interface)>("wl_registry_interface");
567 10 : this->wl_compositor_interface = handle.sym<decltype(this->wl_compositor_interface)>("wl_compositor_interface");
568 10 : this->wl_output_interface = handle.sym<decltype(this->wl_output_interface)>("wl_output_interface");
569 10 : this->wl_seat_interface = handle.sym<decltype(this->wl_seat_interface)>("wl_seat_interface");
570 10 : this->wl_surface_interface = handle.sym<decltype(this->wl_surface_interface)>("wl_surface_interface");
571 10 : this->wl_region_interface = handle.sym<decltype(this->wl_region_interface)>("wl_region_interface");
572 10 : this->wl_callback_interface = handle.sym<decltype(this->wl_callback_interface)>("wl_callback_interface");
573 10 : this->wl_pointer_interface = handle.sym<decltype(this->wl_callback_interface)>("wl_pointer_interface");
574 10 : this->wl_keyboard_interface = handle.sym<decltype(this->wl_keyboard_interface)>("wl_keyboard_interface");
575 10 : this->wl_touch_interface = handle.sym<decltype(this->wl_touch_interface)>("wl_touch_interface");
576 10 : this->wl_shm_interface = handle.sym<decltype(this->wl_shm_interface)>("wl_shm_interface");
577 10 : this->wl_subcompositor_interface = handle.sym<decltype(this->wl_subcompositor_interface)>("wl_subcompositor_interface");
578 10 : this->wl_subsurface_interface = handle.sym<decltype(this->wl_subsurface_interface)>("wl_subsurface_interface");
579 10 : this->wl_shm_pool_interface = handle.sym<decltype(this->wl_shm_pool_interface)>("wl_shm_pool_interface");
580 10 : this->wl_buffer_interface = handle.sym<decltype(this->wl_buffer_interface)>("wl_buffer_interface");
581 :
582 10 : this->wl_display_connect = handle.sym<decltype(this->wl_display_connect)>("wl_display_connect");
583 10 : this->wl_display_get_fd = handle.sym<decltype(this->wl_display_get_fd)>("wl_display_get_fd");
584 10 : this->wl_display_dispatch = handle.sym<decltype(this->wl_display_dispatch)>("wl_display_dispatch");
585 10 : this->wl_display_dispatch_pending = handle.sym<decltype(this->wl_display_dispatch_pending)>("wl_display_dispatch_pending");
586 10 : this->wl_display_prepare_read = handle.sym<decltype(this->wl_display_prepare_read)>("wl_display_prepare_read");
587 10 : this->wl_display_flush = handle.sym<decltype(this->wl_display_flush)>("wl_display_flush");
588 10 : this->wl_display_read_events = handle.sym<decltype(this->wl_display_read_events)>("wl_display_read_events");
589 10 : this->wl_display_disconnect = handle.sym<decltype(this->wl_display_disconnect)>("wl_display_disconnect");
590 10 : this->wl_proxy_marshal_flags = handle.sym<decltype(this->wl_proxy_marshal_flags)>("wl_proxy_marshal_flags");
591 10 : this->wl_proxy_get_version = handle.sym<decltype(this->wl_proxy_get_version)>("wl_proxy_get_version");
592 10 : this->wl_proxy_add_listener = handle.sym<decltype(this->wl_proxy_add_listener)>("wl_proxy_add_listener");
593 10 : this->wl_proxy_set_user_data = handle.sym<decltype(this->wl_proxy_set_user_data)>("wl_proxy_set_user_data");
594 10 : this->wl_proxy_get_user_data = handle.sym<decltype(this->wl_proxy_get_user_data)>("wl_proxy_get_user_data");
595 10 : this->wl_proxy_set_tag = handle.sym<decltype(this->wl_proxy_set_tag)>("wl_proxy_set_tag");
596 10 : this->wl_proxy_get_tag = handle.sym<decltype(this->wl_proxy_get_tag)>("wl_proxy_get_tag");
597 10 : this->wl_proxy_destroy = handle.sym<decltype(this->wl_proxy_destroy)>("wl_proxy_destroy");
598 10 : this->wl_display_roundtrip = handle.sym<decltype(this->wl_display_roundtrip)>("wl_display_roundtrip");
599 : #endif
600 :
601 10 : if (this->wl_registry_interface
602 10 : && this->wl_compositor_interface
603 10 : && this->wl_output_interface
604 10 : && this->wl_seat_interface
605 10 : && this->wl_surface_interface
606 10 : && this->wl_region_interface
607 10 : && this->wl_callback_interface
608 10 : && this->wl_pointer_interface
609 10 : && this->wl_keyboard_interface
610 10 : && this->wl_touch_interface
611 10 : && this->wl_shm_interface
612 10 : && this->wl_subcompositor_interface
613 10 : && this->wl_subsurface_interface
614 10 : && this->wl_shm_pool_interface
615 10 : && this->wl_buffer_interface
616 10 : && this->wl_display_connect
617 10 : && this->wl_display_get_fd
618 10 : && this->wl_display_dispatch
619 10 : && this->wl_display_disconnect
620 10 : && this->wl_proxy_marshal_flags
621 10 : && this->wl_proxy_get_version
622 10 : && this->wl_proxy_add_listener
623 10 : && this->wl_proxy_set_user_data
624 10 : && this->wl_proxy_get_user_data
625 10 : && this->wl_proxy_set_tag
626 10 : && this->wl_proxy_get_tag
627 10 : && this->wl_proxy_destroy
628 10 : && this->wl_display_roundtrip
629 10 : && this->wl_registry_interface) {
630 10 : viewporter = new ViewporterInterface(wl_surface_interface);
631 10 : xdg = new XdgInterface(wl_output_interface, wl_seat_interface, wl_surface_interface);
632 :
633 10 : wp_viewporter_interface = &viewporter->wp_viewporter_interface;
634 10 : wp_viewport_interface = &viewporter->wp_viewport_interface;
635 :
636 10 : xdg_wm_base_interface = &xdg->xdg_wm_base_interface;
637 10 : xdg_positioner_interface = &xdg->xdg_positioner_interface;
638 10 : xdg_surface_interface = &xdg->xdg_surface_interface;
639 10 : xdg_toplevel_interface = &xdg->xdg_toplevel_interface;
640 10 : xdg_popup_interface = &xdg->xdg_popup_interface;
641 :
642 : #ifndef XL_LINK
643 10 : _cursor = Dso("libwayland-cursor.so");
644 : #endif
645 10 : if (!openWaylandCursor(_cursor)) {
646 0 : _cursor = Dso();
647 : }
648 10 : return true;
649 : }
650 0 : return false;
651 : }
652 :
653 10 : bool WaylandLibrary::openWaylandCursor(Dso &handle) {
654 : #if XL_LINK
655 : this->wl_cursor_theme_load = &::wl_cursor_theme_load;
656 : this->wl_cursor_theme_destroy = &::wl_cursor_theme_destroy;
657 : this->wl_cursor_theme_get_cursor = &::wl_cursor_theme_get_cursor;
658 : this->wl_cursor_image_get_buffer = &::wl_cursor_image_get_buffer;
659 : #else
660 10 : if (!handle) {
661 0 : return false;
662 : }
663 :
664 10 : this->wl_cursor_theme_load = handle.sym<decltype(this->wl_cursor_theme_load)>("wl_cursor_theme_load");
665 10 : this->wl_cursor_theme_destroy = handle.sym<decltype(this->wl_cursor_theme_destroy)>("wl_cursor_theme_destroy");
666 10 : this->wl_cursor_theme_get_cursor = handle.sym<decltype(this->wl_cursor_theme_get_cursor)>("wl_cursor_theme_get_cursor");
667 10 : this->wl_cursor_image_get_buffer = handle.sym<decltype(this->wl_cursor_image_get_buffer)>("wl_cursor_image_get_buffer");
668 : #endif
669 10 : return this->wl_cursor_theme_load
670 10 : && this->wl_cursor_theme_destroy
671 10 : && this->wl_cursor_theme_get_cursor
672 20 : && this->wl_cursor_image_get_buffer;
673 : }
674 :
675 10 : void WaylandLibrary::openConnection(ConnectionData &data) {
676 10 : data.display = wl_display_connect(NULL);
677 10 : }
678 :
679 : static const xdg_wm_base_listener s_XdgWmBaseListener{
680 0 : [] (void *data, xdg_wm_base *xdg_wm_base, uint32_t serial) {
681 0 : ((WaylandDisplay *)data)->wayland->xdg_wm_base_pong(xdg_wm_base, serial);
682 0 : },
683 : };
684 :
685 : static const wl_registry_listener s_WaylandRegistryListener{
686 0 : [] (void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) {
687 0 : auto display = (WaylandDisplay *)data;
688 0 : auto wayland = display->wayland.get();
689 :
690 : XL_WAYLAND_LOG("handleGlobal: '", interface, "', version: ", version, ", name: ", name);
691 0 : if (strcmp(interface, wayland->wl_compositor_interface->name) == 0) {
692 0 : display->compositor = static_cast<wl_compositor *>(wayland->wl_registry_bind(registry, name,
693 0 : wayland->wl_compositor_interface, std::min(version, 4U)));
694 0 : } else if (strcmp(interface, wayland->wl_subcompositor_interface->name) == 0) {
695 0 : display->subcompositor = static_cast<wl_subcompositor *>(wayland->wl_registry_bind(registry, name,
696 : wayland->wl_subcompositor_interface, 1U));
697 0 : } else if (strcmp(interface, wayland->wl_output_interface->name) == 0) {
698 0 : auto out = Rc<WaylandOutput>::create(wayland, registry, name, version);
699 0 : display->outputs.emplace_back(move(out));
700 0 : } else if (strcmp(interface, wayland->wp_viewporter_interface->name) == 0) {
701 0 : display->viewporter = static_cast<struct wp_viewporter *>(wayland->wl_registry_bind(registry, name,
702 : wayland->wp_viewporter_interface, 1));
703 0 : } else if (strcmp(interface, wayland->xdg_wm_base_interface->name) == 0) {
704 0 : display->xdgWmBase = static_cast<struct xdg_wm_base *>(wayland->wl_registry_bind(registry, name,
705 0 : wayland->xdg_wm_base_interface, std::min(version, 2U)));
706 0 : wayland->xdg_wm_base_add_listener(display->xdgWmBase, &s_XdgWmBaseListener, display);
707 0 : } else if (strcmp(interface, wayland->wl_shm_interface->name) == 0) {
708 0 : display->shm = Rc<WaylandShm>::create(wayland, registry, name, version);
709 0 : } else if (strcmp(interface, wayland->wl_seat_interface->name) == 0) {
710 0 : display->seat = Rc<WaylandSeat>::create(wayland, display, registry, name, version);
711 : }
712 0 : },
713 0 : [] (void *data, struct wl_registry *registry, uint32_t name) {
714 : //auto display = (WaylandDisplay *)data;
715 :
716 0 : },
717 : };
718 :
719 0 : WaylandDisplay::~WaylandDisplay() {
720 0 : if (xdgWmBase) {
721 0 : wayland->xdg_wm_base_destroy(xdgWmBase);
722 0 : xdgWmBase = nullptr;
723 : }
724 0 : if (compositor) {
725 0 : wayland->wl_compositor_destroy(compositor);
726 0 : compositor = nullptr;
727 : }
728 0 : if (subcompositor) {
729 0 : wayland->wl_subcompositor_destroy(subcompositor);
730 0 : subcompositor = nullptr;
731 : }
732 0 : if (viewporter) {
733 0 : wayland->wp_viewporter_destroy(viewporter);
734 0 : viewporter = nullptr;
735 : }
736 :
737 0 : shm = nullptr;
738 0 : seat = nullptr;
739 0 : outputs.clear();
740 :
741 0 : if (display) {
742 0 : wayland->wl_display_disconnect(display);
743 0 : display = nullptr;
744 : }
745 0 : }
746 :
747 0 : bool WaylandDisplay::init(const Rc<WaylandLibrary> &lib) {
748 0 : wayland = lib;
749 :
750 0 : auto connection = wayland->acquireConnection();
751 :
752 0 : display = connection.display;
753 :
754 0 : struct wl_registry *registry = wayland->wl_display_get_registry(display);
755 :
756 0 : wayland->wl_registry_add_listener(registry, &s_WaylandRegistryListener, this);
757 0 : wayland->wl_display_roundtrip(display); // registry
758 0 : wayland->wl_display_roundtrip(display); // seats and outputs
759 0 : wayland->wl_registry_destroy(registry);
760 :
761 0 : xkb = XkbLibrary::getInstance();
762 0 : return true;
763 : }
764 :
765 0 : wl_surface *WaylandDisplay::createSurface(WaylandViewInterface *view) {
766 0 : auto surface = wayland->wl_compositor_create_surface(compositor);
767 0 : wayland->wl_surface_set_user_data(surface, view);
768 0 : wayland->wl_proxy_set_tag((struct wl_proxy *) surface, &s_XenolithWaylandTag);
769 0 : surfaces.emplace(surface);
770 0 : return surface;
771 : }
772 :
773 0 : void WaylandDisplay::destroySurface(wl_surface *surface) {
774 0 : surfaces.erase(surface);
775 0 : wayland->wl_surface_destroy(surface);
776 0 : }
777 :
778 0 : wl_surface *WaylandDisplay::createDecorationSurface(WaylandDecoration *decor) {
779 0 : auto surface = wayland->wl_compositor_create_surface(compositor);
780 0 : wayland->wl_surface_set_user_data(surface, decor);
781 0 : wayland->wl_proxy_set_tag((struct wl_proxy *) surface, &s_XenolithWaylandTag);
782 0 : decorations.emplace(surface);
783 0 : return surface;
784 : }
785 :
786 0 : void WaylandDisplay::destroyDecorationSurface(wl_surface *surface) {
787 0 : decorations.erase(surface);
788 0 : wayland->wl_surface_destroy(surface);
789 0 : }
790 :
791 0 : bool WaylandDisplay::ownsSurface(wl_surface *surface) const {
792 0 : return surfaces.find(surface) != surfaces.end();
793 : }
794 :
795 0 : bool WaylandDisplay::isDecoration(wl_surface *surface) const {
796 0 : return decorations.find(surface) != decorations.end();
797 : }
798 :
799 0 : bool WaylandDisplay::flush() {
800 0 : while (wayland->wl_display_prepare_read(display) != 0) {
801 0 : wayland->wl_display_dispatch_pending(display);
802 : }
803 :
804 0 : while (wayland->wl_display_flush(display) == -1) {
805 0 : if (errno != EAGAIN) {
806 0 : return false;
807 : }
808 :
809 0 : struct pollfd fd = { getSocketFd(), POLLOUT };
810 :
811 0 : while (::poll(&fd, 1, -1) == -1) {
812 0 : if (errno != EINTR && errno != EAGAIN) {
813 0 : return false;
814 : }
815 : }
816 : }
817 :
818 0 : wayland->wl_display_read_events(display);
819 0 : wayland->wl_display_dispatch_pending(display);
820 :
821 0 : return true;
822 : }
823 :
824 0 : int WaylandDisplay::getSocketFd() const {
825 0 : return wayland->wl_display_get_fd(display);
826 : }
827 :
828 0 : WaylandCursorTheme::~WaylandCursorTheme() {
829 0 : if (cursorTheme) {
830 0 : wayland->wl_cursor_theme_destroy(cursorTheme);
831 0 : cursorTheme = nullptr;
832 : }
833 0 : }
834 :
835 0 : static const char *getCursorName(WaylandCursorImage image) {
836 0 : switch (image) {
837 0 : case WaylandCursorImage::LeftPtr: return "left_ptr"; break;
838 0 : case WaylandCursorImage::EResize: return "right_side"; break;
839 0 : case WaylandCursorImage::NEResize: return "top_right_corner"; break;
840 0 : case WaylandCursorImage::NResize: return "top_side"; break;
841 0 : case WaylandCursorImage::NWResize: return "top_left_corner"; break;
842 0 : case WaylandCursorImage::SEResize: return "bottom_right_corner"; break;
843 0 : case WaylandCursorImage::SResize: return "bottom_side"; break;
844 0 : case WaylandCursorImage::SWResize: return "bottom_left_corner"; break;
845 0 : case WaylandCursorImage::WResize: return "left_side"; break;
846 0 : case WaylandCursorImage::Max: break;
847 : }
848 0 : return nullptr;
849 : }
850 :
851 0 : bool WaylandCursorTheme::init(WaylandDisplay *display, StringView name, int size) {
852 0 : wayland = display->wayland;
853 0 : cursorSize = size;
854 0 : cursorName = name.str<Interface>();
855 0 : cursorTheme = wayland->wl_cursor_theme_load(name.data(), size, display->shm->shm);
856 :
857 0 : if (cursorTheme) {
858 0 : for (int i = 0; i < toInt(WaylandCursorImage::Max); ++ i) {
859 0 : auto name = getCursorName(WaylandCursorImage(i));
860 0 : auto cursor = wayland->wl_cursor_theme_get_cursor(cursorTheme, name);
861 0 : cursors.emplace_back(cursor);
862 : }
863 0 : return true;
864 : }
865 :
866 0 : return false;
867 : }
868 :
869 0 : void WaylandCursorTheme::setCursor(WaylandSeat *seat) {
870 0 : setCursor(seat->pointer, seat->cursorSurface, seat->serial, seat->cursorImage, seat->pointerScale);
871 0 : }
872 :
873 0 : void WaylandCursorTheme::setCursor(wl_pointer *pointer, wl_surface *cursorSurface, uint32_t serial, WaylandCursorImage img, int scale) {
874 0 : if (!cursorTheme || cursors.size() <= size_t(toInt(img))) {
875 0 : return;
876 : }
877 :
878 0 : auto cursor = cursors[toInt(img)];
879 0 : if (!cursor) {
880 0 : cursor = cursors[0];
881 : }
882 :
883 0 : auto image = cursor->images[0];
884 0 : auto buffer = wayland->wl_cursor_image_get_buffer(image);
885 0 : wayland->wl_pointer_set_cursor(pointer, serial, cursorSurface, image->hotspot_x / scale, image->hotspot_y / scale);
886 0 : wayland->wl_surface_attach(cursorSurface, buffer, 0, 0);
887 0 : wayland->wl_surface_set_buffer_scale(cursorSurface, scale);
888 0 : wayland->wl_surface_damage_buffer(cursorSurface, 0, 0, image->width, image->height);
889 0 : wayland->wl_surface_commit(cursorSurface);
890 : }
891 :
892 : static struct wl_shm_listener s_WaylandShmListener = {
893 0 : [] (void *data, wl_shm *shm, uint32_t format) {
894 0 : ((WaylandShm *)data)->format = format;
895 0 : }
896 : };
897 :
898 0 : static int createAnonymousFile(off_t size) {
899 : static const char tpl[] = "/xl-wayland-XXXXXX";
900 : const char* path;
901 : int fd;
902 : int ret;
903 :
904 0 : fd = ::memfd_create("xl-wayland", MFD_CLOEXEC | MFD_ALLOW_SEALING);
905 0 : if (fd >= 0) {
906 0 : ::fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
907 : } else {
908 0 : path = getenv("XDG_RUNTIME_DIR");
909 0 : if (!path) {
910 0 : errno = ENOENT;
911 0 : return -1;
912 : }
913 :
914 0 : char* tmpname = (char *)::calloc(strlen(path) + sizeof(tpl), 1);
915 0 : ::strcpy(tmpname, path);
916 0 : ::strcat(tmpname, tpl);
917 :
918 0 : fd = ::mkostemp(tmpname, O_CLOEXEC);
919 0 : if (fd >= 0) {
920 0 : ::unlink(tmpname);
921 0 : ::free(tmpname);
922 : } else {
923 0 : ::free(tmpname);
924 0 : return -1;
925 : }
926 : }
927 :
928 0 : ret = ::posix_fallocate(fd, 0, size);
929 0 : if (ret != 0) {
930 0 : ::close(fd);
931 0 : errno = ret;
932 0 : return -1;
933 : }
934 0 : return fd;
935 : }
936 :
937 0 : WaylandBuffer::~WaylandBuffer() {
938 0 : if (buffer) {
939 0 : wayland->wl_buffer_destroy(buffer);
940 0 : buffer = nullptr;
941 : }
942 0 : }
943 :
944 0 : bool WaylandBuffer::init(WaylandLibrary *lib, wl_shm_pool *pool, int32_t offset,
945 : int32_t w, int32_t h, int32_t stride, uint32_t format) {
946 0 : wayland = lib;
947 0 : width = w;
948 0 : height = h;
949 0 : buffer = wayland->wl_shm_pool_create_buffer(pool, offset, width, height, stride, format);
950 0 : return true;
951 : }
952 :
953 0 : WaylandShm::~WaylandShm() {
954 0 : if (shm) {
955 0 : wayland->wl_shm_destroy(shm);
956 0 : shm = nullptr;
957 : }
958 0 : }
959 :
960 0 : bool WaylandShm::init(const Rc<WaylandLibrary> &lib, wl_registry *registry, uint32_t name, uint32_t version) {
961 0 : wayland = lib;
962 0 : id = name;
963 0 : shm = static_cast<wl_shm*>(wayland->wl_registry_bind(registry, name,
964 0 : wayland->wl_shm_interface, std::min(version, 1U)));
965 0 : wayland->wl_shm_set_user_data(shm, this);
966 0 : wayland->wl_shm_add_listener(shm, &s_WaylandShmListener, this);
967 0 : wayland->wl_proxy_set_tag((struct wl_proxy *) shm, &s_XenolithWaylandTag);
968 0 : return true;
969 : }
970 :
971 0 : static void makeGaussianVector(Color4B *retA, Color4B *retB, uint32_t size) {
972 0 : const float sigma = sqrtf((size * size) / (-2.0f * logf(1.0f / 255.0f)));
973 0 : const float sigma_v = -1.0f / (2.0f * sigma * sigma);
974 :
975 0 : for (uint32_t j = 0; j < size; j++) {
976 0 : retA[j].a = (uint8_t)(24.0f * expf( (j * j) * sigma_v ));
977 0 : retB[j].a = (uint8_t)(64.0f * expf( (j * j) * sigma_v ));
978 : }
979 0 : }
980 :
981 0 : static void makeGaussianRange(Color4B *retA, Color4B *retB, uint32_t size, uint32_t inset) {
982 0 : auto width = size + inset;
983 0 : auto targetA = retA;
984 0 : auto targetB = retA + width * width;
985 0 : auto targetC = retA + width * width * 2;
986 0 : auto targetD = retA + width * width * 3;
987 0 : auto targetE = retB;
988 0 : auto targetF = retB + width * width;
989 0 : auto targetG = retB + width * width * 2;
990 0 : auto targetH = retB + width * width * 3;
991 :
992 0 : const float sigma = sqrtf((size * size) / (-2.0f * logf(1.0f / 255.0f)));
993 0 : const float sigma_v = -1.0f / (2.0f * sigma * sigma);
994 :
995 0 : for (uint32_t i = 0; i < width; i++) {
996 0 : for (uint32_t j = 0; j < width; j++) {
997 0 : float dist = sqrtf( (i * i) + (j * j) );
998 0 : float tmp = 0.0f;
999 0 : if (dist <= inset) {
1000 0 : tmp = 1.0f;
1001 0 : } else if (dist > size + inset) {
1002 0 : tmp = 0.0f;
1003 : } else {
1004 0 : dist = dist - inset;
1005 0 : tmp = expf( (dist * dist) * sigma_v);
1006 : }
1007 :
1008 0 : auto valueA = (uint8_t)(24.0f * tmp);
1009 0 : auto valueB = (uint8_t)(64.0f * tmp);
1010 0 : targetA[i * width + j].a = valueA;
1011 0 : targetB[(width - i - 1) * width + (width - j - 1)].a = valueA;
1012 0 : targetC[(i) * width + (width - j - 1)].a = valueA;
1013 0 : targetD[(width - i - 1) * width + (j)].a = valueA;
1014 0 : targetE[i * width + j].a = valueB;
1015 0 : targetF[(width - i - 1) * width + (width - j - 1)].a = valueB;
1016 0 : targetG[(i) * width + (width - j - 1)].a = valueB;
1017 0 : targetH[(width - i - 1) * width + (j)].a = valueB;
1018 : }
1019 : }
1020 0 : }
1021 :
1022 0 : static void makeRoundedHeader(Color4B *retA, uint32_t size, const Color3B &colorA, const Color3B &colorB) {
1023 0 : auto targetA = retA;
1024 0 : auto targetB = retA + size * size * 1;
1025 0 : auto targetC = retA + size * size * 2;
1026 0 : auto targetD = retA + size * size * 3;
1027 :
1028 0 : Color4B tmpA = Color4B(colorA.b, colorA.g, colorA.r, 255);
1029 0 : Color4B tmpB = Color4B(colorB.b, colorB.g, colorB.r, 255);
1030 0 : for (uint32_t i = 0; i < size; i++) {
1031 0 : for (uint32_t j = 0; j < size; j++) {
1032 0 : auto u = size - i - 1;
1033 0 : auto v = size - j - 1;
1034 0 : float dist = sqrtf( (u * u) + (v * v) );
1035 0 : if (dist >= size) {
1036 0 : targetA[i * size + j] = Color4B(0, 0, 0, 0);
1037 0 : targetB[i * size + j] = Color4B(0, 0, 0, 0);
1038 0 : targetC[i * size + (size - j - 1)] = Color4B(0, 0, 0, 0);
1039 0 : targetD[i * size + (size - j - 1)] = Color4B(0, 0, 0, 0);
1040 : } else {
1041 0 : targetA[i * size + j] = tmpA;
1042 0 : targetB[i * size + j] = tmpB;
1043 0 : targetC[i * size + (size - j - 1)] = tmpA;
1044 0 : targetD[i * size + (size - j - 1)] = tmpB;
1045 : }
1046 : }
1047 : }
1048 0 : }
1049 :
1050 0 : bool WaylandShm::allocateDecorations(ShadowBuffers *ret, uint32_t width, uint32_t inset,
1051 : const Color3B &header, const Color3B &headerActive) {
1052 :
1053 0 : auto size = width * sizeof(Color4B) * 8; // plain shadows
1054 0 : size += (width + inset) * (width + inset) * sizeof(Color4B) * 8; // cornerShadows
1055 0 : size += (inset * 2 * inset) * sizeof(Color4B) * 2;
1056 0 : size += 2 * sizeof(Color4B);
1057 :
1058 : struct IconData {
1059 : WaylandDecorationName name;
1060 : Value value;
1061 : bool active;
1062 : uint32_t width = 0;
1063 : uint32_t height = 0;
1064 : BytesView data;
1065 : };
1066 :
1067 0 : Vector<IconData> icons;
1068 :
1069 0 : auto loadData = [&] (WaylandDecorationName name, BytesView data, bool active) {
1070 0 : auto &icon = icons.emplace_back(IconData{name, data::read<Interface>(data), active});
1071 0 : icon.width = icon.value.getInteger("width");
1072 0 : icon.height = icon.value.getInteger("height");
1073 0 : icon.data = icon.value.getBytes("data");
1074 0 : return icon.width * icon.height * sizeof(Color4B);
1075 0 : };
1076 :
1077 0 : size += loadData(WaylandDecorationName::IconClose, BytesView(s_iconClose, sizeof(s_iconClose)), false);
1078 0 : size += loadData(WaylandDecorationName::IconMaximize, BytesView(s_iconMaximize, sizeof(s_iconMaximize)), false);
1079 0 : size += loadData(WaylandDecorationName::IconMinimize, BytesView(s_iconMinimize, sizeof(s_iconMinimize)), false);
1080 0 : size += loadData(WaylandDecorationName::IconRestore, BytesView(s_iconRestore, sizeof(s_iconRestore)), false);
1081 0 : size += loadData(WaylandDecorationName::IconClose, BytesView(s_iconCloseActive, sizeof(s_iconCloseActive)), true);
1082 0 : size += loadData(WaylandDecorationName::IconMaximize, BytesView(s_iconMaximizeActive, sizeof(s_iconMaximizeActive)), true);
1083 0 : size += loadData(WaylandDecorationName::IconMinimize, BytesView(s_iconMinimizeActive, sizeof(s_iconMinimizeActive)), true);
1084 0 : size += loadData(WaylandDecorationName::IconRestore, BytesView(s_iconRestoreActive, sizeof(s_iconRestoreActive)), true);
1085 :
1086 0 : const int fd = createAnonymousFile(size);
1087 0 : if (fd < 0) {
1088 0 : return false;
1089 : }
1090 :
1091 0 : auto data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1092 0 : if (data == MAP_FAILED) {
1093 0 : ::close(fd);
1094 0 : return false;
1095 : }
1096 :
1097 0 : auto pool = wayland->wl_shm_create_pool(shm, fd, size);
1098 0 : ::close(fd);
1099 :
1100 0 : auto targetA = (Color4B *)data;
1101 0 : auto targetB = (Color4B *)data + width * 4;
1102 0 : makeGaussianVector(targetA, targetB, width);
1103 :
1104 : // make normal
1105 0 : ::memcpy(targetA + width * 2, targetA, width * sizeof(Color4B));
1106 0 : ::memcpy(targetA + width * 3, targetA, width * sizeof(Color4B));
1107 0 : std::reverse(targetA, targetA + width);
1108 0 : ::memcpy(targetA + width * 1, targetA, width * sizeof(Color4B));
1109 :
1110 : // make active
1111 0 : ::memcpy(targetB + width * 2, targetB, width * sizeof(Color4B));
1112 0 : ::memcpy(targetB + width * 3, targetB, width * sizeof(Color4B));
1113 0 : std::reverse(targetB, targetB + width);
1114 0 : ::memcpy(targetB + width * 1, targetB, width * sizeof(Color4B));
1115 :
1116 0 : ret->top = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 0,
1117 0 : 1, width, sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1118 0 : ret->left = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 1,
1119 0 : width, 1, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1120 0 : ret->bottom = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 2,
1121 0 : 1, width, sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1122 0 : ret->right = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 3,
1123 0 : width, 1, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1124 0 : ret->topActive = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 4,
1125 0 : 1, width, sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1126 0 : ret->leftActive = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 5,
1127 0 : width, 1, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1128 0 : ret->bottomActive = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 6,
1129 0 : 1, width, sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1130 0 : ret->rightActive = Rc<WaylandBuffer>::create(wayland, pool, width * sizeof(Color4B) * 7,
1131 0 : width, 1, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1132 :
1133 0 : auto offset = width * 8 * sizeof(Color4B);
1134 0 : targetA = (Color4B *)data + width * 8;
1135 0 : width += inset;
1136 0 : targetB = targetA + width * width * 4;
1137 0 : makeGaussianRange(targetA, targetB, width - inset, inset);
1138 :
1139 0 : ret->bottomRight = Rc<WaylandBuffer>::create(wayland, pool, offset,
1140 0 : width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1141 0 : ret->topLeft = Rc<WaylandBuffer>::create(wayland, pool, offset + width * width * sizeof(Color4B),
1142 0 : width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1143 0 : ret->bottomLeft = Rc<WaylandBuffer>::create(wayland, pool, offset + width * width * 2 * sizeof(Color4B),
1144 0 : width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1145 0 : ret->topRight = Rc<WaylandBuffer>::create(wayland, pool, offset + width * width * 3 * sizeof(Color4B),
1146 0 : width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1147 0 : ret->bottomRightActive =Rc<WaylandBuffer>::create(wayland, pool, offset + width * width * 4 * sizeof(Color4B),
1148 0 : width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1149 0 : ret->topLeftActive = Rc<WaylandBuffer>::create(wayland, pool, offset + width * width * 5 * sizeof(Color4B),
1150 0 : width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1151 0 : ret->bottomLeftActive = Rc<WaylandBuffer>::create(wayland, pool, offset + width * width * 6 * sizeof(Color4B),
1152 0 : width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1153 0 : ret->topRightActive = Rc<WaylandBuffer>::create(wayland, pool, offset + width * width * 7 * sizeof(Color4B),
1154 0 : width, width, width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1155 :
1156 0 : offset += width * width * 8 * sizeof(Color4B);
1157 0 : targetA = (Color4B *)((uint8_t *)data + offset);
1158 :
1159 0 : makeRoundedHeader(targetA, inset, header, headerActive);
1160 :
1161 0 : ret->headerLeft = Rc<WaylandBuffer>::create(wayland, pool, offset,
1162 0 : inset, inset, inset * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1163 0 : ret->headerLeftActive = Rc<WaylandBuffer>::create(wayland, pool, offset + inset * inset * sizeof(Color4B) * 1,
1164 0 : inset, inset, inset * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1165 0 : ret->headerRight = Rc<WaylandBuffer>::create(wayland, pool, offset + inset * inset * sizeof(Color4B) * 2,
1166 0 : inset, inset, inset * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1167 0 : ret->headerRightActive = Rc<WaylandBuffer>::create(wayland, pool, offset + inset * inset * sizeof(Color4B) * 3,
1168 0 : inset, inset, inset * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1169 :
1170 0 : offset += inset * inset * sizeof(Color4B) * 4;
1171 0 : targetA = (Color4B *)((uint8_t *)data + offset);
1172 0 : targetA[0] = Color4B(header.b, header.g, header.r, 255);
1173 0 : targetA[1] = Color4B(headerActive.b, headerActive.g, headerActive.r, 255);
1174 :
1175 0 : ret->headerCenter = Rc<WaylandBuffer>::create(wayland, pool, offset,
1176 0 : 1, 1, sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1177 0 : ret->headerCenterActive = Rc<WaylandBuffer>::create(wayland, pool, offset + sizeof(Color4B),
1178 0 : 1, 1, sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1179 :
1180 0 : offset += 2 * sizeof(Color4B);
1181 0 : targetA += 2;
1182 :
1183 0 : for (IconData &it : icons) {
1184 0 : memcpy((uint8_t *)data + offset, it.data.data(), it.data.size());
1185 0 : Rc<WaylandBuffer> buf = Rc<WaylandBuffer>::create(wayland, pool, offset,
1186 0 : it.width, it.height, it.width * sizeof(Color4B), WL_SHM_FORMAT_ARGB8888);
1187 0 : switch (it.name) {
1188 0 : case WaylandDecorationName::IconClose:
1189 0 : if (it.active) { ret->iconCloseActive = move(buf); } else { ret->iconClose = move(buf); }
1190 0 : break;
1191 0 : case WaylandDecorationName::IconMaximize:
1192 0 : if (it.active) { ret->iconMaximizeActive = move(buf); } else { ret->iconMaximize = move(buf); }
1193 0 : break;
1194 0 : case WaylandDecorationName::IconMinimize:
1195 0 : if (it.active) { ret->iconMinimizeActive = move(buf); } else { ret->iconMinimize = move(buf); }
1196 0 : break;
1197 0 : case WaylandDecorationName::IconRestore:
1198 0 : if (it.active) { ret->iconRestoreActive = move(buf); } else { ret->iconRestore = move(buf); }
1199 0 : break;
1200 0 : default:
1201 0 : break;
1202 : }
1203 0 : offset += it.data.size();
1204 0 : }
1205 :
1206 0 : ::munmap(data, size);
1207 0 : wayland->wl_shm_pool_destroy(pool);
1208 :
1209 0 : return true;
1210 0 : }
1211 :
1212 : static const wl_output_listener s_WaylandOutputListener{
1213 : // geometry
1214 0 : [] (void *data, wl_output *wl_output, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height,
1215 : int32_t subpixel, char const *make, char const *model, int32_t transform) {
1216 0 : auto out = ((WaylandOutput *)data);
1217 0 : out->geometry = WaylandOutput::Geometry{x, y, physical_width, physical_height,
1218 0 : subpixel, transform, make, model};
1219 0 : if (out->name.empty()) {
1220 0 : out->name = toString(make, " ", model);
1221 : }
1222 0 : },
1223 :
1224 : // mode
1225 0 : [] (void *data, wl_output *output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
1226 0 : ((WaylandOutput *)data)->mode = WaylandOutput::Mode{flags, width, height, refresh};
1227 0 : },
1228 :
1229 : // done
1230 0 : [] (void *data, wl_output* output) {
1231 : // do nothing
1232 0 : },
1233 :
1234 : // scale
1235 0 : [] (void *data, wl_output* output, int32_t factor) {
1236 0 : ((WaylandOutput *)data)->scale = factor;
1237 0 : },
1238 :
1239 : // name
1240 0 : [] (void *data, struct wl_output *wl_output, const char *name) {
1241 0 : ((WaylandOutput *)data)->name = name;
1242 0 : },
1243 :
1244 : // description
1245 0 : [] (void *data, struct wl_output *wl_output, const char *name) {
1246 0 : ((WaylandOutput *)data)->desc = name;
1247 0 : }
1248 : };
1249 :
1250 0 : WaylandOutput::~WaylandOutput() {
1251 0 : if (output) {
1252 0 : wayland->wl_output_destroy(output);
1253 0 : output = nullptr;
1254 : }
1255 0 : }
1256 :
1257 0 : bool WaylandOutput::init(const Rc<WaylandLibrary> &lib, wl_registry *registry, uint32_t name, uint32_t version) {
1258 0 : wayland = lib;
1259 0 : id = name;
1260 0 : output = static_cast<wl_output*>(wayland->wl_registry_bind(registry, name,
1261 0 : wayland->wl_output_interface, std::min(version, 2U)));
1262 0 : wayland->wl_output_set_user_data(output, this);
1263 0 : wayland->wl_output_add_listener(output, &s_WaylandOutputListener, this);
1264 0 : wayland->wl_proxy_set_tag((struct wl_proxy *) output, &s_XenolithWaylandTag);
1265 0 : return true;
1266 : }
1267 :
1268 0 : String WaylandOutput::description() const {
1269 0 : StringStream stream;
1270 0 : stream << geometry.make << " " << geometry.model << ": "
1271 0 : << mode.width << "x" << mode.height << "@" << mode.refresh / 1000 << "Hz (x" << scale << ");";
1272 0 : if (mode.flags & WL_OUTPUT_MODE_CURRENT) {
1273 0 : stream << " Current;";
1274 : }
1275 0 : if (mode.flags & WL_OUTPUT_MODE_PREFERRED) {
1276 0 : stream << " Preferred;";
1277 : }
1278 0 : if (!desc.empty()) {
1279 0 : stream << " " << desc << ";";
1280 : }
1281 0 : return stream.str();
1282 0 : }
1283 :
1284 : static struct wl_pointer_listener s_WaylandPointerListener{
1285 : // enter
1286 0 : [] (void *data, wl_pointer *wl_pointer, uint32_t serial, wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
1287 0 : auto seat = (WaylandSeat *)data;
1288 0 : seat->pointerFocus = surface;
1289 0 : seat->serial = serial;
1290 :
1291 0 : if (!seat->root->ownsSurface(surface)) {
1292 0 : if (seat->root->isDecoration(surface)) {
1293 0 : if (auto decor = (WaylandDecoration *)seat->wayland->wl_surface_get_user_data(surface)) {
1294 0 : if (decor->image != seat->cursorImage) {
1295 0 : if (seat->cursorTheme) {
1296 0 : seat->cursorImage = decor->image;
1297 0 : seat->cursorTheme->setCursor(seat);
1298 : }
1299 : }
1300 0 : seat->pointerDecorations.emplace(decor);
1301 0 : decor->onEnter();
1302 : }
1303 : }
1304 0 : return;
1305 : }
1306 :
1307 0 : if (auto view = (WaylandViewInterface *)seat->wayland->wl_surface_get_user_data(surface)) {
1308 0 : seat->pointerViews.emplace(view);
1309 0 : if (WaylandCursorImage::LeftPtr != seat->cursorImage) {
1310 0 : if (seat->cursorTheme) {
1311 0 : seat->cursorImage = WaylandCursorImage::LeftPtr;
1312 0 : seat->cursorTheme->setCursor(seat);
1313 : }
1314 : }
1315 0 : view->handlePointerEnter(surface_x, surface_y);
1316 : }
1317 : },
1318 :
1319 : // leave
1320 0 : [] (void *data, wl_pointer *wl_pointer, uint32_t serial, wl_surface *surface) {
1321 0 : auto seat = (WaylandSeat *)data;
1322 :
1323 0 : if (seat->root->isDecoration(surface)) {
1324 0 : if (auto decor = (WaylandDecoration *)seat->wayland->wl_surface_get_user_data(surface)) {
1325 0 : decor->waitForMove = false;
1326 0 : seat->pointerDecorations.erase(decor);
1327 0 : decor->onLeave();
1328 : }
1329 : }
1330 :
1331 0 : if (seat->root->ownsSurface(surface)) {
1332 0 : if (auto view = (WaylandViewInterface *)seat->wayland->wl_surface_get_user_data(surface)) {
1333 0 : view->handlePointerLeave();
1334 0 : seat->pointerViews.erase(view);
1335 : }
1336 : }
1337 :
1338 0 : if (seat->pointerFocus == surface) {
1339 0 : seat->pointerFocus = NULL;
1340 0 : seat->cursorImage = WaylandCursorImage::Max;
1341 : }
1342 0 : },
1343 :
1344 : // motion
1345 0 : [] (void *data, wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
1346 0 : auto seat = (WaylandSeat *)data;
1347 0 : for (auto &it : seat->pointerViews) {
1348 0 : it->handlePointerMotion(time, surface_x, surface_y);
1349 : }
1350 0 : for (auto &it : seat->pointerDecorations) {
1351 0 : it->handleMotion();
1352 : }
1353 0 : },
1354 :
1355 : // button
1356 0 : [] (void *data, wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
1357 0 : auto seat = (WaylandSeat *)data;
1358 0 : for (auto &it : seat->pointerViews) {
1359 0 : it->handlePointerButton(serial, time, button, state);
1360 : }
1361 0 : for (auto &it : seat->pointerDecorations) {
1362 0 : it->handlePress(serial, button, state);
1363 : }
1364 0 : },
1365 :
1366 : // axis
1367 0 : [] (void *data, wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {
1368 0 : auto seat = (WaylandSeat *)data;
1369 0 : for (auto &it : seat->pointerViews) {
1370 0 : it->handlePointerAxis(time, axis, value);
1371 : }
1372 0 : },
1373 :
1374 : // frame
1375 0 : [] (void *data, wl_pointer *wl_pointer) {
1376 0 : auto seat = (WaylandSeat *)data;
1377 0 : for (auto &it : seat->pointerViews) {
1378 0 : it->handlePointerFrame();
1379 : }
1380 0 : },
1381 :
1382 : // axis_source
1383 0 : [] (void *data, wl_pointer *wl_pointer, uint32_t axis_source) {
1384 0 : auto seat = (WaylandSeat *)data;
1385 0 : for (auto &it : seat->pointerViews) {
1386 0 : it->handlePointerAxisSource(axis_source);
1387 : }
1388 0 : },
1389 :
1390 : // axis_stop
1391 0 : [] (void *data, wl_pointer *wl_pointer, uint32_t time, uint32_t axis) {
1392 0 : auto seat = (WaylandSeat *)data;
1393 0 : for (auto &it : seat->pointerViews) {
1394 0 : it->handlePointerAxisStop(time, axis);
1395 : }
1396 0 : },
1397 :
1398 : // axis_discrete
1399 0 : [] (void *data, wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) {
1400 0 : auto seat = (WaylandSeat *)data;
1401 0 : for (auto &it : seat->pointerViews) {
1402 0 : it->handlePointerAxisDiscrete(axis, discrete);
1403 : }
1404 0 : }
1405 : };
1406 :
1407 : static struct wl_keyboard_listener s_WaylandKeyboardListener{
1408 : // keymap
1409 0 : [] (void *data, wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size) {
1410 0 : auto seat = (WaylandSeat *)data;
1411 0 : if (seat->root->xkb) {
1412 0 : auto map_shm = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
1413 0 : if (map_shm != MAP_FAILED) {
1414 0 : if (seat->state) {
1415 0 : seat->root->xkb->xkb_state_unref(seat->state);
1416 0 : seat->state = nullptr;
1417 : }
1418 :
1419 0 : if (seat->compose) {
1420 0 : seat->root->xkb->xkb_compose_state_unref(seat->compose);
1421 0 : seat->compose = nullptr;
1422 : }
1423 :
1424 0 : auto keymap = seat->root->xkb->xkb_keymap_new_from_string(seat->root->xkb->getContext(),
1425 : (const char *)map_shm, xkb_keymap_format(format), XKB_KEYMAP_COMPILE_NO_FLAGS);
1426 0 : if (keymap) {
1427 0 : seat->state = seat->root->xkb->xkb_state_new(keymap);
1428 0 : seat->keyState.controlIndex = seat->root->xkb->xkb_keymap_mod_get_index(keymap, "Control");
1429 0 : seat->keyState.altIndex = seat->root->xkb->xkb_keymap_mod_get_index(keymap, "Mod1");
1430 0 : seat->keyState.shiftIndex = seat->root->xkb->xkb_keymap_mod_get_index(keymap, "Shift");
1431 0 : seat->keyState.superIndex = seat->root->xkb->xkb_keymap_mod_get_index(keymap, "Mod4");
1432 0 : seat->keyState.capsLockIndex = seat->root->xkb->xkb_keymap_mod_get_index(keymap, "Lock");
1433 0 : seat->keyState.numLockIndex = seat->root->xkb->xkb_keymap_mod_get_index(keymap, "Mod2");
1434 0 : seat->root->xkb->xkb_keymap_unref(keymap);
1435 : }
1436 :
1437 0 : auto locale = getenv("LC_ALL");
1438 0 : if (!locale) { locale = getenv("LC_CTYPE"); }
1439 0 : if (!locale) { locale = getenv("LANG"); }
1440 :
1441 0 : auto composeTable = seat->root->xkb->xkb_compose_table_new_from_locale(seat->root->xkb->getContext(),
1442 : locale ? locale : "C", XKB_COMPOSE_COMPILE_NO_FLAGS);
1443 0 : if (composeTable) {
1444 0 : seat->compose = seat->root->xkb->xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
1445 0 : seat->root->xkb->xkb_compose_table_unref(composeTable);
1446 : }
1447 :
1448 0 : munmap(map_shm, size);
1449 : }
1450 : }
1451 0 : close(fd);
1452 0 : },
1453 :
1454 : // enter
1455 0 : [] (void *data, wl_keyboard *wl_keyboard, uint32_t serial, wl_surface *surface, struct wl_array *keys) {
1456 0 : auto seat = (WaylandSeat *)data;
1457 0 : if (seat->root->ownsSurface(surface)) {
1458 0 : if (auto view = (WaylandViewInterface *)seat->wayland->wl_surface_get_user_data(surface)) {
1459 0 : Vector<uint32_t> keysVec;
1460 0 : for (uint32_t *it = (uint32_t *)keys->data; (const char *)it < ((const char *) keys->data + keys->size); ++ it) {
1461 0 : keysVec.emplace_back(*it);
1462 : }
1463 :
1464 0 : seat->keyboardViews.emplace(view);
1465 0 : view->handleKeyboardEnter(move(keysVec), seat->keyState.modsDepressed, seat->keyState.modsLatched, seat->keyState.modsLocked);
1466 0 : }
1467 : }
1468 0 : },
1469 :
1470 : // leave
1471 0 : [] (void *data, wl_keyboard *wl_keyboard, uint32_t serial, wl_surface *surface) {
1472 0 : auto seat = (WaylandSeat *)data;
1473 0 : if (seat->root->ownsSurface(surface)) {
1474 0 : if (auto view = (WaylandViewInterface *)seat->wayland->wl_surface_get_user_data(surface)) {
1475 0 : view->handleKeyboardLeave();
1476 0 : seat->keyboardViews.erase(view);
1477 : }
1478 : }
1479 0 : },
1480 :
1481 : // key
1482 0 : [] (void *data, wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
1483 0 : auto seat = (WaylandSeat *)data;
1484 0 : for (auto &it : seat->keyboardViews) {
1485 0 : it->handleKey(time, key, state);
1486 : }
1487 0 : },
1488 :
1489 : // modifiers
1490 0 : [] (void *data, wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed,
1491 : uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {
1492 0 : auto seat = (WaylandSeat *)data;
1493 0 : if (seat->state) {
1494 0 : seat->root->xkb->xkb_state_update_mask(seat->state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
1495 0 : seat->keyState.modsDepressed = mods_depressed;
1496 0 : seat->keyState.modsLatched = mods_latched;
1497 0 : seat->keyState.modsLocked = mods_locked;
1498 0 : for (auto &it : seat->keyboardViews) {
1499 0 : it->handleKeyModifiers(mods_depressed, mods_latched, mods_locked);
1500 : }
1501 : }
1502 0 : },
1503 :
1504 : // repeat_info
1505 0 : [] (void *data, wl_keyboard *wl_keyboard, int32_t rate, int32_t delay) {
1506 0 : auto seat = (WaylandSeat *)data;
1507 0 : seat->keyState.keyRepeatRate = rate;
1508 0 : seat->keyState.keyRepeatDelay = delay;
1509 0 : seat->keyState.keyRepeatInterval = 1'000'000 / rate;
1510 0 : }
1511 : };
1512 :
1513 : static struct wl_touch_listener s_WaylandTouchListener{
1514 : // down
1515 0 : [](void *data, wl_touch *touch, uint32_t serial, uint32_t time, wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y) {
1516 :
1517 0 : },
1518 :
1519 : // up
1520 0 : [](void *data, wl_touch *touch, uint32_t serial, uint32_t time, int32_t id) {
1521 :
1522 0 : },
1523 :
1524 : // motion
1525 0 : [](void *data, wl_touch *touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) {
1526 :
1527 0 : },
1528 :
1529 : // frame
1530 0 : [](void *data, wl_touch *touch) {
1531 :
1532 0 : },
1533 :
1534 : // cancel
1535 0 : [](void *data, wl_touch *touch) {
1536 :
1537 0 : },
1538 :
1539 : // shape
1540 0 : [](void *data, wl_touch *touch, int32_t id, wl_fixed_t major, wl_fixed_t minor) {
1541 :
1542 0 : },
1543 :
1544 : // orientation
1545 0 : [](void *data, wl_touch *touch, int32_t id, wl_fixed_t orientation) {
1546 :
1547 0 : }
1548 : };
1549 :
1550 : static struct wl_seat_listener s_WaylandSeatListener{
1551 0 : [] (void *data, struct wl_seat *wl_seat, uint32_t capabilities) {
1552 0 : auto seat = (WaylandSeat *)data;
1553 0 : seat->capabilities = capabilities;
1554 0 : seat->root->seatDirty = true;
1555 :
1556 0 : if ((capabilities & WL_SEAT_CAPABILITY_POINTER) != 0) {
1557 0 : seat->initCursors();
1558 : }
1559 :
1560 0 : seat->update();
1561 0 : },
1562 0 : [] (void *data, struct wl_seat *wl_seat, const char *name) {
1563 0 : auto seat = (WaylandSeat*) data;
1564 0 : seat->name = name;
1565 0 : }
1566 : };
1567 :
1568 0 : WaylandSeat::~WaylandSeat() {
1569 0 : if (state) {
1570 0 : root->xkb->xkb_state_unref(state);
1571 0 : state = nullptr;
1572 : }
1573 0 : if (compose) {
1574 0 : root->xkb->xkb_compose_state_unref(compose);
1575 0 : compose = nullptr;
1576 : }
1577 0 : if (seat) {
1578 0 : wayland->wl_seat_destroy(seat);
1579 0 : seat = nullptr;
1580 : }
1581 0 : }
1582 :
1583 0 : bool WaylandSeat::init(const Rc<WaylandLibrary> &lib, WaylandDisplay *view, wl_registry *registry, uint32_t name, uint32_t version) {
1584 0 : wayland = lib;
1585 0 : root = view;
1586 0 : id = name;
1587 0 : if (version >= 5U) {
1588 0 : hasPointerFrames = true;
1589 : }
1590 0 : seat = static_cast<wl_seat *>(wayland->wl_registry_bind(registry, name,
1591 0 : wayland->wl_seat_interface, std::min(version, 5U)));
1592 0 : wayland->wl_seat_set_user_data(seat, this);
1593 0 : wayland->wl_seat_add_listener(seat, &s_WaylandSeatListener, this);
1594 0 : wayland->wl_proxy_set_tag((struct wl_proxy *) seat, &s_XenolithWaylandTag);
1595 :
1596 0 : keyState.keycodes[KEY_GRAVE] = core::InputKeyCode::GRAVE_ACCENT;
1597 0 : keyState.keycodes[KEY_1] = core::InputKeyCode::_1;
1598 0 : keyState.keycodes[KEY_2] = core::InputKeyCode::_2;
1599 0 : keyState.keycodes[KEY_3] = core::InputKeyCode::_3;
1600 0 : keyState.keycodes[KEY_4] = core::InputKeyCode::_4;
1601 0 : keyState.keycodes[KEY_5] = core::InputKeyCode::_5;
1602 0 : keyState.keycodes[KEY_6] = core::InputKeyCode::_6;
1603 0 : keyState.keycodes[KEY_7] = core::InputKeyCode::_7;
1604 0 : keyState.keycodes[KEY_8] = core::InputKeyCode::_8;
1605 0 : keyState.keycodes[KEY_9] = core::InputKeyCode::_9;
1606 0 : keyState.keycodes[KEY_0] = core::InputKeyCode::_0;
1607 0 : keyState.keycodes[KEY_SPACE] = core::InputKeyCode::SPACE;
1608 0 : keyState.keycodes[KEY_MINUS] = core::InputKeyCode::MINUS;
1609 0 : keyState.keycodes[KEY_EQUAL] = core::InputKeyCode::EQUAL;
1610 0 : keyState.keycodes[KEY_Q] = core::InputKeyCode::Q;
1611 0 : keyState.keycodes[KEY_W] = core::InputKeyCode::W;
1612 0 : keyState.keycodes[KEY_E] = core::InputKeyCode::E;
1613 0 : keyState.keycodes[KEY_R] = core::InputKeyCode::R;
1614 0 : keyState.keycodes[KEY_T] = core::InputKeyCode::T;
1615 0 : keyState.keycodes[KEY_Y] = core::InputKeyCode::Y;
1616 0 : keyState.keycodes[KEY_U] = core::InputKeyCode::U;
1617 0 : keyState.keycodes[KEY_I] = core::InputKeyCode::I;
1618 0 : keyState.keycodes[KEY_O] = core::InputKeyCode::O;
1619 0 : keyState.keycodes[KEY_P] = core::InputKeyCode::P;
1620 0 : keyState.keycodes[KEY_LEFTBRACE] = core::InputKeyCode::LEFT_BRACKET;
1621 0 : keyState.keycodes[KEY_RIGHTBRACE] = core::InputKeyCode::RIGHT_BRACKET;
1622 0 : keyState.keycodes[KEY_A] = core::InputKeyCode::A;
1623 0 : keyState.keycodes[KEY_S] = core::InputKeyCode::S;
1624 0 : keyState.keycodes[KEY_D] = core::InputKeyCode::D;
1625 0 : keyState.keycodes[KEY_F] = core::InputKeyCode::F;
1626 0 : keyState.keycodes[KEY_G] = core::InputKeyCode::G;
1627 0 : keyState.keycodes[KEY_H] = core::InputKeyCode::H;
1628 0 : keyState.keycodes[KEY_J] = core::InputKeyCode::J;
1629 0 : keyState.keycodes[KEY_K] = core::InputKeyCode::K;
1630 0 : keyState.keycodes[KEY_L] = core::InputKeyCode::L;
1631 0 : keyState.keycodes[KEY_SEMICOLON] = core::InputKeyCode::SEMICOLON;
1632 0 : keyState.keycodes[KEY_APOSTROPHE] = core::InputKeyCode::APOSTROPHE;
1633 0 : keyState.keycodes[KEY_Z] = core::InputKeyCode::Z;
1634 0 : keyState.keycodes[KEY_X] = core::InputKeyCode::X;
1635 0 : keyState.keycodes[KEY_C] = core::InputKeyCode::C;
1636 0 : keyState.keycodes[KEY_V] = core::InputKeyCode::V;
1637 0 : keyState.keycodes[KEY_B] = core::InputKeyCode::B;
1638 0 : keyState.keycodes[KEY_N] = core::InputKeyCode::N;
1639 0 : keyState.keycodes[KEY_M] = core::InputKeyCode::M;
1640 0 : keyState.keycodes[KEY_COMMA] = core::InputKeyCode::COMMA;
1641 0 : keyState.keycodes[KEY_DOT] = core::InputKeyCode::PERIOD;
1642 0 : keyState.keycodes[KEY_SLASH] = core::InputKeyCode::SLASH;
1643 0 : keyState.keycodes[KEY_BACKSLASH] = core::InputKeyCode::BACKSLASH;
1644 0 : keyState.keycodes[KEY_ESC] = core::InputKeyCode::ESCAPE;
1645 0 : keyState.keycodes[KEY_TAB] = core::InputKeyCode::TAB;
1646 0 : keyState.keycodes[KEY_LEFTSHIFT] = core::InputKeyCode::LEFT_SHIFT;
1647 0 : keyState.keycodes[KEY_RIGHTSHIFT] = core::InputKeyCode::RIGHT_SHIFT;
1648 0 : keyState.keycodes[KEY_LEFTCTRL] = core::InputKeyCode::LEFT_CONTROL;
1649 0 : keyState.keycodes[KEY_RIGHTCTRL] = core::InputKeyCode::RIGHT_CONTROL;
1650 0 : keyState.keycodes[KEY_LEFTALT] = core::InputKeyCode::LEFT_ALT;
1651 0 : keyState.keycodes[KEY_RIGHTALT] = core::InputKeyCode::RIGHT_ALT;
1652 0 : keyState.keycodes[KEY_LEFTMETA] = core::InputKeyCode::LEFT_SUPER;
1653 0 : keyState.keycodes[KEY_RIGHTMETA] = core::InputKeyCode::RIGHT_SUPER;
1654 0 : keyState.keycodes[KEY_COMPOSE] = core::InputKeyCode::MENU;
1655 0 : keyState.keycodes[KEY_NUMLOCK] = core::InputKeyCode::NUM_LOCK;
1656 0 : keyState.keycodes[KEY_CAPSLOCK] = core::InputKeyCode::CAPS_LOCK;
1657 0 : keyState.keycodes[KEY_PRINT] = core::InputKeyCode::PRINT_SCREEN;
1658 0 : keyState.keycodes[KEY_SCROLLLOCK] = core::InputKeyCode::SCROLL_LOCK;
1659 0 : keyState.keycodes[KEY_PAUSE] = core::InputKeyCode::PAUSE;
1660 0 : keyState.keycodes[KEY_DELETE] = core::InputKeyCode::DELETE;
1661 0 : keyState.keycodes[KEY_BACKSPACE] = core::InputKeyCode::BACKSPACE;
1662 0 : keyState.keycodes[KEY_ENTER] = core::InputKeyCode::ENTER;
1663 0 : keyState.keycodes[KEY_HOME] = core::InputKeyCode::HOME;
1664 0 : keyState.keycodes[KEY_END] = core::InputKeyCode::END;
1665 0 : keyState.keycodes[KEY_PAGEUP] = core::InputKeyCode::PAGE_UP;
1666 0 : keyState.keycodes[KEY_PAGEDOWN] = core::InputKeyCode::PAGE_DOWN;
1667 0 : keyState.keycodes[KEY_INSERT] = core::InputKeyCode::INSERT;
1668 0 : keyState.keycodes[KEY_LEFT] = core::InputKeyCode::LEFT;
1669 0 : keyState.keycodes[KEY_RIGHT] = core::InputKeyCode::RIGHT;
1670 0 : keyState.keycodes[KEY_DOWN] = core::InputKeyCode::DOWN;
1671 0 : keyState.keycodes[KEY_UP] = core::InputKeyCode::UP;
1672 0 : keyState.keycodes[KEY_F1] = core::InputKeyCode::F1;
1673 0 : keyState.keycodes[KEY_F2] = core::InputKeyCode::F2;
1674 0 : keyState.keycodes[KEY_F3] = core::InputKeyCode::F3;
1675 0 : keyState.keycodes[KEY_F4] = core::InputKeyCode::F4;
1676 0 : keyState.keycodes[KEY_F5] = core::InputKeyCode::F5;
1677 0 : keyState.keycodes[KEY_F6] = core::InputKeyCode::F6;
1678 0 : keyState.keycodes[KEY_F7] = core::InputKeyCode::F7;
1679 0 : keyState.keycodes[KEY_F8] = core::InputKeyCode::F8;
1680 0 : keyState.keycodes[KEY_F9] = core::InputKeyCode::F9;
1681 0 : keyState.keycodes[KEY_F10] = core::InputKeyCode::F10;
1682 0 : keyState.keycodes[KEY_F11] = core::InputKeyCode::F11;
1683 0 : keyState.keycodes[KEY_F12] = core::InputKeyCode::F12;
1684 0 : keyState.keycodes[KEY_F13] = core::InputKeyCode::F13;
1685 0 : keyState.keycodes[KEY_F14] = core::InputKeyCode::F14;
1686 0 : keyState.keycodes[KEY_F15] = core::InputKeyCode::F15;
1687 0 : keyState.keycodes[KEY_F16] = core::InputKeyCode::F16;
1688 0 : keyState.keycodes[KEY_F17] = core::InputKeyCode::F17;
1689 0 : keyState.keycodes[KEY_F18] = core::InputKeyCode::F18;
1690 0 : keyState.keycodes[KEY_F19] = core::InputKeyCode::F19;
1691 0 : keyState.keycodes[KEY_F20] = core::InputKeyCode::F20;
1692 0 : keyState.keycodes[KEY_F21] = core::InputKeyCode::F21;
1693 0 : keyState.keycodes[KEY_F22] = core::InputKeyCode::F22;
1694 0 : keyState.keycodes[KEY_F23] = core::InputKeyCode::F23;
1695 0 : keyState.keycodes[KEY_F24] = core::InputKeyCode::F24;
1696 0 : keyState.keycodes[KEY_KPSLASH] = core::InputKeyCode::KP_DIVIDE;
1697 0 : keyState.keycodes[KEY_KPASTERISK] = core::InputKeyCode::KP_MULTIPLY;
1698 0 : keyState.keycodes[KEY_KPMINUS] = core::InputKeyCode::KP_SUBTRACT;
1699 0 : keyState.keycodes[KEY_KPPLUS] = core::InputKeyCode::KP_ADD;
1700 0 : keyState.keycodes[KEY_KP0] = core::InputKeyCode::KP_0;
1701 0 : keyState.keycodes[KEY_KP1] = core::InputKeyCode::KP_1;
1702 0 : keyState.keycodes[KEY_KP2] = core::InputKeyCode::KP_2;
1703 0 : keyState.keycodes[KEY_KP3] = core::InputKeyCode::KP_3;
1704 0 : keyState.keycodes[KEY_KP4] = core::InputKeyCode::KP_4;
1705 0 : keyState.keycodes[KEY_KP5] = core::InputKeyCode::KP_5;
1706 0 : keyState.keycodes[KEY_KP6] = core::InputKeyCode::KP_6;
1707 0 : keyState.keycodes[KEY_KP7] = core::InputKeyCode::KP_7;
1708 0 : keyState.keycodes[KEY_KP8] = core::InputKeyCode::KP_8;
1709 0 : keyState.keycodes[KEY_KP9] = core::InputKeyCode::KP_9;
1710 0 : keyState.keycodes[KEY_KPDOT] = core::InputKeyCode::KP_DECIMAL;
1711 0 : keyState.keycodes[KEY_KPEQUAL] = core::InputKeyCode::KP_EQUAL;
1712 0 : keyState.keycodes[KEY_KPENTER] = core::InputKeyCode::KP_ENTER;
1713 0 : keyState.keycodes[KEY_102ND] = core::InputKeyCode::WORLD_2;
1714 :
1715 0 : return true;
1716 : }
1717 :
1718 : static struct wl_surface_listener cursor_surface_listener = {
1719 0 : [] (void *data, wl_surface *surface, wl_output *output) {
1720 0 : auto seat = (WaylandSeat *)data;
1721 0 : if (!WaylandLibrary::ownsProxy(output)) {
1722 0 : return;
1723 : }
1724 :
1725 0 : auto out = (WaylandOutput *)seat->wayland->wl_output_get_user_data(output);
1726 0 : seat->pointerOutputs.emplace(out);
1727 0 : seat->tryUpdateCursor();
1728 : },
1729 0 : [] (void *data, struct wl_surface *wl_surface, struct wl_output *output) {
1730 0 : auto seat = (WaylandSeat *)data;
1731 0 : if (!WaylandLibrary::ownsProxy(output)) {
1732 0 : return;
1733 : }
1734 :
1735 0 : auto out = (WaylandOutput *)seat->wayland->wl_output_get_user_data(output);
1736 0 : seat->pointerOutputs.erase(out);
1737 : }
1738 : };
1739 :
1740 0 : void WaylandSeat::initCursors() {
1741 0 : auto lib = DBusLibrary::get();
1742 0 : auto theme = lib.getCurrentInterfaceTheme();
1743 :
1744 0 : theme.cursorSize *= pointerScale;
1745 :
1746 0 : if (!cursorTheme || cursorTheme->cursorSize != theme.cursorSize || cursorTheme->cursorName != String(theme.cursorTheme)) {
1747 0 : cursorTheme = Rc<WaylandCursorTheme>::create(root, theme.cursorTheme, theme.cursorSize);
1748 : }
1749 :
1750 0 : if (!cursorSurface) {
1751 0 : cursorSurface = wayland->wl_compositor_create_surface(root->compositor);
1752 0 : wayland->wl_surface_add_listener(cursorSurface, &cursor_surface_listener, this);
1753 : }
1754 0 : }
1755 :
1756 0 : void WaylandSeat::tryUpdateCursor() {
1757 0 : int32_t scale = 1;
1758 :
1759 0 : for (auto &it : pointerOutputs) {
1760 0 : scale = std::max(scale, it->scale);
1761 : }
1762 :
1763 0 : if (scale != pointerScale) {
1764 0 : pointerScale = scale;
1765 0 : initCursors();
1766 0 : if (cursorTheme) {
1767 0 : cursorTheme->setCursor(this);
1768 : }
1769 : }
1770 0 : }
1771 :
1772 0 : void WaylandSeat::update() {
1773 0 : if (!root->seatDirty) {
1774 0 : return;
1775 : }
1776 :
1777 0 : root->seatDirty = false;
1778 :
1779 0 : if ((capabilities & WL_SEAT_CAPABILITY_POINTER) != 0 && !pointer) {
1780 0 : pointer = wayland->wl_seat_get_pointer(seat);
1781 0 : wayland->wl_pointer_add_listener(pointer, &s_WaylandPointerListener, this);
1782 0 : pointerScale = 1;
1783 0 : initCursors();
1784 0 : } else if ((capabilities & WL_SEAT_CAPABILITY_POINTER) == 0 && pointer) {
1785 0 : wayland->wl_pointer_release(pointer);
1786 0 : pointer = NULL;
1787 : }
1788 :
1789 0 : if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) != 0 && !keyboard) {
1790 0 : keyboard = wayland->wl_seat_get_keyboard(seat);
1791 0 : wayland->wl_keyboard_add_listener(keyboard, &s_WaylandKeyboardListener, this);
1792 0 : } else if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) == 0 && keyboard) {
1793 0 : wayland->wl_keyboard_release(keyboard);
1794 0 : keyboard = NULL;
1795 : }
1796 :
1797 0 : if ((capabilities & WL_SEAT_CAPABILITY_TOUCH) != 0 && !touch) {
1798 0 : touch = wayland->wl_seat_get_touch(seat);
1799 0 : wayland->wl_touch_add_listener(touch, &s_WaylandTouchListener, this);
1800 0 : } else if ((capabilities & WL_SEAT_CAPABILITY_TOUCH) == 0 && touch) {
1801 0 : wayland->wl_touch_release(touch);
1802 0 : touch = NULL;
1803 : }
1804 :
1805 : // wayland->wl_display_roundtrip(root->display);
1806 : }
1807 :
1808 0 : core::InputKeyCode WaylandSeat::translateKey(uint32_t scancode) const {
1809 0 : if (scancode < sizeof(keyState.keycodes) / sizeof(keyState.keycodes[0])) {
1810 0 : return keyState.keycodes[scancode];
1811 : }
1812 :
1813 0 : return core::InputKeyCode::Unknown;
1814 : }
1815 :
1816 0 : xkb_keysym_t WaylandSeat::composeSymbol(xkb_keysym_t sym, core::InputKeyComposeState &composeState) const {
1817 0 : if (sym == XKB_KEY_NoSymbol || !compose) {
1818 0 : return sym;
1819 : }
1820 0 : if (root->xkb->xkb_compose_state_feed(compose, sym) != XKB_COMPOSE_FEED_ACCEPTED) {
1821 0 : return sym;
1822 : }
1823 0 : switch (root->xkb->xkb_compose_state_get_status(compose)) {
1824 0 : case XKB_COMPOSE_COMPOSED:
1825 0 : composeState = core::InputKeyComposeState::Composed;
1826 0 : return root->xkb->xkb_compose_state_get_one_sym(compose);
1827 0 : case XKB_COMPOSE_COMPOSING:
1828 0 : composeState = core::InputKeyComposeState::Composing;
1829 0 : return sym;
1830 0 : case XKB_COMPOSE_CANCELLED:
1831 0 : return sym;
1832 0 : case XKB_COMPOSE_NOTHING:
1833 : default:
1834 0 : return sym;
1835 : }
1836 : }
1837 :
1838 0 : WaylandDecoration::~WaylandDecoration() {
1839 0 : if (viewport) {
1840 0 : wayland->wp_viewport_destroy(viewport);
1841 0 : viewport = nullptr;
1842 : }
1843 0 : if (subsurface) {
1844 0 : wayland->wl_subsurface_destroy(subsurface);
1845 0 : subsurface = nullptr;
1846 : }
1847 0 : if (surface) {
1848 0 : display->destroyDecorationSurface(surface);
1849 0 : surface = nullptr;
1850 : }
1851 0 : }
1852 :
1853 0 : bool WaylandDecoration::init(WaylandViewInterface *view, Rc<WaylandBuffer> &&b, Rc<WaylandBuffer> &&a, WaylandDecorationName n) {
1854 0 : root = view;
1855 0 : display = view->getDisplay();
1856 0 : wayland = display->wayland;
1857 0 : surface = display->createDecorationSurface(this);
1858 0 : name = n;
1859 0 : switch (n) {
1860 0 : case WaylandDecorationName::RightSide: image = WaylandCursorImage::RightSide; break;
1861 0 : case WaylandDecorationName::TopRigntCorner: image = WaylandCursorImage::TopRigntCorner; break;
1862 0 : case WaylandDecorationName::TopSide: image = WaylandCursorImage::TopSide; break;
1863 0 : case WaylandDecorationName::TopLeftCorner: image = WaylandCursorImage::TopLeftCorner; break;
1864 0 : case WaylandDecorationName::BottomRightCorner: image = WaylandCursorImage::BottomRightCorner; break;
1865 0 : case WaylandDecorationName::BottomSide: image = WaylandCursorImage::BottomSide; break;
1866 0 : case WaylandDecorationName::BottomLeftCorner: image = WaylandCursorImage::BottomLeftCorner; break;
1867 0 : case WaylandDecorationName::LeftSide: image = WaylandCursorImage::LeftSide; break;
1868 0 : default:
1869 0 : image = WaylandCursorImage::LeftPtr;
1870 0 : break;
1871 : }
1872 0 : buffer = move(b);
1873 0 : if (a) {
1874 0 : active = move(a);
1875 : }
1876 :
1877 0 : auto parent = root->getSurface();
1878 :
1879 0 : subsurface = wayland->wl_subcompositor_get_subsurface(display->subcompositor, surface, parent);
1880 0 : wayland->wl_subsurface_place_below(subsurface, parent);
1881 0 : wayland->wl_subsurface_set_sync(subsurface);
1882 :
1883 0 : viewport = wayland->wp_viewporter_get_viewport(display->viewporter, surface);
1884 0 : wayland->wl_surface_attach(surface, buffer->buffer, 0, 0);
1885 :
1886 0 : dirty = true;
1887 :
1888 0 : return true;
1889 : }
1890 :
1891 0 : bool WaylandDecoration::init(WaylandViewInterface *view, Rc<WaylandBuffer> &&b, WaylandDecorationName n) {
1892 0 : return init(view, move(b), nullptr, n);
1893 : }
1894 :
1895 0 : void WaylandDecoration::setAltBuffers(Rc<WaylandBuffer> &&b, Rc<WaylandBuffer> &&a) {
1896 0 : altBuffer = move(b);
1897 0 : altActive = move(a);
1898 0 : }
1899 :
1900 0 : void WaylandDecoration::handlePress(uint32_t s, uint32_t button, uint32_t state) {
1901 0 : serial = s;
1902 0 : waitForMove = false;
1903 0 : if (isTouchable()) {
1904 0 : if (state == WL_POINTER_BUTTON_STATE_RELEASED && button == BTN_LEFT) {
1905 0 : root->handleDecorationPress(this, serial);
1906 : }
1907 0 : } else if (image == WaylandCursorImage::LeftPtr) {
1908 0 : if (state == WL_POINTER_BUTTON_STATE_RELEASED && button == BTN_LEFT) {
1909 0 : auto n = Time::now().toMicros();
1910 0 : if (n - lastTouch < 500'000) {
1911 0 : root->handleDecorationPress(this, serial, true);
1912 : }
1913 0 : lastTouch = n;
1914 0 : } else if (state == WL_POINTER_BUTTON_STATE_PRESSED && button == BTN_LEFT) {
1915 0 : waitForMove = true;
1916 : //root->handleDecorationPress(this, serial);
1917 : }
1918 : } else {
1919 0 : if (state == WL_POINTER_BUTTON_STATE_PRESSED && button == BTN_LEFT) {
1920 0 : root->handleDecorationPress(this, serial);
1921 : }
1922 : }
1923 0 : }
1924 :
1925 0 : void WaylandDecoration::handleMotion() {
1926 0 : if (waitForMove) {
1927 0 : root->handleDecorationPress(this, serial);
1928 : }
1929 0 : }
1930 :
1931 0 : void WaylandDecoration::onEnter() {
1932 0 : if (isTouchable() && !isActive) {
1933 0 : isActive = true;
1934 0 : auto &b = (active && isActive) ? active : buffer;
1935 0 : wayland->wl_surface_attach(surface, b->buffer, 0, 0);
1936 0 : wayland->wl_surface_damage_buffer(surface, 0, 0, b->width, b->height);
1937 0 : dirty = true;
1938 : }
1939 0 : }
1940 :
1941 0 : void WaylandDecoration::onLeave() {
1942 0 : if (isTouchable() && isActive) {
1943 0 : isActive = false;
1944 0 : auto &b = (active && isActive) ? active : buffer;
1945 0 : wayland->wl_surface_attach(surface, b->buffer, 0, 0);
1946 0 : wayland->wl_surface_damage_buffer(surface, 0, 0, b->width, b->height);
1947 0 : dirty = true;
1948 : }
1949 0 : }
1950 :
1951 0 : void WaylandDecoration::setActive(bool val) {
1952 0 : if (!isTouchable()) {
1953 0 : if (val != isActive) {
1954 0 : isActive = val;
1955 0 : auto &b = (active && isActive) ? active : buffer;
1956 0 : wayland->wl_surface_attach(surface, b->buffer, 0, 0);
1957 0 : wayland->wl_surface_damage_buffer(surface, 0, 0, b->width, b->height);
1958 0 : dirty = true;
1959 : }
1960 : }
1961 0 : }
1962 :
1963 0 : void WaylandDecoration::setVisible(bool val) {
1964 0 : if (val != visible) {
1965 0 : visible = val;
1966 0 : if (visible) {
1967 0 : auto &b = (active && isActive) ? active : buffer;
1968 0 : wayland->wl_surface_attach(surface, b->buffer, 0, 0);
1969 0 : wayland->wl_surface_damage_buffer(surface, 0, 0, b->width, b->height);
1970 : } else {
1971 0 : wayland->wl_surface_attach(surface, nullptr, 0, 0);
1972 : }
1973 0 : dirty = true;
1974 : }
1975 0 : }
1976 :
1977 0 : void WaylandDecoration::setAlternative(bool val) {
1978 0 : if (!altBuffer || !altActive) {
1979 0 : return;
1980 : }
1981 :
1982 0 : if (alternative != val) {
1983 0 : alternative = val;
1984 0 : auto tmpA = move(altBuffer);
1985 0 : auto tmpB = move(altActive);
1986 :
1987 0 : altBuffer = move(buffer);
1988 0 : altActive = move(active);
1989 :
1990 0 : buffer = move(tmpA);
1991 0 : active = move(tmpB);
1992 :
1993 0 : auto &b = (active && isActive) ? active : buffer;
1994 0 : wayland->wl_surface_attach(surface, b->buffer, 0, 0);
1995 0 : wayland->wl_surface_damage_buffer(surface, 0, 0, b->width, b->height);
1996 0 : dirty = true;
1997 0 : }
1998 : }
1999 :
2000 0 : void WaylandDecoration::setGeometry(int32_t x, int32_t y, int32_t width, int32_t height) {
2001 0 : if (_x == x && _y == y && _width == width && _height == height) {
2002 0 : return;
2003 : }
2004 :
2005 0 : _x = x;
2006 0 : _y = y;
2007 0 : _width = width;
2008 0 : _height = height;
2009 :
2010 0 : wayland->wl_subsurface_set_position(subsurface, _x,_y);
2011 0 : wayland->wp_viewport_set_destination(viewport, _width, _height);
2012 :
2013 0 : auto &b = (active && isActive) ? active : buffer;
2014 0 : wayland->wl_surface_damage_buffer(surface, 0, 0, b->width, b->height);
2015 0 : dirty = true;
2016 : }
2017 :
2018 0 : bool WaylandDecoration::commit() {
2019 0 : if (dirty) {
2020 0 : wayland->wl_surface_commit(surface);
2021 0 : dirty = false;
2022 0 : return true;
2023 : }
2024 0 : return false;
2025 : }
2026 :
2027 0 : bool WaylandDecoration::isTouchable() const {
2028 0 : switch (name) {
2029 0 : case WaylandDecorationName::IconClose:
2030 : case WaylandDecorationName::IconMaximize:
2031 : case WaylandDecorationName::IconMinimize:
2032 : case WaylandDecorationName::IconRestore:
2033 0 : return true;
2034 : break;
2035 0 : default:
2036 0 : break;
2037 : }
2038 0 : return false;
2039 : }
2040 :
2041 : }
|