Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/platform/linuxbsd/wayland/wayland_embedder.h
14772 views
1
/**************************************************************************/
2
/* wayland_embedder.h */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#pragma once
32
33
#ifdef WAYLAND_ENABLED
34
35
#ifdef TOOLS_ENABLED
36
37
#include "core/templates/a_hash_map.h"
38
#include "core/templates/pooled_list.h"
39
40
#ifdef SOWRAP_ENABLED
41
#include "wayland/dynwrappers/wayland-client-core-so_wrap.h"
42
#else
43
#include <wayland-client-core.h>
44
#endif
45
46
#include "protocol/wayland.gen.h"
47
48
#include "protocol/linux_dmabuf_v1.gen.h"
49
#include "protocol/xdg_shell.gen.h"
50
51
#include "protocol/commit_timing_v1.gen.h"
52
#include "protocol/cursor_shape.gen.h"
53
#include "protocol/fifo_v1.gen.h"
54
#include "protocol/fractional_scale.gen.h"
55
#include "protocol/godot_embedding_compositor.gen.h"
56
#include "protocol/idle_inhibit.gen.h"
57
#include "protocol/linux_drm_syncobj_v1.gen.h"
58
#include "protocol/linux_explicit_synchronization_unstable_v1.gen.h"
59
#include "protocol/pointer_constraints.gen.h"
60
#include "protocol/pointer_gestures.gen.h"
61
#include "protocol/primary_selection.gen.h"
62
#include "protocol/relative_pointer.gen.h"
63
#include "protocol/tablet.gen.h"
64
#include "protocol/tearing_control_v1.gen.h"
65
#include "protocol/text_input.gen.h"
66
#include "protocol/viewporter.gen.h"
67
#include "protocol/wayland-drm.gen.h"
68
#include "protocol/xdg_activation.gen.h"
69
#include "protocol/xdg_decoration.gen.h"
70
#include "protocol/xdg_foreign_v1.gen.h"
71
#include "protocol/xdg_foreign_v2.gen.h"
72
#include "protocol/xdg_shell.gen.h"
73
#include "protocol/xdg_system_bell.gen.h"
74
#include "protocol/xdg_toplevel_icon.gen.h"
75
76
#include <errno.h>
77
#include <stdint.h>
78
#include <stdio.h>
79
#include <stdlib.h>
80
#include <string.h>
81
#include <sys/socket.h>
82
#include <sys/un.h>
83
84
#include <poll.h>
85
86
#include "core/io/dir_access.h"
87
#include "core/os/thread.h"
88
89
// TODO: Consider resizing the ancillary buffer dynamically.
90
#define EMBED_ANCILLARY_BUF_SIZE 4096
91
92
class WaylandEmbedder {
93
enum class ProxyDirection {
94
CLIENT,
95
COMPOSITOR,
96
};
97
98
enum class MessageStatus {
99
HANDLED,
100
UNHANDLED,
101
INVALID,
102
ERROR,
103
};
104
105
struct msg_info {
106
uint32_t raw_id = 0;
107
uint16_t size = 0;
108
uint16_t opcode = 0;
109
110
pid_t pid = 0;
111
112
ProxyDirection direction = ProxyDirection::CLIENT;
113
114
constexpr size_t words() const { return (size / sizeof(uint32_t)); }
115
};
116
117
struct WaylandObjectData {
118
virtual ~WaylandObjectData() = default;
119
};
120
121
struct WaylandObject {
122
const struct wl_interface *interface = nullptr;
123
int version = 0;
124
125
// Inert, awaiting confirmation from server.
126
bool destroyed = false;
127
128
// Other objects might depend on it and must not be destroyed.
129
bool shared = false;
130
131
WaylandObjectData *data = nullptr;
132
};
133
134
struct WaylandDrmGlobalData : WaylandObjectData {
135
String device;
136
LocalVector<uint32_t> formats;
137
bool authenticated;
138
uint32_t capabilities;
139
};
140
141
struct WaylandShmGlobalData : WaylandObjectData {
142
LocalVector<uint32_t> formats;
143
};
144
145
struct Client {
146
struct GlobalIdInfo {
147
uint32_t id = INVALID_ID;
148
List<uint32_t>::Element *history_elem = nullptr;
149
150
GlobalIdInfo() = default;
151
GlobalIdInfo(uint32_t p_id, List<uint32_t>::Element *p_history_elem) :
152
id(p_id), history_elem(p_history_elem) {}
153
};
154
155
WaylandEmbedder *embedder = nullptr;
156
157
int socket = -1;
158
159
// NOTE: PIDs are not unique per client!
160
pid_t pid = 0;
161
162
// FIXME: Names suck.
163
AHashMap<uint32_t, HashSet<uint32_t>> registry_globals_instances;
164
HashSet<uint32_t> wl_registry_instances;
165
166
List<uint32_t> global_id_history;
167
AHashMap<uint32_t, GlobalIdInfo> global_ids;
168
AHashMap<uint32_t, uint32_t> local_ids;
169
170
// Objects with no equivalent on the real compositor.
171
AHashMap<uint32_t, WaylandObject> fake_objects;
172
173
// Objects which mirror events of a global object.
174
AHashMap<uint32_t, WaylandObject> global_instances;
175
176
uint32_t embedded_client_id = INVALID_ID;
177
uint32_t embedded_window_id = INVALID_ID;
178
179
List<int> fds;
180
181
// Clients obviously expect properly packed server IDs, so we need to allocate
182
// them somehow. This approach mimics the one used in PooledList.
183
uint32_t allocated_server_ids = INVALID_ID;
184
LocalVector<uint32_t> free_server_ids;
185
186
uint32_t get_global_id(uint32_t p_local_id) const { return global_ids.has(p_local_id) ? global_ids[p_local_id].id : INVALID_ID; }
187
uint32_t get_local_id(uint32_t p_global_id) const { return local_ids.has(p_global_id) ? local_ids[p_global_id] : INVALID_ID; }
188
189
uint32_t allocate_server_id();
190
WaylandObject *get_object(uint32_t p_local_id);
191
Error delete_object(uint32_t p_local_id);
192
193
Error bind_global_id(uint32_t p_global_id, uint32_t p_local_id);
194
195
uint32_t new_object(uint32_t p_local_id, const struct wl_interface *p_interface, int p_version = 1, WaylandObjectData *p_data = nullptr);
196
uint32_t new_server_object(uint32_t p_global_id, const struct wl_interface *p_interface, int p_version = 1, WaylandObjectData *p_data = nullptr);
197
WaylandObject *new_fake_object(uint32_t p_local_id, const struct wl_interface *p_interface, int p_version = 1, WaylandObjectData *p_data = nullptr);
198
WaylandObject *new_global_instance(uint32_t p_local_id, uint32_t p_global_id, const struct wl_interface *p_interface, int p_version = 1, WaylandObjectData *p_data = nullptr);
199
200
Error send_wl_drm_state(uint32_t p_id, WaylandDrmGlobalData *p_state);
201
};
202
203
// Local IDs are a mess to handle as they strictly depend on their client of
204
// origin. This wrapper helps with that.
205
class LocalObjectHandle {
206
Client *client = nullptr;
207
uint32_t local_id = INVALID_ID;
208
209
public:
210
constexpr LocalObjectHandle() = default;
211
212
constexpr LocalObjectHandle(Client *p_client, uint32_t p_id) :
213
client(p_client), local_id(p_id) {}
214
215
void invalidate() {
216
client = nullptr;
217
local_id = INVALID_ID;
218
}
219
constexpr bool is_valid() const { return client != nullptr && local_id != INVALID_ID; }
220
221
WaylandObject *get() { return is_valid() ? client->get_object(local_id) : nullptr; }
222
constexpr Client *get_client() const { return client; }
223
constexpr uint32_t get_local_id() const { return local_id; }
224
uint32_t get_global_id() const { return (is_valid() && client->global_ids.has(local_id)) ? client->global_ids[local_id].id : INVALID_ID; }
225
};
226
227
struct WaylandSeatInstanceData : WaylandObjectData {
228
uint32_t wl_keyboard_id = INVALID_ID;
229
uint32_t wl_pointer_id = INVALID_ID;
230
};
231
232
struct WaylandSeatGlobalData : WaylandObjectData {
233
uint32_t capabilities = 0;
234
235
uint32_t pointed_surface_id = INVALID_ID;
236
uint32_t focused_surface_id = INVALID_ID;
237
};
238
239
struct WaylandKeyboardData : WaylandObjectData {
240
uint32_t wl_seat_id = INVALID_ID;
241
};
242
243
struct WaylandPointerData : WaylandObjectData {
244
uint32_t wl_seat_id = INVALID_ID;
245
};
246
247
struct WaylandSurfaceData : WaylandObjectData {
248
Client *client = nullptr;
249
LocalObjectHandle role_object_handle;
250
};
251
252
struct XdgSurfaceData : WaylandObjectData {
253
uint32_t wl_surface_id = INVALID_ID;
254
};
255
256
struct WaylandSubsurfaceData : WaylandObjectData {
257
Point2i position;
258
};
259
260
struct XdgToplevelData : WaylandObjectData {
261
LocalObjectHandle xdg_surface_handle;
262
LocalObjectHandle parent_handle;
263
uint32_t wl_subsurface_id = INVALID_ID;
264
265
Size2i size;
266
267
bool configured = false;
268
269
constexpr bool is_embedded() const { return wl_subsurface_id != INVALID_ID; }
270
};
271
272
struct XdgPopupData : WaylandObjectData {
273
LocalObjectHandle parent_handle;
274
};
275
276
struct XdgPositionerData : WaylandObjectData {
277
Rect2i anchor_rect;
278
};
279
280
struct EmbeddedClientData : WaylandObjectData {
281
Client *client = nullptr;
282
bool disconnected = false;
283
};
284
285
struct RegistryGlobalInfo {
286
const struct wl_interface *interface = nullptr;
287
uint32_t version = 0;
288
uint32_t compositor_name = 0;
289
290
// The specs requires for us to ignore requests for destroyed global
291
// objects until all instances are gone, to avoid races.
292
bool destroyed = false;
293
int instance_counter = 0;
294
295
// Key is version.
296
HashMap<uint32_t, uint32_t> reusable_objects;
297
298
WaylandObjectData *data = nullptr;
299
};
300
301
// These are the interfaces that the embedder understands and exposes. We do
302
// not implement handlers for all of them (that's the point), but we need to
303
// list them anyways to query their signatures at runtime, which include file
304
// descriptors count. Additionally, even if we could go without specifying
305
// them, having a "known good" list avoids unpleasant incompatibilities with
306
// future compositors.
307
const static constexpr struct wl_interface *interfaces[] = {
308
// wayland
309
&wl_buffer_interface,
310
&wl_callback_interface,
311
&wl_compositor_interface,
312
&wl_data_device_interface,
313
&wl_data_device_manager_interface,
314
&wl_data_offer_interface,
315
&wl_data_source_interface,
316
&wl_display_interface,
317
&wl_keyboard_interface,
318
&wl_output_interface,
319
&wl_pointer_interface,
320
&wl_region_interface,
321
&wl_registry_interface,
322
&wl_seat_interface,
323
//&wl_shell_interface, // Deprecated.
324
//&wl_shell_surface_interface, // Deprecated.
325
&wl_shm_interface,
326
&wl_shm_pool_interface,
327
&wl_subcompositor_interface,
328
&wl_subsurface_interface,
329
&wl_surface_interface,
330
//&wl_touch_interface, // Unused (at the moment).
331
332
// xdg-shell
333
&xdg_wm_base_interface,
334
&xdg_positioner_interface,
335
&xdg_surface_interface,
336
&xdg_toplevel_interface,
337
&xdg_popup_interface,
338
339
// linux-dmabuf-v1
340
&zwp_linux_dmabuf_v1_interface,
341
&zwp_linux_buffer_params_v1_interface,
342
&zwp_linux_dmabuf_feedback_v1_interface,
343
344
// linux-explicit-synchronization-unstable-v1
345
&zwp_linux_explicit_synchronization_v1_interface,
346
&zwp_linux_surface_synchronization_v1_interface,
347
&zwp_linux_buffer_release_v1_interface,
348
349
// fractional-scale
350
&wp_fractional_scale_manager_v1_interface,
351
&wp_fractional_scale_v1_interface,
352
353
// idle-inhibit
354
&zwp_idle_inhibit_manager_v1_interface,
355
&zwp_idle_inhibitor_v1_interface,
356
357
// pointer-constraints
358
&zwp_pointer_constraints_v1_interface,
359
&zwp_locked_pointer_v1_interface,
360
&zwp_confined_pointer_v1_interface,
361
362
// pointer-gestures
363
&zwp_pointer_gestures_v1_interface,
364
&zwp_pointer_gesture_swipe_v1_interface,
365
&zwp_pointer_gesture_pinch_v1_interface,
366
&zwp_pointer_gesture_hold_v1_interface,
367
368
// primary-selection
369
&zwp_primary_selection_device_manager_v1_interface,
370
&zwp_primary_selection_device_v1_interface,
371
&zwp_primary_selection_offer_v1_interface,
372
&zwp_primary_selection_source_v1_interface,
373
374
// relative-pointer
375
&zwp_relative_pointer_manager_v1_interface,
376
&zwp_relative_pointer_v1_interface,
377
378
// tablet
379
// TODO: Needs some extra work
380
//&zwp_tablet_manager_v2_interface,
381
//&zwp_tablet_seat_v2_interface,
382
//&zwp_tablet_tool_v2_interface,
383
//&zwp_tablet_v2_interface,
384
//&zwp_tablet_pad_ring_v2_interface,
385
//&zwp_tablet_pad_strip_v2_interface,
386
//&zwp_tablet_pad_group_v2_interface,
387
//&zwp_tablet_pad_v2_interface,
388
389
// text-input
390
&zwp_text_input_v3_interface,
391
&zwp_text_input_manager_v3_interface,
392
393
// viewporter
394
&wp_viewporter_interface,
395
&wp_viewport_interface,
396
397
// xdg-activation
398
&xdg_activation_v1_interface,
399
&xdg_activation_token_v1_interface,
400
401
// xdg-decoration
402
&zxdg_decoration_manager_v1_interface,
403
&zxdg_toplevel_decoration_v1_interface,
404
405
// xdg-foreign
406
&zxdg_exporter_v1_interface,
407
&zxdg_importer_v1_interface,
408
409
// xdg-foreign-v1
410
&zxdg_exporter_v1_interface,
411
&zxdg_importer_v1_interface,
412
413
// xdg-foreign-v2
414
&zxdg_exporter_v2_interface,
415
&zxdg_importer_v2_interface,
416
417
// xdg-shell
418
&xdg_wm_base_interface,
419
&xdg_positioner_interface,
420
&xdg_surface_interface,
421
&xdg_toplevel_interface,
422
&xdg_popup_interface,
423
424
// xdg-system-bell
425
&xdg_system_bell_v1_interface,
426
427
// xdg-toplevel-icon-v1
428
&xdg_toplevel_icon_manager_v1_interface,
429
&xdg_toplevel_icon_v1_interface,
430
431
// wp-cursor-shape-v1
432
&wp_cursor_shape_manager_v1_interface,
433
434
// wayland-drm
435
&wl_drm_interface,
436
437
// linux-drm-syncobj-v1
438
&wp_linux_drm_syncobj_manager_v1_interface,
439
&wp_linux_drm_syncobj_surface_v1_interface,
440
&wp_linux_drm_syncobj_timeline_v1_interface,
441
442
// fifo-v1
443
&wp_fifo_manager_v1_interface,
444
&wp_fifo_v1_interface,
445
446
// commit-timing-v1
447
&wp_commit_timing_manager_v1_interface,
448
&wp_commit_timer_v1_interface,
449
450
// tearing-control-v1
451
&wp_tearing_control_manager_v1_interface,
452
&wp_tearing_control_v1_interface,
453
454
// Our custom things.
455
&godot_embedding_compositor_interface,
456
&godot_embedded_client_interface,
457
};
458
459
// These interfaces will not be reported to embedded clients. This includes
460
// stuff that interacts with toplevels or other emulated objects that would
461
// have been filtered out manually anyways.
462
HashSet<const struct wl_interface *> embedded_interface_deny_list = HashSet({
463
&zxdg_decoration_manager_v1_interface,
464
&zxdg_decoration_manager_v1_interface,
465
&zxdg_exporter_v1_interface,
466
&zxdg_exporter_v2_interface,
467
&xdg_toplevel_icon_manager_v1_interface,
468
&godot_embedding_compositor_interface,
469
});
470
471
static constexpr uint32_t INVALID_ID = 0;
472
static constexpr uint32_t DISPLAY_ID = 1;
473
static constexpr uint32_t REGISTRY_ID = 2;
474
475
int proxy_socket = -1;
476
int compositor_socket = -1;
477
478
// NOTE: First element must be the listening socket! This allows us to process
479
// it last, cleaning up closed sockets before it reuses their handles.
480
LocalVector<struct pollfd> pollfds;
481
482
// Key is socket.
483
AHashMap<int, Client> clients;
484
485
Client *main_client = nullptr;
486
487
PooledList<WaylandObject> objects;
488
// Proxies allocated by the compositor. Their ID starts from 0xff000000.
489
LocalVector<WaylandObject> server_objects;
490
491
uint32_t wl_compositor_id = 0;
492
uint32_t wl_subcompositor_id = 0;
493
uint32_t main_toplevel_id = 0;
494
uint32_t xdg_wm_base_id = 0;
495
496
// Global id to name
497
HashMap<uint32_t, uint32_t> registry_globals_names;
498
499
HashMap<uint32_t, RegistryGlobalInfo> registry_globals;
500
uint32_t registry_globals_counter = 0;
501
502
uint32_t godot_embedding_compositor_name = 0;
503
504
LocalVector<uint32_t> wl_seat_names;
505
506
Thread proxy_thread;
507
508
List<int> client_fds;
509
List<int> compositor_fds;
510
511
uint32_t serial_counter = 0;
512
uint32_t configure_serial_counter = 0;
513
514
uint32_t sync_callback_id = 0;
515
516
Ref<DirAccess> runtime_dir;
517
int lock_fd = -1;
518
String socket_path;
519
String socket_lock_path;
520
521
LocalVector<uint32_t> msg_buf;
522
LocalVector<uint8_t> ancillary_buf;
523
524
SafeFlag thread_done;
525
526
static size_t wl_array_word_offset(uint32_t p_size);
527
const static struct wl_interface *wl_interface_from_string(const char *name, size_t size);
528
static int wl_interface_get_destructor_opcode(const struct wl_interface *p_iface, uint32_t p_version);
529
530
static Error send_raw_message(int p_socket, std::initializer_list<struct iovec> p_vecs, const LocalVector<int> &p_fds = LocalVector<int>());
531
532
static Error send_wayland_message(int p_socket, uint32_t p_id, uint32_t p_opcode, const uint32_t *p_args, const size_t p_args_words);
533
static Error send_wayland_message(ProxyDirection p_direction, int p_socket, uint32_t p_id, const struct wl_interface &p_interface, uint32_t p_opcode, const LocalVector<union wl_argument> &p_args);
534
535
// Utility aliases.
536
537
static Error send_wayland_message(int p_socket, uint32_t p_id, uint32_t p_opcode, std::initializer_list<uint32_t> p_args) {
538
return send_wayland_message(p_socket, p_id, p_opcode, p_args.begin(), p_args.size());
539
}
540
541
static Error send_wayland_method(int p_socket, uint32_t p_id, const struct wl_interface &p_interface, uint32_t p_opcode, const LocalVector<union wl_argument> &p_args) {
542
return send_wayland_message(ProxyDirection::COMPOSITOR, p_socket, p_id, p_interface, p_opcode, p_args);
543
}
544
545
static Error send_wayland_event(int p_socket, uint32_t p_id, const struct wl_interface &p_interface, uint32_t p_opcode, const LocalVector<union wl_argument> &p_args) {
546
return send_wayland_message(ProxyDirection::CLIENT, p_socket, p_id, p_interface, p_opcode, p_args);
547
}
548
549
// Closes the socket.
550
static void socket_error(int p_socket, uint32_t p_object_id, uint32_t p_code, const String &p_message);
551
552
// NOTE: Yes, in our case object arguments are actually uints for now.
553
// Best way I found to reuse the Wayland stuff. Might need to make our
554
// own eventually.
555
static constexpr union wl_argument wl_arg_int(int32_t p_value) {
556
union wl_argument arg = {};
557
arg.i = p_value;
558
return arg;
559
}
560
static constexpr union wl_argument wl_arg_uint(uint32_t p_value) {
561
union wl_argument arg = {};
562
arg.u = p_value;
563
return arg;
564
}
565
static constexpr union wl_argument wl_arg_fixed(wl_fixed_t p_value) {
566
union wl_argument arg = {};
567
arg.f = p_value;
568
return arg;
569
}
570
static constexpr union wl_argument wl_arg_string(const char *p_value) {
571
union wl_argument arg = {};
572
arg.s = p_value;
573
return arg;
574
}
575
static constexpr union wl_argument wl_arg_object(uint32_t p_value) {
576
union wl_argument arg = {};
577
arg.u = p_value;
578
return arg;
579
}
580
static constexpr union wl_argument wl_arg_new_id(uint32_t p_value) {
581
union wl_argument arg = {};
582
arg.n = p_value;
583
return arg;
584
}
585
586
uint32_t new_object(const struct wl_interface *p_interface, int p_version = 1, WaylandObjectData *p_data = nullptr);
587
WaylandObject *new_server_object(uint32_t p_global_id, const struct wl_interface *p_interface, int p_version = 1, WaylandObjectData *p_data = nullptr);
588
589
void poll_sockets();
590
591
int allocate_global_id();
592
593
bool global_surface_is_window(uint32_t p_global_surface_id);
594
595
WaylandObject *get_object(uint32_t id);
596
Error delete_object(uint32_t id);
597
598
void cleanup_socket(int p_socket);
599
600
void sync();
601
602
uint32_t wl_registry_bind(uint32_t p_registry_id, uint32_t p_name, int p_version);
603
604
void seat_name_enter_surface(uint32_t p_seat_name, uint32_t p_global_surface_id);
605
void seat_name_leave_surface(uint32_t p_seat_name, uint32_t p_global_surface_id);
606
607
MessageStatus handle_request(LocalObjectHandle p_object, uint32_t p_opcode, const uint32_t *msg_data, size_t msg_len);
608
MessageStatus handle_event(uint32_t p_global_id, LocalObjectHandle p_local_handle, uint32_t p_opcode, const uint32_t *msg_data, size_t msg_len);
609
610
void shutdown();
611
612
bool handle_generic_msg(Client *client, const WaylandObject *p_object, const struct wl_message *message, const struct msg_info *info, uint32_t *buf, uint32_t instance_id = INVALID_ID);
613
Error handle_msg_info(Client *client, const struct msg_info *info, uint32_t *buf, int *fds_requested);
614
Error handle_sock(int p_fd);
615
void handle_fd(int p_fd, int p_revents);
616
617
static void _thread_loop(void *p_data);
618
619
public:
620
// Returns path to socket.
621
Error init();
622
623
String get_socket_path() const { return socket_path; }
624
625
~WaylandEmbedder();
626
};
627
628
#endif // TOOLS_ENABLED
629
630
#endif // WAYLAND_ENABLED
631
632