Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/platform/linuxbsd/wayland/wayland_embedder.cpp
14772 views
1
/**************************************************************************/
2
/* wayland_embedder.cpp */
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
#include "wayland_embedder.h"
32
33
#ifdef WAYLAND_ENABLED
34
35
#ifdef TOOLS_ENABLED
36
37
#include <sys/stat.h>
38
39
#ifdef __FreeBSD__
40
#include <dev/evdev/input-event-codes.h>
41
#else
42
// Assume Linux.
43
#include <linux/input-event-codes.h>
44
#endif
45
46
#include "core/os/os.h"
47
48
#include <fcntl.h>
49
#include <sys/file.h>
50
#include <unistd.h>
51
52
#define WAYLAND_EMBED_ID_MAX 1000
53
54
//#define WAYLAND_EMBED_DEBUG_LOGS_ENABLED
55
#ifdef WAYLAND_EMBED_DEBUG_LOGS_ENABLED
56
57
// Gotta flush as we're doing this mess from a thread without any
58
// synchronization. It's awful, I know, but the `print_*` utilities hang for
59
// some reason during editor startup and I need some quick and dirty debugging.
60
#define DEBUG_LOG_WAYLAND_EMBED(...) \
61
if (1) { \
62
printf("[PROXY] %s\n", vformat(__VA_ARGS__).utf8().ptr()); \
63
fflush(stdout); \
64
} else \
65
((void)0)
66
67
#else
68
#define DEBUG_LOG_WAYLAND_EMBED(...)
69
#endif
70
71
// Wayland messages are structured with 32-bit words.
72
#define WL_WORD_SIZE (sizeof(uint32_t))
73
74
// Event opcodes. Request opcodes are defined in the generated client headers.
75
// We could generate server headers but they would clash (without modifications)
76
// and we use just a few constants anyways.
77
78
#define WL_DISPLAY_ERROR 0
79
#define WL_DISPLAY_DELETE_ID 1
80
81
#define WL_REGISTRY_GLOBAL 0
82
#define WL_REGISTRY_GLOBAL_REMOVE 1
83
84
#define WL_CALLBACK_DONE 0
85
86
#define WL_KEYBOARD_ENTER 1
87
#define WL_KEYBOARD_LEAVE 2
88
#define WL_KEYBOARD_KEY 3
89
90
#define WL_POINTER_ENTER 0
91
#define WL_POINTER_LEAVE 1
92
#define WL_POINTER_BUTTON 3
93
94
#define WL_SHM_FORMAT 0
95
96
#define WL_DRM_DEVICE 0
97
#define WL_DRM_FORMAT 1
98
#define WL_DRM_AUTHENTICATED 2
99
#define WL_DRM_CAPABILITIES 3
100
101
#define XDG_POPUP_CONFIGURE 0
102
103
size_t WaylandEmbedder::wl_array_word_offset(uint32_t p_size) {
104
uint32_t pad = (WL_WORD_SIZE - (p_size % WL_WORD_SIZE)) % WL_WORD_SIZE;
105
return (p_size + pad) / WL_WORD_SIZE;
106
}
107
108
const struct wl_interface *WaylandEmbedder::wl_interface_from_string(const char *name, size_t size) {
109
for (size_t i = 0; i < (sizeof interfaces / sizeof *interfaces); ++i) {
110
if (strncmp(name, interfaces[i]->name, size) == 0) {
111
return interfaces[i];
112
}
113
}
114
115
return nullptr;
116
}
117
118
int WaylandEmbedder::wl_interface_get_destructor_opcode(const struct wl_interface *p_iface, uint32_t version) {
119
ERR_FAIL_NULL_V(p_iface, -1);
120
121
// FIXME: Figure out how to extract the destructor from the XML files. This
122
// value is not currently exposed by wayland-scanner.
123
for (int i = 0; i < p_iface->method_count; ++i) {
124
const struct wl_message &m = p_iface->methods[i];
125
uint32_t destructor_version = String::to_int(m.signature);
126
if (destructor_version <= version && (strcmp(m.name, "destroy") == 0 || strcmp(m.name, "release") == 0)) {
127
return i;
128
}
129
}
130
131
return -1;
132
}
133
134
struct WaylandEmbedder::WaylandObject *WaylandEmbedder::get_object(uint32_t p_global_id) {
135
if (p_global_id == 0) {
136
return nullptr;
137
}
138
139
// Server-allocated stuff starts at 0xff000000.
140
bool is_server = p_global_id & 0xff000000;
141
if (is_server) {
142
p_global_id &= ~(0xff000000);
143
}
144
145
#ifdef DEV_ENABLED
146
if (p_global_id >= WAYLAND_EMBED_ID_MAX) {
147
// Oh no. Time for debug info!
148
149
#ifdef WAYLAND_EMBED_DEBUG_LOGS_ENABLED
150
for (uint32_t id = 1; id < objects.reserved_size(); ++id) {
151
WaylandObject &object = objects[id];
152
DEBUG_LOG_WAYLAND_EMBED(vformat(" - g0x%x (#%d): %s version %d, data 0x%x", id, id, object.interface->name, object.version, (uintptr_t)object.data));
153
}
154
#endif // WAYLAND_EMBED_DEBUG_LOGS_ENABLED
155
156
CRASH_NOW_MSG(vformat("Tried to access ID bigger than debug cap (%d > %d).", p_global_id, WAYLAND_EMBED_ID_MAX));
157
}
158
#endif // DEV_ENABLED
159
160
if (is_server) {
161
if (server_objects.size() <= p_global_id) {
162
return nullptr;
163
}
164
165
return &server_objects[p_global_id];
166
} else {
167
if (objects.reserved_size() <= p_global_id) {
168
return nullptr;
169
}
170
171
return &objects[p_global_id];
172
}
173
}
174
175
Error WaylandEmbedder::delete_object(uint32_t p_global_id) {
176
WaylandObject *object = get_object(p_global_id);
177
ERR_FAIL_NULL_V(object, ERR_DOES_NOT_EXIST);
178
179
if (object->shared) {
180
ERR_FAIL_V_MSG(FAILED, vformat("Tried to delete shared object g0x%x.", p_global_id));
181
}
182
183
DEBUG_LOG_WAYLAND_EMBED(vformat("Deleting object %s g0x%x", object->interface ? object->interface->name : "UNKNOWN", p_global_id));
184
185
if (object->data) {
186
memdelete(object->data);
187
object->data = nullptr;
188
}
189
190
bool is_server = p_global_id & 0xff000000;
191
if (is_server) {
192
server_objects[p_global_id & ~(0xff000000)] = WaylandObject();
193
} else {
194
objects.free(p_global_id);
195
}
196
197
registry_globals_names.erase(p_global_id);
198
199
return OK;
200
}
201
202
uint32_t WaylandEmbedder::Client::allocate_server_id() {
203
uint32_t new_id = INVALID_ID;
204
205
if (free_server_ids.size() > 0) {
206
int new_size = free_server_ids.size() - 1;
207
new_id = free_server_ids[new_size] | 0xff000000;
208
free_server_ids.resize_uninitialized(new_size);
209
} else {
210
new_id = allocated_server_ids | 0xff000000;
211
212
++allocated_server_ids;
213
#ifdef DEV_ENABLED
214
CRASH_COND_MSG(allocated_server_ids > WAYLAND_EMBED_ID_MAX, "Max server ID reached. This might indicate a leak.");
215
#endif // DEV_ENABLED
216
}
217
218
DEBUG_LOG_WAYLAND_EMBED(vformat("Allocated server-side id 0x%x.", new_id));
219
220
return new_id;
221
}
222
223
struct WaylandEmbedder::WaylandObject *WaylandEmbedder::Client::get_object(uint32_t p_local_id) {
224
if (p_local_id == INVALID_ID) {
225
return nullptr;
226
}
227
228
if (global_instances.has(p_local_id)) {
229
return &global_instances[p_local_id];
230
}
231
232
if (fake_objects.has(p_local_id)) {
233
return &fake_objects[p_local_id];
234
}
235
236
if (!global_ids.has(p_local_id)) {
237
return nullptr;
238
}
239
240
ERR_FAIL_NULL_V(embedder, nullptr);
241
return embedder->get_object(get_global_id(p_local_id));
242
}
243
244
Error WaylandEmbedder::Client::bind_global_id(uint32_t p_global_id, uint32_t p_local_id) {
245
ERR_FAIL_COND_V(local_ids.has(p_global_id), ERR_ALREADY_EXISTS);
246
ERR_FAIL_COND_V(global_ids.has(p_local_id), ERR_ALREADY_EXISTS);
247
248
GlobalIdInfo gid_info;
249
gid_info.id = p_global_id;
250
DEBUG_LOG_WAYLAND_EMBED(vformat("Pushing g0x%x in the global id history", p_global_id));
251
gid_info.history_elem = global_id_history.push_back(p_global_id);
252
global_ids[p_local_id] = gid_info;
253
254
local_ids[p_global_id] = p_local_id;
255
256
return OK;
257
}
258
259
Error WaylandEmbedder::Client::delete_object(uint32_t p_local_id) {
260
if (fake_objects.has(p_local_id)) {
261
#ifdef WAYLAND_EMBED_DEBUG_LOGS_ENABLED
262
WaylandObject *object = &fake_objects[p_local_id];
263
DEBUG_LOG_WAYLAND_EMBED(vformat("Deleting fake object %s l0x%x", object->interface ? object->interface->name : "UNKNOWN", p_local_id));
264
#endif
265
266
if (!(p_local_id & 0xff000000)) {
267
// wl_display::delete_id
268
send_wayland_message(socket, DISPLAY_ID, 1, { p_local_id });
269
}
270
271
fake_objects.erase(p_local_id);
272
273
// We can skip everything else below, as fake objects don't have a global id.
274
return OK;
275
}
276
277
ERR_FAIL_COND_V(!global_ids.has(p_local_id), ERR_DOES_NOT_EXIST);
278
GlobalIdInfo gid_info = global_ids[p_local_id];
279
uint32_t global_id = gid_info.id;
280
281
DEBUG_LOG_WAYLAND_EMBED(vformat("Erasing g0x%x from the global id history", global_id));
282
global_id_history.erase(gid_info.history_elem);
283
284
if (global_instances.has(p_local_id)) {
285
#ifdef WAYLAND_EMBED_DEBUG_LOGS_ENABLED
286
WaylandObject *object = &global_instances[p_local_id];
287
DEBUG_LOG_WAYLAND_EMBED(vformat("Deleting global instance %s l0x%x", object->interface ? object->interface->name : "UNKNOWN", p_local_id));
288
#endif
289
290
// wl_display::delete_id
291
send_wayland_message(socket, DISPLAY_ID, 1, { p_local_id });
292
293
// We don't want to delete the global object tied to this instance, so we'll only get rid of the local stuff.
294
global_instances.erase(p_local_id);
295
global_ids.erase(p_local_id);
296
297
if (global_id != INVALID_ID) {
298
local_ids.erase(global_id);
299
}
300
301
// We're done here.
302
return OK;
303
}
304
305
if (wl_registry_instances.has(p_local_id)) {
306
wl_registry_instances.erase(p_local_id);
307
}
308
309
WaylandObject *object = embedder->get_object(global_id);
310
ERR_FAIL_NULL_V(object, ERR_DOES_NOT_EXIST);
311
312
ERR_FAIL_COND_V_MSG(object->shared, ERR_INVALID_PARAMETER, vformat("Tried to delete shared object g0x%x.", global_id));
313
314
global_ids.erase(p_local_id);
315
local_ids.erase(global_id);
316
317
if (p_local_id & 0xff000000) {
318
free_server_ids.push_back(p_local_id & ~(0xff000000));
319
}
320
321
uint32_t *global_name = embedder->registry_globals_names.getptr(global_id);
322
if (global_name) {
323
{
324
RegistryGlobalInfo &info = embedder->registry_globals[*global_name];
325
ERR_FAIL_COND_V_MSG(info.instance_counter == 0, ERR_BUG, "Instance counter inconsistency.");
326
--info.instance_counter;
327
328
if (info.destroyed && info.instance_counter == 0) {
329
embedder->registry_globals.erase(*global_name);
330
}
331
}
332
333
registry_globals_instances[*global_name].erase(p_local_id);
334
}
335
336
return embedder->delete_object(global_id);
337
}
338
339
// Returns INVALID_ID if the creation fails. In that case, the user can assume
340
// that the client got kicked out.
341
uint32_t WaylandEmbedder::Client::new_object(uint32_t p_local_id, const struct wl_interface *p_interface, int p_version, WaylandObjectData *p_data) {
342
if (embedder == nullptr) {
343
socket_error(socket, p_local_id, WL_DISPLAY_ERROR_IMPLEMENTATION, "No embedder set.");
344
ERR_FAIL_V(INVALID_ID);
345
}
346
347
if (get_object(p_local_id) != nullptr) {
348
socket_error(socket, p_local_id, WL_DISPLAY_ERROR_IMPLEMENTATION, vformat("Tried to create %s l0x%x but it already exists as %s", p_interface->name, p_local_id, get_object(p_local_id)->interface->name));
349
ERR_FAIL_V(INVALID_ID);
350
}
351
352
uint32_t new_global_id = embedder->new_object(p_interface, p_version, p_data);
353
354
bind_global_id(new_global_id, p_local_id);
355
356
return new_global_id;
357
}
358
359
uint32_t WaylandEmbedder::Client::new_server_object(uint32_t p_global_id, const struct wl_interface *p_interface, int p_version, WaylandObjectData *p_data) {
360
if (embedder == nullptr) {
361
socket_error(socket, get_local_id(p_global_id), WL_DISPLAY_ERROR_IMPLEMENTATION, "No embedder set.");
362
ERR_FAIL_V(INVALID_ID);
363
}
364
365
uint32_t new_local_id = allocate_server_id();
366
367
embedder->new_server_object(p_global_id, p_interface, p_version, p_data);
368
369
bind_global_id(p_global_id, new_local_id);
370
371
return new_local_id;
372
}
373
374
WaylandEmbedder::WaylandObject *WaylandEmbedder::Client::new_fake_object(uint32_t p_local_id, const struct wl_interface *p_interface, int p_version, WaylandObjectData *p_data) {
375
if (embedder == nullptr) {
376
socket_error(socket, p_local_id, WL_DISPLAY_ERROR_IMPLEMENTATION, "No embedder set.");
377
ERR_FAIL_V(nullptr);
378
}
379
380
if (get_object(p_local_id) != nullptr) {
381
socket_error(socket, p_local_id, WL_DISPLAY_ERROR_IMPLEMENTATION, vformat("Object l0x%x already exists", p_local_id));
382
ERR_FAIL_V(nullptr);
383
}
384
385
WaylandObject &new_object = fake_objects[p_local_id];
386
new_object.interface = p_interface;
387
new_object.version = p_version;
388
new_object.data = p_data;
389
390
return &new_object;
391
}
392
393
WaylandEmbedder::WaylandObject *WaylandEmbedder::Client::new_global_instance(uint32_t p_local_id, uint32_t p_global_id, const struct wl_interface *p_interface, int p_version, WaylandObjectData *p_data) {
394
if (embedder == nullptr) {
395
socket_error(socket, p_local_id, WL_DISPLAY_ERROR_IMPLEMENTATION, "No embedder set.");
396
ERR_FAIL_V(nullptr);
397
}
398
399
if (get_object(p_local_id) != nullptr) {
400
socket_error(socket, p_local_id, WL_DISPLAY_ERROR_IMPLEMENTATION, vformat("Object l0x%x already exists", p_local_id));
401
ERR_FAIL_V(nullptr);
402
}
403
404
WaylandObject &new_object = global_instances[p_local_id];
405
new_object.interface = p_interface;
406
new_object.version = p_version;
407
new_object.data = p_data;
408
409
// FIXME: Track each instance properly. Global instances (the compatibility
410
// mechanism) are particular as they're the only case where a global ID might
411
// map to multiple local objects. In that case we need to mirror each event
412
// which passes a registry object as an argument for each instance.
413
GlobalIdInfo gid_info;
414
gid_info.id = p_global_id;
415
gid_info.history_elem = global_id_history.push_back(p_global_id);
416
global_ids[p_local_id] = gid_info;
417
418
// NOTE: Normally, for each client, there's a single local object per global
419
// object, but global instances break this expectation. This is technically
420
// wrong but should work fine, as we have special logic whenever needed.
421
//
422
// TODO: it might be nice to enforce that this table is never looked up for
423
// global instances or even just log attempts.
424
local_ids[p_global_id] = p_local_id;
425
426
return &new_object;
427
}
428
429
Error WaylandEmbedder::Client::send_wl_drm_state(uint32_t p_id, WaylandDrmGlobalData *p_state) {
430
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
431
432
if (p_state->device.is_empty()) {
433
// Not yet initialized.
434
return OK;
435
}
436
437
LocalVector<union wl_argument> args;
438
args.push_back(wl_arg_string(p_state->device.utf8().get_data()));
439
send_wayland_event(socket, p_id, wl_drm_interface, WL_DRM_DEVICE, args);
440
441
for (uint32_t format : p_state->formats) {
442
Error err = send_wayland_message(socket, p_id, WL_DRM_FORMAT, { format });
443
ERR_FAIL_COND_V(err != OK, err);
444
}
445
446
if (p_state->authenticated) {
447
Error err = send_wayland_message(socket, p_id, WL_DRM_AUTHENTICATED, {});
448
ERR_FAIL_COND_V(err != OK, err);
449
}
450
451
Error err = send_wayland_message(socket, p_id, WL_DRM_CAPABILITIES, { p_state->capabilities });
452
ERR_FAIL_COND_V(err != OK, err);
453
454
return OK;
455
}
456
457
void WaylandEmbedder::cleanup_socket(int p_socket) {
458
DEBUG_LOG_WAYLAND_EMBED(vformat("Cleaning up socket %d.", p_socket));
459
460
close(p_socket);
461
462
for (size_t i = 0; i < pollfds.size(); ++i) {
463
if (pollfds[i].fd == p_socket) {
464
pollfds.remove_at_unordered(i);
465
break;
466
}
467
}
468
469
ERR_FAIL_COND(!clients.has(p_socket));
470
471
Client &client = clients[p_socket];
472
473
for (KeyValue<uint32_t, WaylandObject> &pair : client.fake_objects) {
474
WaylandObject &object = pair.value;
475
476
if (object.interface == &xdg_toplevel_interface) {
477
XdgToplevelData *data = (XdgToplevelData *)object.data;
478
CRASH_COND(data == nullptr);
479
480
if (data->wl_subsurface_id != INVALID_ID) {
481
// wl_subsurface::destroy() - xdg_toplevels are mapped to subsurfaces.
482
send_wayland_message(compositor_socket, data->wl_subsurface_id, 0, {});
483
}
484
485
if (!data->xdg_surface_handle.get()) {
486
continue;
487
}
488
489
XdgSurfaceData *xdg_surf_data = (XdgSurfaceData *)data->xdg_surface_handle.get()->data;
490
if (xdg_surf_data == nullptr) {
491
continue;
492
}
493
494
if (!data->parent_handle.get()) {
495
continue;
496
}
497
498
XdgToplevelData *parent_data = (XdgToplevelData *)data->parent_handle.get()->data;
499
if (parent_data == nullptr) {
500
continue;
501
}
502
503
if (!parent_data->xdg_surface_handle.get()) {
504
continue;
505
}
506
507
XdgSurfaceData *parent_xdg_surf_data = (XdgSurfaceData *)parent_data->xdg_surface_handle.get()->data;
508
if (parent_xdg_surf_data == nullptr) {
509
continue;
510
}
511
512
for (uint32_t wl_seat_name : wl_seat_names) {
513
WaylandSeatGlobalData *global_seat_data = (WaylandSeatGlobalData *)registry_globals[wl_seat_name].data;
514
if (global_seat_data == nullptr) {
515
continue;
516
}
517
518
if (global_seat_data->focused_surface_id == xdg_surf_data->wl_surface_id) {
519
seat_name_leave_surface(wl_seat_name, xdg_surf_data->wl_surface_id);
520
seat_name_enter_surface(wl_seat_name, parent_xdg_surf_data->wl_surface_id);
521
}
522
}
523
}
524
}
525
526
for (List<uint32_t>::Element *E = client.global_id_history.back(); E;) {
527
uint32_t global_id = E->get();
528
E = E->prev();
529
530
WaylandObject *object = get_object(global_id);
531
if (object == nullptr) {
532
DEBUG_LOG_WAYLAND_EMBED(vformat("Skipping deletability check of object g0x%x as it's null.", global_id));
533
continue;
534
}
535
536
if (object->interface == nullptr) {
537
DEBUG_LOG_WAYLAND_EMBED(vformat("Skipping deletability check of object g0x%x as it's invalid.", global_id));
538
continue;
539
}
540
541
DEBUG_LOG_WAYLAND_EMBED(vformat("Checking deletability of %s#g0x%x version %s", object->interface->name, global_id, object->version));
542
543
if (object->shared) {
544
DEBUG_LOG_WAYLAND_EMBED("Shared, skipping.");
545
continue;
546
}
547
548
if (object->interface == &wl_callback_interface) {
549
// Those things self-destruct.
550
DEBUG_LOG_WAYLAND_EMBED("wl_callback self destructs.");
551
continue;
552
}
553
554
if (object->destroyed) {
555
DEBUG_LOG_WAYLAND_EMBED("Already destroyed, skipping.");
556
continue;
557
}
558
559
int destructor = wl_interface_get_destructor_opcode(object->interface, object->version);
560
if (destructor >= 0) {
561
DEBUG_LOG_WAYLAND_EMBED(vformat("Destroying %s#g0x%x", object->interface->name, global_id));
562
563
if (object->interface == &wl_surface_interface) {
564
for (uint32_t wl_seat_name : wl_seat_names) {
565
WaylandSeatGlobalData *global_seat_data = (WaylandSeatGlobalData *)registry_globals[wl_seat_name].data;
566
if (global_seat_data) {
567
if (global_seat_data->pointed_surface_id == global_id) {
568
global_seat_data->pointed_surface_id = INVALID_ID;
569
}
570
571
if (global_seat_data->focused_surface_id == global_id) {
572
global_seat_data->focused_surface_id = INVALID_ID;
573
}
574
}
575
}
576
}
577
578
send_wayland_message(compositor_socket, global_id, destructor, {});
579
object->destroyed = true;
580
581
if (global_id & 0xff000000) {
582
delete_object(global_id);
583
object = nullptr;
584
}
585
}
586
587
if (object && !object->destroyed) {
588
ERR_PRINT(vformat("Unreferenced object %s g0x%x (leak!)", object->interface->name, global_id));
589
}
590
}
591
592
uint32_t eclient_id = client.embedded_client_id;
593
594
clients.erase(client.socket);
595
596
WaylandObject *eclient = main_client->get_object(eclient_id);
597
598
if (eclient) {
599
EmbeddedClientData *eclient_data = (EmbeddedClientData *)eclient->data;
600
ERR_FAIL_NULL(eclient_data);
601
602
if (!eclient_data->disconnected) {
603
// godot_embedded_client::disconnected
604
send_wayland_message(main_client->socket, eclient_id, 0, {});
605
}
606
607
eclient_data->disconnected = true;
608
}
609
}
610
611
void WaylandEmbedder::socket_error(int p_socket, uint32_t p_object_id, uint32_t p_code, const String &p_message) {
612
const char *err_name = "unknown";
613
switch (p_code) {
614
case WL_DISPLAY_ERROR_INVALID_OBJECT: {
615
err_name = "invalid_object";
616
} break;
617
618
case WL_DISPLAY_ERROR_INVALID_METHOD: {
619
err_name = "invalid_method";
620
} break;
621
622
case WL_DISPLAY_ERROR_NO_MEMORY: {
623
err_name = "no_memory";
624
} break;
625
626
case WL_DISPLAY_ERROR_IMPLEMENTATION: {
627
err_name = "implementation";
628
} break;
629
}
630
631
ERR_PRINT(vformat("Socket %d %s error: %s", p_socket, err_name, p_message));
632
633
LocalVector<union wl_argument> args;
634
args.push_back(wl_arg_object(p_object_id));
635
args.push_back(wl_arg_uint(p_code));
636
args.push_back(wl_arg_string(vformat("[Godot Embedder] %s", p_message).utf8().get_data()));
637
638
send_wayland_event(p_socket, DISPLAY_ID, wl_display_interface, WL_DISPLAY_ERROR, args);
639
640
// So, here's the deal: from some extensive research I did, there are
641
// absolutely zero safeguards for ensuring that the error message ends to the
642
// client. It's absolutely tiny and takes _nothing_ to get there (less than
643
// 4µs with a debug build on my machine), but still enough to get truncated in
644
// the distance between `send_wayland_event` and `close`.
645
//
646
// Because of this we're going to give the client some slack: we're going to
647
// wait for its socket to close (or whatever) or 1s, whichever happens first.
648
//
649
// Hopefully it's good enough for <1000 bytes :P
650
struct pollfd pollfd = {};
651
pollfd.fd = p_socket;
652
653
int ret = poll(&pollfd, 1, 1'000);
654
if (ret == 0) {
655
ERR_PRINT("Client timeout while disconnecting.");
656
}
657
if (ret < 0) {
658
ERR_PRINT(vformat("Client error while disconnecting: %s", strerror(errno)));
659
}
660
661
close(p_socket);
662
}
663
664
void WaylandEmbedder::poll_sockets() {
665
if (poll(pollfds.ptr(), pollfds.size(), -1) == -1) {
666
CRASH_NOW_MSG(vformat("poll() failed, errno %d.", errno));
667
}
668
669
// First handle everything but the listening socket (which is always the first
670
// element), so that we can cleanup closed sockets before accidentally reusing
671
// them (and breaking everything).
672
for (size_t i = 1; i < pollfds.size(); ++i) {
673
handle_fd(pollfds[i].fd, pollfds[i].revents);
674
}
675
676
handle_fd(pollfds[0].fd, pollfds[0].revents);
677
}
678
679
Error WaylandEmbedder::send_raw_message(int p_socket, std::initializer_list<struct iovec> p_vecs, const LocalVector<int> &p_fds) {
680
struct msghdr msg = {};
681
msg.msg_iov = (struct iovec *)p_vecs.begin();
682
msg.msg_iovlen = p_vecs.size();
683
684
if (!p_fds.is_empty()) {
685
size_t data_size = p_fds.size() * sizeof(int);
686
687
msg.msg_control = Memory::alloc_aligned_static(CMSG_SPACE(data_size), CMSG_ALIGN(1));
688
msg.msg_controllen = CMSG_SPACE(data_size);
689
690
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
691
cmsg->cmsg_level = SOL_SOCKET;
692
cmsg->cmsg_type = SCM_RIGHTS;
693
cmsg->cmsg_len = CMSG_LEN(data_size);
694
695
// NOTE: According to the linux man page cmsg(5), we shall not access the
696
// pointer returned CMSG_DATA directly, due to alignment concerns. We should
697
// copy data from a suitably aligned object instead.
698
memcpy(CMSG_DATA(cmsg), p_fds.ptr(), data_size);
699
}
700
701
#ifdef WAYLAND_EMBED_DEBUG_LOGS_ENABLED
702
printf("[PROXY] Sending: ");
703
704
for (const struct iovec &vec : p_vecs) {
705
for (size_t i = 0; i < vec.iov_len; ++i) {
706
printf("%.2x", ((const uint8_t *)vec.iov_base)[i]);
707
}
708
}
709
printf("\n");
710
#endif
711
712
sendmsg(p_socket, &msg, MSG_NOSIGNAL);
713
714
if (msg.msg_control) {
715
Memory::free_aligned_static(msg.msg_control);
716
}
717
718
return OK;
719
}
720
721
Error WaylandEmbedder::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) {
722
ERR_FAIL_COND_V(p_socket < 0, ERR_INVALID_PARAMETER);
723
ERR_FAIL_COND_V(p_id == INVALID_ID, ERR_INVALID_PARAMETER);
724
725
uint32_t args_size = p_args_words * sizeof *p_args;
726
727
// Header is always 8 bytes long.
728
uint32_t total_size = 8 + (args_size);
729
730
uint32_t header[2] = { p_id, (total_size << 16) + p_opcode };
731
732
struct iovec vecs[2] = {
733
{ header, 8 },
734
// According to the sendmsg manual, these buffers should never be written to,
735
// so this cast should be safe.
736
{ (void *)p_args, args_size },
737
};
738
739
struct msghdr msg = {};
740
msg.msg_iov = vecs;
741
msg.msg_iovlen = std_size(vecs);
742
743
#ifdef WAYLAND_EMBED_DEBUG_LOGS_ENABLED
744
printf("[PROXY] Sending: ");
745
746
for (struct iovec &vec : vecs) {
747
for (size_t i = 0; i < vec.iov_len; ++i) {
748
printf("%.2x", ((const uint8_t *)vec.iov_base)[i]);
749
}
750
}
751
printf("\n");
752
#endif
753
754
if (sendmsg(p_socket, &msg, MSG_NOSIGNAL) < 0) {
755
return FAILED;
756
}
757
758
return OK;
759
}
760
761
Error WaylandEmbedder::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) {
762
ERR_FAIL_COND_V(p_direction == ProxyDirection::CLIENT && p_opcode >= (uint32_t)p_interface.event_count, ERR_INVALID_PARAMETER);
763
ERR_FAIL_COND_V(p_direction == ProxyDirection::COMPOSITOR && p_opcode >= (uint32_t)p_interface.method_count, ERR_INVALID_PARAMETER);
764
765
const struct wl_message &msg = p_direction == ProxyDirection::CLIENT ? p_interface.events[p_opcode] : p_interface.methods[p_opcode];
766
767
LocalVector<uint32_t> arg_buf;
768
769
size_t arg_idx = 0;
770
for (size_t sig_idx = 0; sig_idx < strlen(msg.signature); ++sig_idx) {
771
if (arg_idx >= p_args.size()) {
772
String err_msg = vformat("Not enough arguments for r0x%d %s.%s(%s) (only got %d)", p_id, p_interface.name, msg.name, msg.signature, p_args.size());
773
ERR_FAIL_COND_V_MSG(arg_idx >= p_args.size(), ERR_INVALID_PARAMETER, err_msg);
774
}
775
776
char sym = msg.signature[sig_idx];
777
if (sym >= '0' && sym <= '?') {
778
// We don't care about version notices and nullability symbols. We can skip
779
// those.
780
continue;
781
}
782
783
const union wl_argument &arg = p_args[arg_idx];
784
785
switch (sym) {
786
case 'i': {
787
arg_buf.push_back((uint32_t)arg.i);
788
} break;
789
790
case 'u': {
791
arg_buf.push_back(arg.u);
792
} break;
793
794
case 'f': {
795
arg_buf.push_back((uint32_t)arg.f);
796
} break;
797
798
case 'o': {
799
// We're encoding object arguments as uints because I don't think we can
800
// reuse the whole opaque struct thing.
801
arg_buf.push_back(arg.u);
802
} break;
803
804
case 'n': {
805
arg_buf.push_back(arg.n);
806
} break;
807
808
case 's': {
809
const char *str = p_args[arg_idx].s;
810
// Wayland requires the string length to include the null terminator.
811
uint32_t str_len = strlen(str) + 1;
812
813
arg_buf.push_back(str_len);
814
815
size_t data_begin_idx = arg_buf.size();
816
817
uint32_t str_words = wl_array_word_offset(str_len);
818
819
arg_buf.resize(arg_buf.size() + str_words);
820
strcpy((char *)(arg_buf.ptr() + data_begin_idx), str);
821
} break;
822
823
case 'a': {
824
const wl_array *arr = p_args[arg_idx].a;
825
826
arg_buf.push_back(arr->size);
827
828
size_t data_begin_idx = arg_buf.size();
829
830
uint32_t words = wl_array_word_offset(arr->size);
831
832
arg_buf.resize(arg_buf.size() + words);
833
memcpy(arg_buf.ptr() + data_begin_idx, arr->data, arr->size);
834
} break;
835
836
// FDs (h) are encoded out-of-band.
837
}
838
839
++arg_idx;
840
}
841
842
send_wayland_message(p_socket, p_id, p_opcode, arg_buf.ptr(), arg_buf.size());
843
844
return OK;
845
}
846
847
uint32_t WaylandEmbedder::new_object(const struct wl_interface *p_interface, int p_version, WaylandObjectData *p_data) {
848
uint32_t new_global_id = allocate_global_id();
849
850
DEBUG_LOG_WAYLAND_EMBED(vformat("New object g0x%x %s", new_global_id, p_interface->name));
851
852
WaylandObject *new_object = get_object(new_global_id);
853
new_object->interface = p_interface;
854
new_object->version = p_version;
855
new_object->data = p_data;
856
857
return new_global_id;
858
}
859
860
WaylandEmbedder::WaylandObject *WaylandEmbedder::new_server_object(uint32_t p_global_id, const struct wl_interface *p_interface, int p_version, WaylandObjectData *p_data) {
861
// The max ID will never increment more than one at a time, due to the
862
// packed nature of IDs. libwayland already does similar assertions so it
863
// just makes sense to double-check to avoid messing memory up or
864
// allocating a huge buffer for nothing.
865
uint32_t stripped_id = p_global_id & ~(0xff000000);
866
867
ERR_FAIL_COND_V_MSG(stripped_id > server_objects.size(), nullptr, "Invalid new server id requested.");
868
ERR_FAIL_COND_V_MSG(get_object(p_global_id) && get_object(p_global_id)->interface, nullptr, vformat("Tried to create %s g0x%x but it already exists as %s.", p_interface->name, p_global_id, get_object(p_global_id)->interface->name));
869
870
if (stripped_id == server_objects.size()) {
871
server_objects.resize(server_objects.size() + 1);
872
}
873
874
DEBUG_LOG_WAYLAND_EMBED(vformat("New server object %s g0x%x", p_interface->name, p_global_id));
875
876
WaylandObject *new_object = get_object(p_global_id);
877
new_object->interface = p_interface;
878
new_object->version = p_version;
879
new_object->data = p_data;
880
881
return new_object;
882
}
883
884
void WaylandEmbedder::sync() {
885
CRASH_COND_MSG(sync_callback_id, "Sync already in progress.");
886
887
sync_callback_id = allocate_global_id();
888
get_object(sync_callback_id)->interface = &wl_callback_interface;
889
get_object(sync_callback_id)->version = 1;
890
send_wayland_message(compositor_socket, DISPLAY_ID, 0, { sync_callback_id });
891
892
DEBUG_LOG_WAYLAND_EMBED("Synchronizing");
893
894
while (true) {
895
poll_sockets();
896
897
if (!sync_callback_id) {
898
// Obj got deleted - sync is done.
899
return;
900
}
901
}
902
}
903
904
// Returns the gid for the newly bound object, or an existing shared object if
905
// necessary.
906
uint32_t WaylandEmbedder::wl_registry_bind(uint32_t p_registry_id, uint32_t p_name, int p_version) {
907
RegistryGlobalInfo &info = registry_globals[p_name];
908
909
uint32_t id = INVALID_ID;
910
911
if (wl_interface_get_destructor_opcode(info.interface, p_version) < 0) {
912
DEBUG_LOG_WAYLAND_EMBED(vformat("Binding instanced global %s %d", info.interface->name, p_version));
913
914
// Reusable object.
915
if (info.reusable_objects.has(p_version) && info.reusable_objects[p_version] != INVALID_ID) {
916
DEBUG_LOG_WAYLAND_EMBED("Already bound.");
917
return info.reusable_objects[p_version];
918
}
919
920
id = new_object(info.interface, p_version);
921
ERR_FAIL_COND_V(id == INVALID_ID, INVALID_ID);
922
923
info.reusable_objects[p_version] = id;
924
get_object(id)->shared = true;
925
} else {
926
DEBUG_LOG_WAYLAND_EMBED(vformat("Binding global %s as g0x%x version %d", info.interface->name, id, p_version));
927
id = new_object(info.interface, p_version);
928
}
929
930
ERR_FAIL_COND_V(id == INVALID_ID, INVALID_ID);
931
932
registry_globals_names[id] = p_name;
933
934
LocalVector<union wl_argument> args;
935
args.push_back(wl_arg_uint(info.compositor_name));
936
args.push_back(wl_arg_string(info.interface->name));
937
args.push_back(wl_arg_int(p_version));
938
args.push_back(wl_arg_new_id(id));
939
940
Error err = send_wayland_method(compositor_socket, p_registry_id, wl_registry_interface, WL_REGISTRY_BIND, args);
941
ERR_FAIL_COND_V_MSG(err != OK, INVALID_ID, "Error while sending bind request.");
942
943
return id;
944
}
945
946
void WaylandEmbedder::seat_name_enter_surface(uint32_t p_seat_name, uint32_t p_wl_surface_id) {
947
WaylandSurfaceData *surf_data = (WaylandSurfaceData *)get_object(p_wl_surface_id)->data;
948
CRASH_COND(surf_data == nullptr);
949
950
Client *client = surf_data->client;
951
CRASH_COND(client == nullptr);
952
953
if (!client->local_ids.has(p_wl_surface_id)) {
954
DEBUG_LOG_WAYLAND_EMBED("Called seat_name_enter_surface with an unknown surface");
955
return;
956
}
957
958
uint32_t local_surface_id = client->get_local_id(p_wl_surface_id);
959
960
DEBUG_LOG_WAYLAND_EMBED(vformat("KB: Entering surface g0x%x", p_wl_surface_id));
961
962
for (uint32_t local_seat_id : client->registry_globals_instances[p_seat_name]) {
963
WaylandSeatInstanceData *seat_data = (WaylandSeatInstanceData *)client->get_object(local_seat_id)->data;
964
CRASH_COND(seat_data == nullptr);
965
966
uint32_t local_keyboard_id = client->get_local_id(seat_data->wl_keyboard_id);
967
968
if (local_keyboard_id != INVALID_ID) {
969
// TODO: track keys. Not super important at the time of writing, since we
970
// don't use that in the engine, although we should.
971
972
// wl_keyboard::enter(serial, surface, keys) - keys will be empty for now
973
send_wayland_message(client->socket, local_keyboard_id, 1, { serial_counter++, local_surface_id, 0 });
974
}
975
}
976
977
if (client->socket != main_client->socket) {
978
// godot_embedded_client::window_focus_in
979
send_wayland_message(main_client->socket, client->embedded_client_id, 2, {});
980
}
981
}
982
983
void WaylandEmbedder::seat_name_leave_surface(uint32_t p_seat_name, uint32_t p_wl_surface_id) {
984
WaylandSurfaceData *surf_data = (WaylandSurfaceData *)get_object(p_wl_surface_id)->data;
985
CRASH_COND(surf_data == nullptr);
986
987
Client *client = surf_data->client;
988
CRASH_COND(client == nullptr);
989
990
if (!client->local_ids.has(p_wl_surface_id)) {
991
DEBUG_LOG_WAYLAND_EMBED("Called seat_name_leave_surface with an unknown surface!");
992
return;
993
}
994
995
uint32_t local_surface_id = client->get_local_id(p_wl_surface_id);
996
997
DEBUG_LOG_WAYLAND_EMBED(vformat("KB: Leaving surface g0x%x", p_wl_surface_id));
998
999
for (uint32_t local_seat_id : client->registry_globals_instances[p_seat_name]) {
1000
WaylandSeatInstanceData *seat_data = (WaylandSeatInstanceData *)client->get_object(local_seat_id)->data;
1001
CRASH_COND(seat_data == nullptr);
1002
1003
uint32_t local_keyboard_id = client->get_local_id(seat_data->wl_keyboard_id);
1004
1005
if (local_keyboard_id != INVALID_ID) {
1006
// wl_keyboard::enter(serial, surface, keys) - keys will be empty for now
1007
send_wayland_message(client->socket, local_keyboard_id, 2, { serial_counter++, local_surface_id });
1008
}
1009
}
1010
1011
if (client != main_client) {
1012
// godot_embedded_client::window_focus_out
1013
send_wayland_message(main_client->socket, client->embedded_client_id, 3, {});
1014
}
1015
}
1016
1017
int WaylandEmbedder::allocate_global_id() {
1018
uint32_t id = INVALID_ID;
1019
objects.request(id);
1020
objects[id] = WaylandObject();
1021
1022
DEBUG_LOG_WAYLAND_EMBED(vformat("Allocated new global id g0x%x", id));
1023
1024
#ifdef DEV_ENABLED
1025
if (id > WAYLAND_EMBED_ID_MAX) {
1026
// Oh no. Time for debug info!
1027
1028
#ifdef WAYLAND_EMBED_DEBUG_LOGS_ENABLED
1029
for (uint32_t i = 1; i < objects.reserved_size(); ++i) {
1030
WaylandObject &object = objects[id];
1031
DEBUG_LOG_WAYLAND_EMBED(vformat(" - g0x%x (#%d): %s version %d, data 0x%x", i, i, object.interface->name, object.version, (uintptr_t)object.data));
1032
}
1033
#endif // WAYLAND_EMBED_DEBUG_LOGS_ENABLED
1034
1035
CRASH_NOW_MSG("Max ID reached. This might indicate a leak.");
1036
}
1037
#endif // DEV_ENABLED
1038
1039
return id;
1040
}
1041
1042
bool WaylandEmbedder::global_surface_is_window(uint32_t p_wl_surface_id) {
1043
WaylandObject *surface_object = get_object(p_wl_surface_id);
1044
ERR_FAIL_NULL_V(surface_object, false);
1045
if (surface_object->interface != &wl_surface_interface || surface_object->data == nullptr) {
1046
return false;
1047
}
1048
1049
WaylandSurfaceData *surface_data = (WaylandSurfaceData *)surface_object->data;
1050
if (!surface_data->role_object_handle.get()) {
1051
return false;
1052
}
1053
1054
WaylandObject *role_object = surface_data->role_object_handle.get();
1055
1056
return (role_object && role_object->interface == &xdg_toplevel_interface);
1057
}
1058
1059
bool WaylandEmbedder::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) {
1060
// We allow client-less events.
1061
CRASH_COND(client == nullptr && info->direction == ProxyDirection::COMPOSITOR);
1062
1063
ERR_FAIL_NULL_V(p_object, false);
1064
1065
bool valid = true;
1066
1067
// Let's strip the header.
1068
uint32_t *body = buf + 2;
1069
1070
size_t arg_idx = 0;
1071
size_t buf_idx = 0;
1072
size_t last_str_buf_idx = -1;
1073
uint32_t last_str_len = 0;
1074
for (size_t i = 0; i < strlen(message->signature); ++i) {
1075
ERR_FAIL_COND_V(buf_idx > (info->size / sizeof *body), false);
1076
1077
char sym = message->signature[i];
1078
if (sym >= '0' && sym <= '?') {
1079
// We don't care about version notices and nullability symbols. We can skip
1080
// those.
1081
continue;
1082
}
1083
1084
switch (sym) {
1085
case 'a': {
1086
uint32_t array_len = body[buf_idx];
1087
1088
// We can't obviously go forward by just one byte. Let's skip to the end of
1089
// the array.
1090
buf_idx += wl_array_word_offset(array_len);
1091
} break;
1092
1093
case 's': {
1094
uint32_t string_len = body[buf_idx];
1095
1096
last_str_buf_idx = buf_idx;
1097
last_str_len = string_len;
1098
1099
// Same as the array.
1100
buf_idx += wl_array_word_offset(string_len);
1101
} break;
1102
1103
case 'n': {
1104
uint32_t arg = body[buf_idx];
1105
1106
const struct wl_interface *new_interface = message->types[arg_idx];
1107
uint32_t new_version = p_object->version;
1108
1109
if (!new_interface && last_str_len != 0) {
1110
// When the protocol definition does not define an interface it reports a
1111
// string and an unsigned integer representing the interface and the
1112
// version requested.
1113
new_interface = wl_interface_from_string((char *)(body + last_str_buf_idx + 1), last_str_len);
1114
new_version = body[arg_idx - 1];
1115
}
1116
1117
if (new_interface == nullptr) {
1118
if (last_str_len > 0) {
1119
DEBUG_LOG_WAYLAND_EMBED(vformat("Unknown interface %s, marking packet as invalid.", (char *)(body + last_str_buf_idx + 1)));
1120
} else {
1121
DEBUG_LOG_WAYLAND_EMBED("Unknown interface, marking packet as invalid.");
1122
}
1123
valid = false;
1124
break;
1125
}
1126
1127
if (info->direction == ProxyDirection::COMPOSITOR) {
1128
// FIXME: Create objects only if the packet is valid.
1129
uint32_t new_local_id = arg;
1130
body[buf_idx] = client->new_object(new_local_id, new_interface, new_version);
1131
1132
if (body[buf_idx] == INVALID_ID) {
1133
valid = false;
1134
break;
1135
}
1136
1137
} else if (info->direction == ProxyDirection::CLIENT) {
1138
uint32_t new_global_id = arg;
1139
1140
if (client) {
1141
body[buf_idx] = client->new_server_object(new_global_id, new_interface, new_version);
1142
} else {
1143
new_server_object(new_global_id, new_interface, new_version);
1144
}
1145
1146
if (body[buf_idx] == INVALID_ID) {
1147
valid = false;
1148
break;
1149
}
1150
}
1151
} break;
1152
1153
case 'o': {
1154
if (!client) {
1155
break;
1156
}
1157
1158
uint32_t obj_id = body[buf_idx];
1159
if (obj_id == 0) {
1160
// Object arguments can be nil.
1161
break;
1162
}
1163
1164
if (info->direction == ProxyDirection::CLIENT) {
1165
if (!client->local_ids.has(obj_id)) {
1166
DEBUG_LOG_WAYLAND_EMBED(vformat("Object argument g0x%x not found, marking packet as invalid.", obj_id));
1167
valid = false;
1168
break;
1169
}
1170
body[buf_idx] = instance_id != INVALID_ID ? instance_id : client->get_local_id(obj_id);
1171
} else if (info->direction == ProxyDirection::COMPOSITOR) {
1172
if (!client->global_ids.has(obj_id)) {
1173
DEBUG_LOG_WAYLAND_EMBED(vformat("Object argument l0x%x not found, marking packet as invalid.", obj_id));
1174
valid = false;
1175
break;
1176
}
1177
body[buf_idx] = client->get_global_id(obj_id);
1178
}
1179
} break;
1180
}
1181
1182
++arg_idx;
1183
++buf_idx;
1184
}
1185
1186
return valid;
1187
}
1188
1189
WaylandEmbedder::MessageStatus WaylandEmbedder::handle_request(LocalObjectHandle p_object, uint32_t p_opcode, const uint32_t *msg_data, size_t msg_len) {
1190
ERR_FAIL_COND_V(!p_object.is_valid(), MessageStatus::HANDLED);
1191
1192
WaylandObject *object = p_object.get();
1193
Client *client = p_object.get_client();
1194
1195
ERR_FAIL_NULL_V(object, MessageStatus::HANDLED);
1196
1197
// NOTE: Global ID may be null.
1198
uint32_t global_id = p_object.get_global_id();
1199
uint32_t local_id = p_object.get_local_id();
1200
1201
ERR_FAIL_NULL_V(object->interface, MessageStatus::ERROR);
1202
const struct wl_interface *interface = object->interface;
1203
1204
ERR_FAIL_COND_V((int)p_opcode >= interface->method_count, MessageStatus::ERROR);
1205
const struct wl_message message = interface->methods[p_opcode];
1206
1207
DEBUG_LOG_WAYLAND_EMBED(vformat("Client #%d -> %s::%s(%s) l0x%x g0x%x", client->socket, interface->name, message.name, message.signature, local_id, global_id));
1208
1209
const uint32_t *body = msg_data + 2;
1210
1211
if (registry_globals_names.has(global_id)) {
1212
int global_name = registry_globals_names[global_id];
1213
ERR_FAIL_COND_V(!registry_globals.has(global_name), MessageStatus::ERROR);
1214
RegistryGlobalInfo &global_info = registry_globals[global_name];
1215
1216
if (global_info.destroyed) {
1217
DEBUG_LOG_WAYLAND_EMBED("Skipping request for destroyed global object");
1218
return MessageStatus::HANDLED;
1219
}
1220
}
1221
1222
if (object->interface == &wl_display_interface && p_opcode == WL_DISPLAY_GET_REGISTRY) {
1223
// The gist of this is that the registry is a global and the compositor can
1224
// quite simply take for granted that a single client can access any global
1225
// bound from any registry. Let's remove all doubts by using a single
1226
// registry (also for efficiency) and doing fancy remaps.
1227
uint32_t local_registry_id = body[0];
1228
1229
// Note that the registry has already been allocated in the initialization
1230
// routine.
1231
1232
for (KeyValue<uint32_t, RegistryGlobalInfo> &pair : registry_globals) {
1233
uint32_t global_name = pair.key;
1234
RegistryGlobalInfo &global_info = pair.value;
1235
1236
if (global_info.destroyed) {
1237
continue;
1238
}
1239
1240
const struct wl_interface *global_interface = global_info.interface;
1241
1242
if (client != main_client && embedded_interface_deny_list.has(global_interface)) {
1243
DEBUG_LOG_WAYLAND_EMBED(vformat("Skipped global announcement %s for embedded client.", global_interface->name));
1244
continue;
1245
}
1246
1247
LocalVector<union wl_argument> args;
1248
args.push_back(wl_arg_uint(global_name));
1249
args.push_back(wl_arg_string(global_interface->name));
1250
args.push_back(wl_arg_uint(global_info.version));
1251
1252
send_wayland_event(client->socket, local_registry_id, wl_registry_interface, WL_REGISTRY_GLOBAL, args);
1253
}
1254
1255
client->wl_registry_instances.insert(local_registry_id);
1256
client->new_global_instance(local_registry_id, REGISTRY_ID, &wl_registry_interface, 1);
1257
1258
return MessageStatus::HANDLED;
1259
}
1260
1261
if (object->interface == &wl_registry_interface) {
1262
if (p_opcode == WL_REGISTRY_BIND) {
1263
// [Request] wl_registry::bind(usun)
1264
uint32_t global_name = body[0];
1265
uint32_t interface_name_len = body[1];
1266
//const char *interface_name = (const char *)(body + 2);
1267
uint32_t version = body[2 + wl_array_word_offset(interface_name_len)];
1268
uint32_t new_local_id_idx = 2 + wl_array_word_offset(interface_name_len) + 1;
1269
uint32_t new_local_id = body[new_local_id_idx];
1270
1271
if (!registry_globals.has(global_name)) {
1272
socket_error(client->socket, local_id, WL_DISPLAY_ERROR_INVALID_METHOD, vformat("Invalid global object #%d", global_name));
1273
return MessageStatus::HANDLED;
1274
}
1275
1276
RegistryGlobalInfo &global_info = registry_globals[global_name];
1277
ERR_FAIL_NULL_V(global_info.interface, MessageStatus::ERROR);
1278
1279
version = MIN(global_info.version, version);
1280
1281
if (global_info.interface == &godot_embedding_compositor_interface) {
1282
if (!client->registry_globals_instances.has(global_name)) {
1283
client->registry_globals_instances[global_name] = {};
1284
}
1285
1286
client->registry_globals_instances[global_name].insert(new_local_id);
1287
++global_info.instance_counter;
1288
DEBUG_LOG_WAYLAND_EMBED("Bound embedded compositor interface.");
1289
client->new_fake_object(new_local_id, &godot_embedding_compositor_interface, 1);
1290
return MessageStatus::HANDLED;
1291
}
1292
1293
WaylandObject *instance = nullptr;
1294
1295
client->registry_globals_instances[global_name].insert(new_local_id);
1296
++global_info.instance_counter;
1297
1298
if (!client->registry_globals_instances.has(global_name)) {
1299
client->registry_globals_instances[global_name] = {};
1300
}
1301
1302
uint32_t bind_gid = wl_registry_bind(REGISTRY_ID, global_name, version);
1303
if (bind_gid == INVALID_ID) {
1304
socket_error(client->socket, local_id, WL_DISPLAY_ERROR_IMPLEMENTATION, "Bind failed.");
1305
return MessageStatus::HANDLED;
1306
}
1307
1308
WaylandObject *bind_obj = get_object(bind_gid);
1309
if (bind_obj == nullptr) {
1310
socket_error(client->socket, local_id, WL_DISPLAY_ERROR_IMPLEMENTATION, "Bind failed.");
1311
return MessageStatus::HANDLED;
1312
}
1313
1314
if (!bind_obj->shared) {
1315
client->bind_global_id(bind_gid, new_local_id);
1316
instance = bind_obj;
1317
} else {
1318
instance = client->new_global_instance(new_local_id, global_info.reusable_objects[version], global_info.interface, version);
1319
DEBUG_LOG_WAYLAND_EMBED(vformat("Instancing global #%d iface %s ver %d new id l0x%x g0x%x", global_name, global_info.interface->name, version, new_local_id, global_info.reusable_objects[version]));
1320
1321
// Some interfaces report their state as soon as they're bound. Since
1322
// instances are handled by us, we need to track and report the relevant
1323
// data ourselves.
1324
if (global_info.interface == &wl_drm_interface) {
1325
Error err = client->send_wl_drm_state(new_local_id, (WaylandDrmGlobalData *)global_info.data);
1326
if (err != OK) {
1327
return MessageStatus::ERROR;
1328
}
1329
} else if (global_info.interface == &wl_shm_interface) {
1330
WaylandShmGlobalData *global_data = (WaylandShmGlobalData *)global_info.data;
1331
ERR_FAIL_NULL_V(global_data, MessageStatus::ERROR);
1332
1333
for (uint32_t format : global_data->formats) {
1334
send_wayland_message(client->socket, new_local_id, WL_SHM_FORMAT, { format });
1335
}
1336
}
1337
}
1338
1339
ERR_FAIL_NULL_V(instance, MessageStatus::UNHANDLED);
1340
1341
if (global_info.interface == &wl_seat_interface) {
1342
WaylandSeatInstanceData *new_data = memnew(WaylandSeatInstanceData);
1343
instance->data = new_data;
1344
}
1345
1346
return MessageStatus::HANDLED;
1347
}
1348
}
1349
1350
if (object->interface == &wl_compositor_interface && p_opcode == WL_COMPOSITOR_CREATE_SURFACE) {
1351
uint32_t new_local_id = body[0];
1352
1353
WaylandSurfaceData *data = memnew(WaylandSurfaceData);
1354
data->client = client;
1355
1356
uint32_t new_global_id = client->new_object(new_local_id, &wl_surface_interface, object->version, data);
1357
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1358
1359
DEBUG_LOG_WAYLAND_EMBED(vformat("Keeping track of surface l0x%x g0x%x.", new_local_id, new_global_id));
1360
1361
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id });
1362
return MessageStatus::HANDLED;
1363
}
1364
1365
if (object->interface == &wl_surface_interface) {
1366
WaylandSurfaceData *surface_data = (WaylandSurfaceData *)object->data;
1367
ERR_FAIL_NULL_V(surface_data, MessageStatus::ERROR);
1368
1369
if (p_opcode == WL_SURFACE_DESTROY) {
1370
for (uint32_t wl_seat_name : wl_seat_names) {
1371
WaylandSeatGlobalData *global_seat_data = (WaylandSeatGlobalData *)registry_globals[wl_seat_name].data;
1372
ERR_FAIL_NULL_V(global_seat_data, MessageStatus::ERROR);
1373
1374
if (global_seat_data->pointed_surface_id == global_id) {
1375
global_seat_data->pointed_surface_id = INVALID_ID;
1376
}
1377
1378
if (global_seat_data->focused_surface_id == global_id) {
1379
global_seat_data->focused_surface_id = INVALID_ID;
1380
}
1381
}
1382
} else if (p_opcode == WL_SURFACE_COMMIT) {
1383
if (surface_data->role_object_handle.is_valid()) {
1384
WaylandObject *role_object = surface_data->role_object_handle.get();
1385
if (role_object && role_object->interface) {
1386
DEBUG_LOG_WAYLAND_EMBED(vformat("!!!!! Committed surface g0x%x with role object %s id l0x%x", global_id, role_object->interface->name, surface_data->role_object_handle.get_local_id()));
1387
}
1388
1389
if (role_object && role_object->interface == &xdg_toplevel_interface) {
1390
XdgToplevelData *toplevel_data = (XdgToplevelData *)role_object->data;
1391
ERR_FAIL_NULL_V(toplevel_data, MessageStatus::ERROR);
1392
// xdg shell spec requires clients to first send data and then commit the
1393
// surface.
1394
1395
if (toplevel_data->is_embedded() && !toplevel_data->configured) {
1396
toplevel_data->configured = true;
1397
// xdg_surface::configure
1398
send_wayland_message(client->socket, toplevel_data->xdg_surface_handle.get_local_id(), 0, { serial_counter++ });
1399
}
1400
}
1401
}
1402
1403
send_wayland_message(compositor_socket, global_id, p_opcode, {});
1404
return MessageStatus::HANDLED;
1405
}
1406
}
1407
1408
if (object->interface == &wl_seat_interface) {
1409
uint32_t global_seat_name = registry_globals_names[global_id];
1410
1411
RegistryGlobalInfo &seat_global_info = registry_globals[global_seat_name];
1412
WaylandSeatGlobalData *global_data = (WaylandSeatGlobalData *)seat_global_info.data;
1413
ERR_FAIL_NULL_V(global_data, MessageStatus::ERROR);
1414
1415
WaylandSeatInstanceData *instance_data = (WaylandSeatInstanceData *)object->data;
1416
ERR_FAIL_NULL_V(instance_data, MessageStatus::ERROR);
1417
1418
if (p_opcode == WL_SEAT_GET_POINTER) {
1419
ERR_FAIL_COND_V(global_id == INVALID_ID, MessageStatus::ERROR);
1420
// [Request] wl_seat::get_pointer(n);
1421
uint32_t new_local_id = body[0];
1422
1423
WaylandPointerData *new_data = memnew(WaylandPointerData);
1424
new_data->wl_seat_id = global_id;
1425
1426
uint32_t new_global_id = client->new_object(new_local_id, &wl_pointer_interface, object->version, new_data);
1427
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1428
1429
instance_data->wl_pointer_id = new_global_id;
1430
1431
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id });
1432
1433
return MessageStatus::HANDLED;
1434
}
1435
1436
if (p_opcode == WL_SEAT_GET_KEYBOARD) {
1437
ERR_FAIL_COND_V(global_id == INVALID_ID, MessageStatus::ERROR);
1438
// [Request] wl_seat::get_pointer(n);
1439
uint32_t new_local_id = body[0];
1440
1441
WaylandKeyboardData *new_data = memnew(WaylandKeyboardData);
1442
new_data->wl_seat_id = global_id;
1443
1444
uint32_t new_global_id = client->new_object(new_local_id, &wl_keyboard_interface, object->version, new_data);
1445
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1446
1447
instance_data->wl_keyboard_id = new_global_id;
1448
1449
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id });
1450
1451
return MessageStatus::HANDLED;
1452
}
1453
}
1454
1455
if (object->interface == &xdg_wm_base_interface) {
1456
if (p_opcode == XDG_WM_BASE_CREATE_POSITIONER) {
1457
uint32_t new_local_id = body[0];
1458
uint32_t new_global_id = client->new_object(new_local_id, &xdg_positioner_interface, object->version, memnew(XdgPositionerData));
1459
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1460
1461
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id });
1462
return MessageStatus::HANDLED;
1463
}
1464
1465
if (p_opcode == XDG_WM_BASE_GET_XDG_SURFACE) {
1466
// [Request] xdg_wm_base::get_xdg_surface(no).
1467
uint32_t new_local_id = body[0];
1468
uint32_t surface_id = body[1];
1469
1470
uint32_t global_surface_id = client->get_global_id(surface_id);
1471
1472
bool fake = (client != main_client);
1473
1474
XdgSurfaceData *data = memnew(XdgSurfaceData);
1475
data->wl_surface_id = global_surface_id;
1476
1477
if (fake) {
1478
client->new_fake_object(new_local_id, &xdg_surface_interface, object->version, data);
1479
DEBUG_LOG_WAYLAND_EMBED(vformat("Created fake xdg_surface l0x%x for surface l0x%x", new_local_id, surface_id));
1480
} else {
1481
uint32_t new_global_id = client->new_object(new_local_id, &xdg_surface_interface, object->version, data);
1482
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1483
1484
DEBUG_LOG_WAYLAND_EMBED(vformat("Created real xdg_surface l0x%x g0x%x for surface l0x%x", new_local_id, new_global_id, surface_id));
1485
1486
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id, global_surface_id });
1487
}
1488
1489
return MessageStatus::HANDLED;
1490
}
1491
}
1492
1493
if (object->interface == &xdg_surface_interface) {
1494
XdgSurfaceData *xdg_surf_data = (XdgSurfaceData *)object->data;
1495
ERR_FAIL_NULL_V(xdg_surf_data, MessageStatus::ERROR);
1496
1497
WaylandSurfaceData *surface_data = (WaylandSurfaceData *)get_object(xdg_surf_data->wl_surface_id)->data;
1498
ERR_FAIL_NULL_V(surface_data, MessageStatus::ERROR);
1499
1500
bool is_embedded = client->fake_objects.has(local_id);
1501
1502
if (p_opcode == XDG_SURFACE_GET_POPUP) {
1503
// [Request] xdg_surface::get_popup(no?o).
1504
1505
uint32_t new_local_id = body[0];
1506
uint32_t local_parent_id = body[1];
1507
uint32_t local_positioner_id = body[2];
1508
1509
surface_data->role_object_handle = LocalObjectHandle(client, new_local_id);
1510
1511
XdgPopupData *popup_data = memnew(XdgPopupData);
1512
popup_data->parent_handle = LocalObjectHandle(client, local_parent_id);
1513
1514
if (!is_embedded) {
1515
uint32_t new_global_id = client->new_object(new_local_id, &xdg_popup_interface, object->version, popup_data);
1516
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1517
1518
uint32_t global_parent_id = client->get_global_id(local_parent_id);
1519
uint32_t global_positioner_id = client->get_global_id(local_positioner_id);
1520
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id, global_parent_id, global_positioner_id });
1521
1522
return MessageStatus::HANDLED;
1523
}
1524
1525
{
1526
// Popups are real, time to actually instantiate an xdg_surface.
1527
WaylandObject copy = *object;
1528
client->fake_objects.erase(local_id);
1529
1530
global_id = client->new_object(local_id, copy.interface, copy.version, copy.data);
1531
ERR_FAIL_COND_V(global_id == INVALID_ID, MessageStatus::HANDLED);
1532
object = get_object(global_id);
1533
1534
// xdg_wm_base::get_xdg_surface(no);
1535
send_wayland_message(compositor_socket, xdg_wm_base_id, 2, { global_id, xdg_surf_data->wl_surface_id });
1536
}
1537
1538
uint32_t new_global_id = client->new_object(new_local_id, &xdg_popup_interface, object->version, popup_data);
1539
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1540
1541
uint32_t global_parent_id = INVALID_ID;
1542
if (local_parent_id != INVALID_ID) {
1543
XdgSurfaceData *parent_xdg_surf_data = (XdgSurfaceData *)client->get_object(local_parent_id)->data;
1544
ERR_FAIL_NULL_V(parent_xdg_surf_data, MessageStatus::ERROR);
1545
1546
WaylandSurfaceData *parent_surface_data = (WaylandSurfaceData *)get_object(parent_xdg_surf_data->wl_surface_id)->data;
1547
ERR_FAIL_NULL_V(parent_surface_data, MessageStatus::ERROR);
1548
1549
WaylandObject *parent_role_obj = parent_surface_data->role_object_handle.get();
1550
ERR_FAIL_NULL_V(parent_role_obj, MessageStatus::ERROR);
1551
1552
XdgPositionerData *pos_data = (XdgPositionerData *)client->get_object(local_positioner_id)->data;
1553
ERR_FAIL_NULL_V(pos_data, MessageStatus::ERROR);
1554
1555
if (parent_role_obj->interface == &xdg_toplevel_interface) {
1556
XdgToplevelData *parent_toplevel_data = (XdgToplevelData *)parent_role_obj->data;
1557
ERR_FAIL_NULL_V(parent_toplevel_data, MessageStatus::ERROR);
1558
1559
if (parent_toplevel_data->is_embedded()) {
1560
// Embedded windows are subsurfaces of a parent window. We need to
1561
// "redirect" the popup request on the parent window and adjust the
1562
// positioner properly if needed.
1563
1564
XdgToplevelData *main_parent_toplevel_data = (XdgToplevelData *)parent_toplevel_data->parent_handle.get()->data;
1565
ERR_FAIL_NULL_V(main_parent_toplevel_data, MessageStatus::ERROR);
1566
1567
global_parent_id = main_parent_toplevel_data->xdg_surface_handle.get_global_id();
1568
1569
WaylandSubsurfaceData *subsurf_data = (WaylandSubsurfaceData *)get_object(parent_toplevel_data->wl_subsurface_id)->data;
1570
ERR_FAIL_NULL_V(subsurf_data, MessageStatus::ERROR);
1571
1572
Point2i adj_pos = subsurf_data->position + pos_data->anchor_rect.position;
1573
1574
// xdg_positioner::set_anchor_rect
1575
send_wayland_message(compositor_socket, client->get_global_id(local_positioner_id), 2, { (uint32_t)adj_pos.x, (uint32_t)adj_pos.y, (uint32_t)pos_data->anchor_rect.size.width, (uint32_t)pos_data->anchor_rect.size.height });
1576
}
1577
} else {
1578
global_parent_id = client->get_global_id(local_parent_id);
1579
}
1580
}
1581
1582
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id, global_parent_id, client->get_global_id(local_positioner_id) });
1583
return MessageStatus::HANDLED;
1584
}
1585
1586
if (p_opcode == XDG_SURFACE_GET_TOPLEVEL) {
1587
// [Request] xdg_surface::get_toplevel(n).
1588
uint32_t new_local_id = body[0];
1589
1590
surface_data->role_object_handle = LocalObjectHandle(client, new_local_id);
1591
1592
XdgToplevelData *data = memnew(XdgToplevelData);
1593
data->xdg_surface_handle = LocalObjectHandle(client, local_id);
1594
1595
if (is_embedded) {
1596
client->new_fake_object(new_local_id, &xdg_toplevel_interface, object->version, data);
1597
client->embedded_window_id = new_local_id;
1598
1599
// godot_embedded_client::window_embedded()
1600
send_wayland_message(main_client->socket, client->embedded_client_id, 1, {});
1601
} else {
1602
uint32_t new_global_id = client->new_object(new_local_id, &xdg_toplevel_interface, object->version, data);
1603
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1604
1605
if (main_toplevel_id == 0) {
1606
main_toplevel_id = new_global_id;
1607
DEBUG_LOG_WAYLAND_EMBED(vformat("main toplevel set to gx0%x.", main_toplevel_id));
1608
}
1609
1610
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id });
1611
}
1612
1613
return MessageStatus::HANDLED;
1614
}
1615
}
1616
1617
if (object->interface == &xdg_positioner_interface) {
1618
XdgPositionerData *pos_data = (XdgPositionerData *)object->data;
1619
ERR_FAIL_NULL_V(pos_data, MessageStatus::ERROR);
1620
1621
if (p_opcode == XDG_POSITIONER_SET_ANCHOR_RECT) {
1622
// Args: int x, int y, int width, int height.
1623
pos_data->anchor_rect = Rect2i(body[0], body[1], body[2], body[3]);
1624
1625
send_wayland_message(compositor_socket, global_id, p_opcode, { body[0], body[1], body[2], body[3] });
1626
return MessageStatus::HANDLED;
1627
}
1628
}
1629
1630
if (object->interface == &xdg_toplevel_interface && p_opcode == XDG_TOPLEVEL_DESTROY) {
1631
if (client->fake_objects.has(local_id)) {
1632
XdgToplevelData *data = (XdgToplevelData *)object->data;
1633
ERR_FAIL_NULL_V(data, MessageStatus::ERROR);
1634
1635
XdgSurfaceData *xdg_surf_data = nullptr;
1636
if (data->xdg_surface_handle.is_valid()) {
1637
xdg_surf_data = (XdgSurfaceData *)data->xdg_surface_handle.get()->data;
1638
ERR_FAIL_NULL_V(xdg_surf_data, MessageStatus::ERROR);
1639
}
1640
ERR_FAIL_NULL_V(xdg_surf_data, MessageStatus::ERROR);
1641
1642
XdgSurfaceData *parent_xdg_surf_data = nullptr;
1643
{
1644
XdgToplevelData *parent_data = nullptr;
1645
if (data->parent_handle.get()) {
1646
parent_data = (XdgToplevelData *)data->parent_handle.get()->data;
1647
ERR_FAIL_NULL_V(parent_data, MessageStatus::ERROR);
1648
}
1649
1650
if (parent_data && parent_data->xdg_surface_handle.get()) {
1651
parent_xdg_surf_data = (XdgSurfaceData *)parent_data->xdg_surface_handle.get()->data;
1652
ERR_FAIL_NULL_V(parent_xdg_surf_data, MessageStatus::ERROR);
1653
}
1654
}
1655
1656
for (uint32_t wl_seat_name : wl_seat_names) {
1657
WaylandSeatGlobalData *global_seat_data = (WaylandSeatGlobalData *)registry_globals[wl_seat_name].data;
1658
ERR_FAIL_NULL_V(global_seat_data, MessageStatus::ERROR);
1659
1660
if (global_seat_data->focused_surface_id == xdg_surf_data->wl_surface_id) {
1661
if (xdg_surf_data) {
1662
seat_name_leave_surface(wl_seat_name, xdg_surf_data->wl_surface_id);
1663
}
1664
1665
if (parent_xdg_surf_data) {
1666
seat_name_enter_surface(wl_seat_name, parent_xdg_surf_data->wl_surface_id);
1667
}
1668
}
1669
}
1670
1671
// wl_display::delete_id
1672
send_wayland_message(client->socket, local_id, p_opcode, {});
1673
1674
if (local_id == client->embedded_window_id) {
1675
client->embedded_window_id = 0;
1676
}
1677
1678
if (data->wl_subsurface_id != INVALID_ID) {
1679
send_wayland_message(compositor_socket, data->wl_subsurface_id, WL_SUBSURFACE_DESTROY, {});
1680
}
1681
1682
client->delete_object(local_id);
1683
1684
return MessageStatus::HANDLED;
1685
}
1686
}
1687
1688
if (interface == &zwp_pointer_constraints_v1_interface) {
1689
// FIXME: This implementation leaves no way of unlocking the pointer when
1690
// embedded into the main window. We might need to be a bit more invasive.
1691
if (p_opcode == ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER) {
1692
// [Request] zwp_pointer_constraints_v1::lock_pointer(nooou).
1693
1694
uint32_t new_local_id = body[0];
1695
uint32_t local_surface_id = body[1];
1696
uint32_t local_pointer_id = body[2];
1697
uint32_t lifetime = body[4];
1698
1699
WaylandSurfaceData *surf_data = (WaylandSurfaceData *)client->get_object(local_surface_id)->data;
1700
ERR_FAIL_NULL_V(surf_data, MessageStatus::ERROR);
1701
1702
WaylandObject *role_obj = surf_data->role_object_handle.get();
1703
ERR_FAIL_NULL_V(role_obj, MessageStatus::ERROR);
1704
1705
if (role_obj->interface == &xdg_toplevel_interface) {
1706
XdgToplevelData *toplevel_data = (XdgToplevelData *)role_obj->data;
1707
ERR_FAIL_NULL_V(toplevel_data, MessageStatus::ERROR);
1708
1709
if (!toplevel_data->is_embedded()) {
1710
// Passthrough.
1711
return MessageStatus::UNHANDLED;
1712
}
1713
1714
// Subsurfaces don't normally work, at least on sway, as the locking
1715
// condition might rely on focus, which they don't get. We can remap them to
1716
// the parent surface and set a region though.
1717
1718
XdgToplevelData *parent_data = (XdgToplevelData *)toplevel_data->parent_handle.get()->data;
1719
ERR_FAIL_NULL_V(parent_data, MessageStatus::ERROR);
1720
1721
XdgSurfaceData *parent_xdg_surf_data = (XdgSurfaceData *)parent_data->xdg_surface_handle.get()->data;
1722
ERR_FAIL_NULL_V(parent_xdg_surf_data, MessageStatus::ERROR);
1723
1724
WaylandSubsurfaceData *subsurf_data = (WaylandSubsurfaceData *)get_object(toplevel_data->wl_subsurface_id)->data;
1725
ERR_FAIL_NULL_V(subsurf_data, MessageStatus::ERROR);
1726
1727
uint32_t new_global_id = client->new_object(new_local_id, &zwp_locked_pointer_v1_interface, object->version);
1728
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1729
1730
uint32_t x = subsurf_data->position.x;
1731
uint32_t y = subsurf_data->position.y;
1732
uint32_t width = toplevel_data->size.width;
1733
uint32_t height = toplevel_data->size.height;
1734
1735
// NOTE: At least on sway I can't seem to be able to get this region
1736
// working but the calls check out.
1737
DEBUG_LOG_WAYLAND_EMBED(vformat("Creating custom region x%d y%d w%d h%d", x, y, width, height));
1738
1739
uint32_t new_region_id = allocate_global_id();
1740
get_object(new_region_id)->interface = &wl_region_interface;
1741
get_object(new_region_id)->version = get_object(wl_compositor_id)->version;
1742
1743
// wl_compostor::create_region(n).
1744
send_wayland_message(compositor_socket, wl_compositor_id, 1, { new_region_id });
1745
1746
// wl_region::add(iiii).
1747
send_wayland_message(compositor_socket, new_region_id, 1, { x, y, width, height });
1748
1749
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id, parent_xdg_surf_data->wl_surface_id, client->get_global_id(local_pointer_id), new_region_id, lifetime });
1750
1751
// wl_region::destroy().
1752
send_wayland_message(compositor_socket, new_region_id, 0, {});
1753
1754
return MessageStatus::HANDLED;
1755
}
1756
}
1757
}
1758
1759
if (interface == &godot_embedded_client_interface) {
1760
EmbeddedClientData *eclient_data = (EmbeddedClientData *)object->data;
1761
ERR_FAIL_NULL_V(eclient_data, MessageStatus::ERROR);
1762
1763
Client *eclient = eclient_data->client;
1764
ERR_FAIL_NULL_V(eclient, MessageStatus::ERROR);
1765
1766
if (p_opcode == GODOT_EMBEDDED_CLIENT_DESTROY) {
1767
if (!eclient_data->disconnected) {
1768
close(eclient->socket);
1769
}
1770
1771
client->delete_object(local_id);
1772
1773
return MessageStatus::HANDLED;
1774
}
1775
1776
if (eclient_data->disconnected) {
1777
// Object is inert.
1778
return MessageStatus::HANDLED;
1779
}
1780
1781
ERR_FAIL_COND_V(eclient->embedded_window_id == 0, MessageStatus::ERROR);
1782
1783
XdgToplevelData *toplevel_data = (XdgToplevelData *)eclient->get_object(eclient->embedded_window_id)->data;
1784
ERR_FAIL_NULL_V(toplevel_data, MessageStatus::ERROR);
1785
1786
if (p_opcode == GODOT_EMBEDDED_CLIENT_SET_EMBEDDED_WINDOW_RECT && toplevel_data->wl_subsurface_id != INVALID_ID) {
1787
uint32_t x = body[0];
1788
uint32_t y = body[1];
1789
uint32_t width = body[2];
1790
uint32_t height = body[3];
1791
1792
WaylandSubsurfaceData *subsurf_data = (WaylandSubsurfaceData *)get_object(toplevel_data->wl_subsurface_id)->data;
1793
ERR_FAIL_NULL_V(subsurf_data, MessageStatus::ERROR);
1794
1795
toplevel_data->size.width = width;
1796
toplevel_data->size.height = height;
1797
1798
subsurf_data->position.x = x;
1799
subsurf_data->position.y = y;
1800
1801
// wl_subsurface::set_position
1802
send_wayland_message(compositor_socket, toplevel_data->wl_subsurface_id, 1, { x, y });
1803
1804
// xdg_toplevel::configure
1805
send_wayland_message(eclient->socket, eclient->embedded_window_id, 0, { width, height, 0 });
1806
1807
// xdg_surface::configure
1808
send_wayland_message(eclient->socket, toplevel_data->xdg_surface_handle.get_local_id(), 0, { configure_serial_counter++ });
1809
1810
return MessageStatus::HANDLED;
1811
} else if (p_opcode == GODOT_EMBEDDED_CLIENT_SET_EMBEDDED_WINDOW_PARENT) {
1812
uint32_t main_client_parent_id = body[0];
1813
1814
if (toplevel_data->parent_handle.get_local_id() == main_client_parent_id) {
1815
return MessageStatus::HANDLED;
1816
}
1817
1818
if (main_client_parent_id == INVALID_ID && toplevel_data->wl_subsurface_id != INVALID_ID) {
1819
// Window hiding logic.
1820
1821
// wl_subsurface::destroy()
1822
send_wayland_message(compositor_socket, toplevel_data->wl_subsurface_id, 0, {});
1823
1824
toplevel_data->parent_handle.invalidate();
1825
toplevel_data->wl_subsurface_id = INVALID_ID;
1826
1827
return MessageStatus::HANDLED;
1828
}
1829
1830
XdgToplevelData *parent_toplevel_data = (XdgToplevelData *)client->get_object(main_client_parent_id)->data;
1831
ERR_FAIL_NULL_V(parent_toplevel_data, MessageStatus::ERROR);
1832
XdgSurfaceData *parent_xdg_surf_data = (XdgSurfaceData *)parent_toplevel_data->xdg_surface_handle.get()->data;
1833
ERR_FAIL_NULL_V(parent_xdg_surf_data, MessageStatus::ERROR);
1834
1835
XdgSurfaceData *xdg_surf_data = (XdgSurfaceData *)toplevel_data->xdg_surface_handle.get()->data;
1836
ERR_FAIL_NULL_V(xdg_surf_data, MessageStatus::ERROR);
1837
1838
if (toplevel_data->wl_subsurface_id != INVALID_ID) {
1839
// wl_subsurface::destroy()
1840
send_wayland_message(compositor_socket, toplevel_data->wl_subsurface_id, 0, {});
1841
}
1842
1843
uint32_t new_sub_id = allocate_global_id();
1844
WaylandObject *new_sub_object = get_object(new_sub_id);
1845
new_sub_object->interface = &wl_subsurface_interface;
1846
new_sub_object->data = memnew(WaylandSubsurfaceData);
1847
new_sub_object->version = get_object(wl_subcompositor_id)->version;
1848
1849
toplevel_data->wl_subsurface_id = new_sub_id;
1850
toplevel_data->parent_handle = LocalObjectHandle(main_client, main_client_parent_id);
1851
1852
DEBUG_LOG_WAYLAND_EMBED(vformat("Binding subsurface g0x%x.", new_sub_id));
1853
1854
// wl_subcompositor::get_subsurface
1855
send_wayland_message(compositor_socket, wl_subcompositor_id, 1, { new_sub_id, xdg_surf_data->wl_surface_id, parent_xdg_surf_data->wl_surface_id });
1856
1857
// wl_subsurface::set_desync
1858
send_wayland_message(compositor_socket, new_sub_id, 5, {});
1859
1860
return MessageStatus::HANDLED;
1861
} else if (p_opcode == GODOT_EMBEDDED_CLIENT_FOCUS_WINDOW) {
1862
XdgSurfaceData *xdg_surf_data = (XdgSurfaceData *)toplevel_data->xdg_surface_handle.get()->data;
1863
ERR_FAIL_NULL_V(xdg_surf_data, MessageStatus::ERROR);
1864
1865
for (uint32_t wl_seat_name : wl_seat_names) {
1866
RegistryGlobalInfo &global_seat_info = registry_globals[wl_seat_name];
1867
WaylandSeatGlobalData *global_seat_data = (WaylandSeatGlobalData *)global_seat_info.data;
1868
1869
if (global_seat_data->focused_surface_id != INVALID_ID) {
1870
seat_name_leave_surface(wl_seat_name, global_seat_data->focused_surface_id);
1871
}
1872
global_seat_data->focused_surface_id = xdg_surf_data->wl_surface_id;
1873
1874
seat_name_enter_surface(wl_seat_name, xdg_surf_data->wl_surface_id);
1875
}
1876
} else if (p_opcode == GODOT_EMBEDDED_CLIENT_EMBEDDED_WINDOW_REQUEST_CLOSE) {
1877
// xdg_toplevel::close
1878
send_wayland_message(eclient->socket, eclient->embedded_window_id, 1, {});
1879
1880
return MessageStatus::HANDLED;
1881
}
1882
}
1883
1884
// Server-allocated objects are a bit annoying to handle for us. Right now we
1885
// use a heuristic. See: https://ppaalanen.blogspot.com/2014/07/wayland-protocol-design-object-lifespan.html
1886
if (strcmp(message.name, "destroy") == 0 || strcmp(message.name, "release") == 0) {
1887
if (object->shared) {
1888
// We must not delete shared objects.
1889
client->delete_object(local_id);
1890
return MessageStatus::HANDLED;
1891
}
1892
1893
if (global_id != INVALID_ID) {
1894
send_wayland_message(compositor_socket, global_id, p_opcode, {});
1895
object->destroyed = true;
1896
}
1897
1898
if (local_id & 0xff000000) {
1899
DEBUG_LOG_WAYLAND_EMBED(vformat("!!!!!! Deallocating server object l0x%x", local_id));
1900
client->delete_object(local_id);
1901
}
1902
1903
return MessageStatus::HANDLED;
1904
}
1905
1906
if (client->fake_objects.has(local_id)) {
1907
// Object is fake, we're done.
1908
DEBUG_LOG_WAYLAND_EMBED("Dropping unhandled request for fake object.");
1909
return MessageStatus::HANDLED;
1910
}
1911
1912
if (global_id == INVALID_ID) {
1913
DEBUG_LOG_WAYLAND_EMBED("Dropping request with invalid global object id");
1914
return MessageStatus::HANDLED;
1915
}
1916
1917
return MessageStatus::UNHANDLED;
1918
}
1919
1920
WaylandEmbedder::MessageStatus WaylandEmbedder::handle_event(uint32_t p_global_id, LocalObjectHandle p_local_handle, uint32_t p_opcode, const uint32_t *msg_data, size_t msg_len) {
1921
WaylandObject *global_object = get_object(p_global_id);
1922
ERR_FAIL_NULL_V_MSG(global_object, MessageStatus::ERROR, "Compositor messages must always have a global object.");
1923
1924
#ifdef WAYLAND_EMBED_DEBUG_LOGS_ENABLED
1925
ERR_FAIL_NULL_V(global_object->interface, MessageStatus::ERROR);
1926
const struct wl_interface *interface = global_object->interface;
1927
1928
ERR_FAIL_COND_V((int)p_opcode >= interface->event_count, MessageStatus::ERROR);
1929
const struct wl_message message = interface->events[p_opcode];
1930
1931
if (p_local_handle.is_valid()) {
1932
int socket = p_local_handle.get_client()->socket;
1933
DEBUG_LOG_WAYLAND_EMBED(vformat("Client #%d <- %s::%s(%s) g0x%x", socket, interface->name, message.name, message.signature, p_global_id));
1934
} else {
1935
DEBUG_LOG_WAYLAND_EMBED(vformat("Client N/A <- %s::%s(%s) g0x%x", interface->name, message.name, message.signature, p_global_id));
1936
}
1937
#endif //WAYLAND_EMBED_DEBUG_LOGS_ENABLED
1938
1939
const uint32_t *body = msg_data + 2;
1940
//size_t body_len = msg_len - (WL_WORD_SIZE * 2);
1941
1942
// FIXME: Make sure that it makes sense to track this protocol. Not only is it
1943
// old and getting deprecated, but I can't even get this code branch to hit
1944
// probably because, at the time of writing, we only get the "main" display
1945
// through the proxy.
1946
if (global_object->interface == &wl_drm_interface) {
1947
// wl_drm can't ever be destroyed, so we need to track its state as it's going
1948
// to be instanced at least few times.
1949
uint32_t global_name = registry_globals_names[p_global_id];
1950
WaylandDrmGlobalData *global_data = (WaylandDrmGlobalData *)registry_globals[global_name].data;
1951
ERR_FAIL_NULL_V(global_data, MessageStatus::ERROR);
1952
1953
if (p_opcode == WL_DRM_DEVICE) {
1954
// signature: s
1955
uint32_t name_len = body[0];
1956
uint8_t *name = (uint8_t *)(body + 1);
1957
global_data->device = String::utf8((const char *)name, name_len);
1958
1959
return MessageStatus::UNHANDLED;
1960
}
1961
1962
if (p_opcode == WL_DRM_FORMAT) {
1963
// signature: u
1964
uint32_t format = body[0];
1965
global_data->formats.push_back(format);
1966
1967
return MessageStatus::UNHANDLED;
1968
}
1969
1970
if (p_opcode == WL_DRM_AUTHENTICATED) {
1971
// signature: N/A
1972
global_data->authenticated = true;
1973
1974
return MessageStatus::UNHANDLED;
1975
}
1976
1977
if (p_opcode == WL_DRM_CAPABILITIES) {
1978
// signature: u
1979
uint32_t capabilities = body[0];
1980
global_data->capabilities = capabilities;
1981
}
1982
1983
return MessageStatus::UNHANDLED;
1984
}
1985
1986
if (global_object->interface == &wl_shm_interface) {
1987
uint32_t global_name = registry_globals_names[p_global_id];
1988
WaylandShmGlobalData *global_data = (WaylandShmGlobalData *)registry_globals[global_name].data;
1989
ERR_FAIL_NULL_V(global_data, MessageStatus::ERROR);
1990
1991
if (p_opcode == WL_SHM_FORMAT) {
1992
// Signature: u
1993
uint32_t format = body[0];
1994
global_data->formats.push_back(format);
1995
}
1996
}
1997
1998
if (!p_local_handle.is_valid()) {
1999
// Some requests might not have a valid local object handle for various
2000
// reasons, such as when certain events are directed to this proxy or when the
2001
// destination client of a message disconnected in the meantime.
2002
2003
if (global_object->interface == &wl_display_interface) {
2004
if (p_opcode == WL_DISPLAY_DELETE_ID) {
2005
// [Event] wl_display::delete_id(u)
2006
uint32_t global_delete_id = body[0];
2007
DEBUG_LOG_WAYLAND_EMBED(vformat("Compositor requested deletion of g0x%x (no client)", global_delete_id));
2008
2009
delete_object(global_delete_id);
2010
2011
return MessageStatus::HANDLED;
2012
} else if (p_opcode == WL_DISPLAY_ERROR) {
2013
// [Event] wl_display::error(ous)
2014
uint32_t obj_id = body[0];
2015
uint32_t err_code = body[1];
2016
2017
CRASH_NOW_MSG(vformat("Error obj g0x%x code %d: %s", obj_id, err_code, (const char *)(body + 3)));
2018
}
2019
}
2020
2021
if (global_object->interface == &wl_callback_interface && p_opcode == WL_CALLBACK_DONE) {
2022
if (sync_callback_id != INVALID_ID && p_global_id == sync_callback_id) {
2023
sync_callback_id = 0;
2024
DEBUG_LOG_WAYLAND_EMBED("Sync response received");
2025
return MessageStatus::HANDLED;
2026
}
2027
}
2028
2029
if (global_object->interface == &wl_registry_interface) {
2030
if (p_opcode == WL_REGISTRY_GLOBAL) {
2031
// [Event] wl_registry::global(usu).
2032
2033
uint32_t global_name = body[0];
2034
uint32_t interface_name_len = body[1];
2035
const char *interface_name = (const char *)(body + 2);
2036
uint32_t global_version = body[2 + wl_array_word_offset(interface_name_len)];
2037
2038
DEBUG_LOG_WAYLAND_EMBED("Global c#%d %s %d", global_name, interface_name, global_version);
2039
2040
const struct wl_interface *global_interface = wl_interface_from_string(interface_name, interface_name_len);
2041
if (global_interface) {
2042
RegistryGlobalInfo global_info = {};
2043
global_info.interface = global_interface;
2044
global_info.version = MIN(global_version, (uint32_t)global_interface->version);
2045
DEBUG_LOG_WAYLAND_EMBED("Clamped global %s to version %d.", interface_name, global_info.version);
2046
global_info.compositor_name = global_name;
2047
2048
int new_global_name = registry_globals_counter++;
2049
2050
if (global_info.interface == &wl_shm_interface) {
2051
DEBUG_LOG_WAYLAND_EMBED("Allocating global wl_shm data.");
2052
global_info.data = memnew(WaylandShmGlobalData);
2053
}
2054
2055
if (global_info.interface == &wl_seat_interface) {
2056
DEBUG_LOG_WAYLAND_EMBED("Allocating global wl_seat data.");
2057
global_info.data = memnew(WaylandSeatGlobalData);
2058
wl_seat_names.push_back(new_global_name);
2059
}
2060
2061
if (global_info.interface == &wl_drm_interface) {
2062
DEBUG_LOG_WAYLAND_EMBED("Allocating global wl_drm data.");
2063
global_info.data = memnew(WaylandDrmGlobalData);
2064
}
2065
2066
registry_globals[new_global_name] = global_info;
2067
2068
// We need some interfaces directly. It's better to bind a "copy" ourselves
2069
// than to wait for the client to ask one.
2070
if (global_interface == &xdg_wm_base_interface && xdg_wm_base_id == 0) {
2071
xdg_wm_base_id = wl_registry_bind(p_global_id, new_global_name, global_info.version);
2072
ERR_FAIL_COND_V(xdg_wm_base_id == INVALID_ID, MessageStatus::ERROR);
2073
} else if (global_interface == &wl_compositor_interface && wl_compositor_id == 0) {
2074
wl_compositor_id = wl_registry_bind(p_global_id, new_global_name, global_info.version);
2075
ERR_FAIL_COND_V(wl_compositor_id == INVALID_ID, MessageStatus::ERROR);
2076
} else if (global_interface == &wl_subcompositor_interface && wl_subcompositor_id == 0) {
2077
wl_subcompositor_id = wl_registry_bind(p_global_id, new_global_name, global_info.version);
2078
ERR_FAIL_COND_V(wl_subcompositor_id == INVALID_ID, MessageStatus::ERROR);
2079
}
2080
2081
DEBUG_LOG_WAYLAND_EMBED(vformat("Local registry object name: l#%d", new_global_name));
2082
2083
if (clients.is_empty()) {
2084
// Let's not waste time.
2085
return MessageStatus::HANDLED;
2086
}
2087
2088
// Notify all clients.
2089
LocalVector<wl_argument> args;
2090
args.push_back(wl_arg_uint(new_global_name));
2091
args.push_back(wl_arg_string(interface_name));
2092
args.push_back(wl_arg_uint(global_info.version));
2093
for (KeyValue<int, Client> &pair : clients) {
2094
Client &client = pair.value;
2095
for (uint32_t local_registry_id : client.wl_registry_instances) {
2096
send_wayland_event(client.socket, local_registry_id, wl_registry_interface, WL_REGISTRY_GLOBAL, args);
2097
}
2098
}
2099
2100
return MessageStatus::HANDLED;
2101
} else {
2102
DEBUG_LOG_WAYLAND_EMBED("Skipping unknown global %s version %d.", interface_name, global_version);
2103
2104
return MessageStatus::HANDLED;
2105
}
2106
} else if (p_opcode == WL_REGISTRY_GLOBAL_REMOVE) {
2107
uint32_t compositor_name = body[0];
2108
uint32_t local_name = 0;
2109
RegistryGlobalInfo *global_info = nullptr;
2110
2111
// FIXME: Use a map or something.
2112
for (KeyValue<uint32_t, RegistryGlobalInfo> &pair : registry_globals) {
2113
uint32_t name = pair.key;
2114
RegistryGlobalInfo &info = pair.value;
2115
2116
if (info.compositor_name == compositor_name) {
2117
local_name = name;
2118
global_info = &info;
2119
break;
2120
}
2121
}
2122
2123
ERR_FAIL_NULL_V(global_info, MessageStatus::ERROR);
2124
2125
if (global_info->instance_counter == 0) {
2126
memdelete(global_info->data);
2127
registry_globals.erase(local_name);
2128
} else {
2129
global_info->destroyed = true;
2130
}
2131
2132
// Notify all clients.
2133
LocalVector<wl_argument> args;
2134
args.push_back(wl_arg_uint(local_name));
2135
for (KeyValue<int, Client> &pair : clients) {
2136
Client &client = pair.value;
2137
for (uint32_t local_registry_id : client.wl_registry_instances) {
2138
send_wayland_event(client.socket, local_registry_id, wl_registry_interface, WL_REGISTRY_GLOBAL_REMOVE, args);
2139
}
2140
}
2141
2142
return MessageStatus::HANDLED;
2143
}
2144
}
2145
2146
DEBUG_LOG_WAYLAND_EMBED("No valid local object handle, falling back to generic handler.");
2147
return MessageStatus::UNHANDLED;
2148
}
2149
2150
Client *client = p_local_handle.get_client();
2151
2152
ERR_FAIL_NULL_V(client, MessageStatus::ERROR);
2153
2154
WaylandObject *object = p_local_handle.get();
2155
uint32_t local_id = p_local_handle.get_local_id();
2156
2157
if (global_object->interface == &wl_display_interface) {
2158
if (p_opcode == WL_DISPLAY_DELETE_ID) {
2159
// [Event] wl_display::delete_id(u)
2160
uint32_t global_delete_id = body[0];
2161
uint32_t local_delete_id = client->get_local_id(global_delete_id);
2162
DEBUG_LOG_WAYLAND_EMBED(vformat("Compositor requested delete of g0x%x l0x%x", global_delete_id, local_delete_id));
2163
if (local_delete_id == INVALID_ID) {
2164
// No idea what this object is, might be of the other client. This
2165
// definitely does not make sense to us, so we're done.
2166
return MessageStatus::INVALID;
2167
}
2168
2169
client->delete_object(local_delete_id);
2170
2171
send_wayland_message(client->socket, DISPLAY_ID, WL_DISPLAY_DELETE_ID, { local_delete_id });
2172
2173
return MessageStatus::HANDLED;
2174
}
2175
2176
return MessageStatus::UNHANDLED;
2177
}
2178
2179
if (object->interface == &wl_keyboard_interface) {
2180
WaylandKeyboardData *data = (WaylandKeyboardData *)object->data;
2181
ERR_FAIL_NULL_V(data, MessageStatus::ERROR);
2182
2183
uint32_t global_seat_name = registry_globals_names[data->wl_seat_id];
2184
RegistryGlobalInfo &global_seat_info = registry_globals[global_seat_name];
2185
WaylandSeatGlobalData *global_seat_data = (WaylandSeatGlobalData *)global_seat_info.data;
2186
ERR_FAIL_NULL_V(global_seat_data, MessageStatus::ERROR);
2187
2188
if (p_opcode == WL_KEYBOARD_ENTER) {
2189
// [Event] wl_keyboard::enter(uoa)
2190
uint32_t surface = body[1];
2191
2192
if (global_seat_data->focused_surface_id != surface) {
2193
DEBUG_LOG_WAYLAND_EMBED(vformat("Focused g0x%x", surface));
2194
global_seat_data->focused_surface_id = surface;
2195
}
2196
} else if (p_opcode == WL_KEYBOARD_LEAVE) {
2197
// [Event] wl_keyboard::leave(uo)
2198
uint32_t surface = body[1];
2199
2200
if (global_seat_data->focused_surface_id == surface) {
2201
global_seat_data->focused_surface_id = INVALID_ID;
2202
}
2203
} else if (p_opcode == WL_KEYBOARD_KEY) {
2204
// NOTE: modifiers event can be sent even without focus, according to the
2205
// spec, so there's no need to skip it.
2206
if (global_seat_data->focused_surface_id != INVALID_ID && !client->local_ids.has(global_seat_data->focused_surface_id)) {
2207
DEBUG_LOG_WAYLAND_EMBED(vformat("Skipped wl_keyboard event due to unfocused surface 0x%x", global_seat_data->focused_surface_id));
2208
return MessageStatus::HANDLED;
2209
}
2210
}
2211
2212
return MessageStatus::UNHANDLED;
2213
}
2214
2215
if (object->interface == &wl_pointer_interface) {
2216
WaylandPointerData *data = (WaylandPointerData *)object->data;
2217
ERR_FAIL_NULL_V(data, MessageStatus::ERROR);
2218
2219
uint32_t global_seat_name = registry_globals_names[data->wl_seat_id];
2220
RegistryGlobalInfo &global_seat_info = registry_globals[global_seat_name];
2221
WaylandSeatGlobalData *global_seat_data = (WaylandSeatGlobalData *)global_seat_info.data;
2222
ERR_FAIL_NULL_V(global_seat_data, MessageStatus::ERROR);
2223
2224
WaylandSeatInstanceData *seat_data = (WaylandSeatInstanceData *)object->data;
2225
ERR_FAIL_NULL_V(seat_data, MessageStatus::ERROR);
2226
2227
if (p_opcode == WL_POINTER_BUTTON && global_seat_data->pointed_surface_id != INVALID_ID) {
2228
// [Event] wl_pointer::button(uuuu);
2229
uint32_t button = body[2];
2230
uint32_t state = body[3];
2231
2232
DEBUG_LOG_WAYLAND_EMBED(vformat("Button %d state %d on surface g0x%x (focused g0x%x)", button, state, global_seat_data->pointed_surface_id, global_seat_data->focused_surface_id));
2233
2234
bool client_pointed = client->local_ids.has(global_seat_data->pointed_surface_id);
2235
2236
if (button != BTN_LEFT || state != WL_POINTER_BUTTON_STATE_RELEASED) {
2237
return client_pointed ? MessageStatus::UNHANDLED : MessageStatus::HANDLED;
2238
}
2239
2240
if (global_seat_data->focused_surface_id == global_seat_data->pointed_surface_id) {
2241
return client_pointed ? MessageStatus::UNHANDLED : MessageStatus::HANDLED;
2242
}
2243
2244
if (!global_surface_is_window(global_seat_data->pointed_surface_id)) {
2245
return client_pointed ? MessageStatus::UNHANDLED : MessageStatus::HANDLED;
2246
}
2247
2248
if (global_seat_data->focused_surface_id != INVALID_ID) {
2249
seat_name_leave_surface(global_seat_name, global_seat_data->focused_surface_id);
2250
}
2251
2252
global_seat_data->focused_surface_id = global_seat_data->pointed_surface_id;
2253
seat_name_enter_surface(global_seat_name, global_seat_data->focused_surface_id);
2254
} else if (p_opcode == WL_POINTER_ENTER) {
2255
// [Event] wl_pointer::enter(uoff).
2256
uint32_t surface = body[1];
2257
WaylandSurfaceData *surface_data = (WaylandSurfaceData *)get_object(surface)->data;
2258
ERR_FAIL_NULL_V(surface_data, MessageStatus::ERROR);
2259
2260
if (global_seat_data->pointed_surface_id != surface) {
2261
DEBUG_LOG_WAYLAND_EMBED(vformat("Pointer (g0x%x seat g0x%x): pointed surface old g0x%x new g0x%x", p_global_id, data->wl_seat_id, global_seat_data->pointed_surface_id, surface));
2262
2263
global_seat_data->pointed_surface_id = surface;
2264
}
2265
} else if (p_opcode == WL_POINTER_LEAVE) {
2266
// [Event] wl_pointer::leave(uo).
2267
uint32_t surface = body[1];
2268
WaylandSurfaceData *surface_data = (WaylandSurfaceData *)get_object(surface)->data;
2269
ERR_FAIL_NULL_V(surface_data, MessageStatus::ERROR);
2270
2271
if (global_seat_data->pointed_surface_id == surface) {
2272
DEBUG_LOG_WAYLAND_EMBED(vformat("Pointer (g0x%x seat g0x%x): g0x%x -> g0x%x", p_global_id, data->wl_seat_id, global_seat_data->pointed_surface_id, INVALID_ID));
2273
global_seat_data->pointed_surface_id = INVALID_ID;
2274
}
2275
}
2276
2277
return MessageStatus::UNHANDLED;
2278
}
2279
2280
if (object->interface == &xdg_popup_interface) {
2281
if (p_opcode == XDG_POPUP_CONFIGURE) {
2282
// [Event] xdg_popup::configure(iiii);
2283
int32_t x = body[0];
2284
int32_t y = body[1];
2285
int32_t width = body[2];
2286
int32_t height = body[3];
2287
2288
XdgPopupData *data = (XdgPopupData *)object->data;
2289
ERR_FAIL_NULL_V(data, MessageStatus::ERROR);
2290
2291
XdgSurfaceData *parent_xdg_surf_data = (XdgSurfaceData *)data->parent_handle.get()->data;
2292
ERR_FAIL_NULL_V(parent_xdg_surf_data, MessageStatus::ERROR);
2293
2294
WaylandSurfaceData *parent_surface_data = (WaylandSurfaceData *)get_object(parent_xdg_surf_data->wl_surface_id)->data;
2295
ERR_FAIL_NULL_V(parent_surface_data, MessageStatus::ERROR);
2296
2297
WaylandObject *parent_role_obj = parent_surface_data->role_object_handle.get();
2298
ERR_FAIL_NULL_V(parent_role_obj, MessageStatus::ERROR);
2299
2300
if (parent_role_obj->interface == &xdg_toplevel_interface) {
2301
XdgToplevelData *parent_toplevel_data = (XdgToplevelData *)parent_role_obj->data;
2302
ERR_FAIL_NULL_V(parent_toplevel_data, MessageStatus::ERROR);
2303
2304
if (parent_toplevel_data->is_embedded()) {
2305
WaylandSubsurfaceData *subsurf_data = (WaylandSubsurfaceData *)get_object(parent_toplevel_data->wl_subsurface_id)->data;
2306
ERR_FAIL_NULL_V(subsurf_data, MessageStatus::ERROR);
2307
2308
// The coordinates passed will be shifted by the embedded window position,
2309
// so we need to fix them back.
2310
Point2i fixed_position = Point2i(x, y) - subsurf_data->position;
2311
2312
DEBUG_LOG_WAYLAND_EMBED(vformat("Correcting popup configure position to %s", fixed_position));
2313
2314
send_wayland_message(client->socket, local_id, p_opcode, { (uint32_t)fixed_position.x, (uint32_t)fixed_position.y, (uint32_t)width, (uint32_t)height });
2315
2316
return MessageStatus::HANDLED;
2317
}
2318
}
2319
}
2320
}
2321
2322
return MessageStatus::UNHANDLED;
2323
}
2324
2325
void WaylandEmbedder::shutdown() {
2326
thread_done.set();
2327
2328
{
2329
// First making a list of all clients so that we can iteratively delete them.
2330
LocalVector<int> sockets;
2331
for (KeyValue<int, Client> &pair : clients) {
2332
sockets.push_back(pair.key);
2333
}
2334
2335
for (int socket : sockets) {
2336
cleanup_socket(socket);
2337
}
2338
}
2339
2340
close(compositor_socket);
2341
compositor_socket = -1;
2342
2343
for (KeyValue<uint32_t, RegistryGlobalInfo> &pair : registry_globals) {
2344
RegistryGlobalInfo &info = pair.value;
2345
if (info.data) {
2346
memdelete(info.data);
2347
info.data = nullptr;
2348
}
2349
}
2350
}
2351
2352
Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *info, uint32_t *buf, int *fds_requested) {
2353
ERR_FAIL_NULL_V(info, ERR_BUG);
2354
ERR_FAIL_NULL_V(fds_requested, ERR_BUG);
2355
ERR_FAIL_NULL_V_MSG(info->direction == ProxyDirection::COMPOSITOR && client, ERR_BUG, "Wait, where did this message come from?");
2356
2357
*fds_requested = 0;
2358
2359
WaylandObject *object = nullptr;
2360
2361
uint32_t global_id = INVALID_ID;
2362
if (info->direction == ProxyDirection::CLIENT) {
2363
global_id = info->raw_id;
2364
} else if (info->direction == ProxyDirection::COMPOSITOR) {
2365
global_id = client->get_global_id(info->raw_id);
2366
}
2367
2368
if (global_id != INVALID_ID) {
2369
object = get_object(global_id);
2370
} else if (client) {
2371
object = client->get_object(info->raw_id);
2372
}
2373
2374
if (object == nullptr) {
2375
if (info->direction == ProxyDirection::COMPOSITOR) {
2376
uint32_t local_id = info->raw_id;
2377
ERR_PRINT(vformat("Couldn't find requested object l0x%x for client %d, disconnecting.", local_id, client->socket));
2378
2379
socket_error(client->socket, local_id, WL_DISPLAY_ERROR_INVALID_OBJECT, vformat("Object l0x%x not found.", local_id));
2380
return OK;
2381
} else {
2382
CRASH_NOW_MSG(vformat("No object found for r0x%x", info->raw_id));
2383
}
2384
}
2385
2386
const struct wl_interface *interface = nullptr;
2387
interface = object->interface;
2388
2389
if (interface == nullptr && info->raw_id & 0xff000000) {
2390
// Regular clients have no confirmation about deleted server objects (why
2391
// should they?) but since we share connections there's the risk of receiving
2392
// messages about deleted server objects. The simplest solution is to ignore
2393
// unknown server-side objects. Not the safest thing, I know, but it should do
2394
// the job.
2395
DEBUG_LOG_WAYLAND_EMBED(vformat("Ignoring unknown server-side object r0x%x", info->raw_id));
2396
return OK;
2397
}
2398
2399
ERR_FAIL_NULL_V_MSG(interface, ERR_BUG, vformat("Object r0x%x has no interface", info->raw_id));
2400
2401
const struct wl_message *message = nullptr;
2402
if (info->direction == ProxyDirection::CLIENT) {
2403
ERR_FAIL_COND_V(info->opcode >= interface->event_count, ERR_BUG);
2404
message = &interface->events[info->opcode];
2405
} else {
2406
ERR_FAIL_COND_V(info->opcode >= interface->method_count, ERR_BUG);
2407
message = &interface->methods[info->opcode];
2408
}
2409
ERR_FAIL_NULL_V(message, ERR_BUG);
2410
2411
*fds_requested = String(message->signature).count("h");
2412
LocalVector<int> sent_fds;
2413
2414
if (*fds_requested > 0) {
2415
DEBUG_LOG_WAYLAND_EMBED(vformat("Requested %d FDs.", *fds_requested));
2416
2417
List<int> &fd_queue = info->direction == ProxyDirection::COMPOSITOR ? client->fds : compositor_fds;
2418
for (int i = 0; i < *fds_requested; ++i) {
2419
ERR_FAIL_COND_V_MSG(fd_queue.is_empty(), ERR_BUG, "Out of FDs.");
2420
DEBUG_LOG_WAYLAND_EMBED(vformat("Fetching FD %d.", fd_queue.front()->get()));
2421
sent_fds.push_back(fd_queue.front()->get());
2422
fd_queue.pop_front();
2423
}
2424
2425
DEBUG_LOG_WAYLAND_EMBED(vformat("Remaining FDs: %d.", fd_queue.size()));
2426
}
2427
2428
if (object->destroyed) {
2429
DEBUG_LOG_WAYLAND_EMBED("Ignoring message for inert object.");
2430
// Inert object.
2431
return OK;
2432
}
2433
2434
if (info->direction == ProxyDirection::COMPOSITOR) {
2435
MessageStatus request_status = handle_request(LocalObjectHandle(client, info->raw_id), info->opcode, buf, info->size);
2436
if (request_status == MessageStatus::ERROR) {
2437
return ERR_BUG;
2438
}
2439
2440
if (request_status == MessageStatus::HANDLED) {
2441
DEBUG_LOG_WAYLAND_EMBED("Custom handler success.");
2442
return OK;
2443
}
2444
2445
if (global_id != INVALID_ID) {
2446
buf[0] = global_id;
2447
}
2448
2449
DEBUG_LOG_WAYLAND_EMBED("Falling back to generic handler.");
2450
2451
if (handle_generic_msg(client, object, message, info, buf)) {
2452
send_raw_message(compositor_socket, { { buf, info->size } }, sent_fds);
2453
}
2454
} else {
2455
uint32_t global_name = 0;
2456
2457
bool is_global = false;
2458
if (registry_globals_names.has(global_id)) {
2459
global_name = registry_globals_names[global_id];
2460
is_global = true;
2461
}
2462
2463
// FIXME: For compatibility, mirror events with instanced registry globals as
2464
// object arguments. For example, `wl_surface.enter` returns a `wl_output`. If
2465
// said `wl_output` has been instanced multiple times, we need to resend the
2466
// same event with each instance as the argument, or the client might miss the
2467
// event by looking for the "wrong" instance.
2468
//
2469
// Note that this missing behavior is exclusively a compatibility mechanism
2470
// for old compositors which only implement undestroyable globals. We
2471
// otherwise passthrough every bind request and then the compositor takes care
2472
// of everything.
2473
// See: https://lore.freedesktop.org/wayland-devel/[email protected]/
2474
if (object->shared) {
2475
bool handled = false;
2476
2477
for (KeyValue<int, Client> &pair : clients) {
2478
Client &c = pair.value;
2479
if (c.socket < 0) {
2480
continue;
2481
}
2482
2483
if (!c.local_ids.has(global_id)) {
2484
DEBUG_LOG_WAYLAND_EMBED("!!!!!!!!!!! Instance missing?");
2485
continue;
2486
}
2487
2488
if (is_global) {
2489
if (!c.registry_globals_instances.has(global_name)) {
2490
continue;
2491
}
2492
2493
DEBUG_LOG_WAYLAND_EMBED(vformat("Broadcasting to all global instances for client %d (socket %d)", c.pid, c.socket));
2494
for (uint32_t instance_id : c.registry_globals_instances[global_name]) {
2495
DEBUG_LOG_WAYLAND_EMBED(vformat("Global instance l0x%x", instance_id));
2496
2497
LocalObjectHandle local_obj = LocalObjectHandle(&c, instance_id);
2498
if (!local_obj.is_valid()) {
2499
continue;
2500
}
2501
2502
MessageStatus event_status = handle_event(global_id, local_obj, info->opcode, buf, info->size);
2503
2504
if (event_status == MessageStatus::ERROR) {
2505
return ERR_BUG;
2506
}
2507
2508
if (event_status == MessageStatus::HANDLED) {
2509
DEBUG_LOG_WAYLAND_EMBED("Custom handler success.");
2510
handled = true;
2511
continue;
2512
}
2513
2514
if (event_status == MessageStatus::INVALID) {
2515
continue;
2516
}
2517
2518
DEBUG_LOG_WAYLAND_EMBED("Falling back to generic handler.");
2519
2520
buf[0] = instance_id;
2521
2522
if (handle_generic_msg(&c, local_obj.get(), message, info, buf, instance_id)) {
2523
send_raw_message(c.socket, { { buf, info->size } }, sent_fds);
2524
}
2525
2526
handled = true;
2527
}
2528
} else if (interface == &wl_display_interface) {
2529
// NOTE: The only shared non-global objects are `wl_display` and
2530
// `wl_registry`, both of which require custom handlers. Additionally, of
2531
// those only `wl_display` has client-specific handlers, which is what this
2532
// branch manages.
2533
2534
LocalObjectHandle local_obj = LocalObjectHandle(&c, c.get_local_id(global_id));
2535
if (!local_obj.is_valid()) {
2536
continue;
2537
}
2538
2539
DEBUG_LOG_WAYLAND_EMBED(vformat("Shared non-global l0x%x g0x%x", c.get_local_id(global_id), global_id));
2540
2541
MessageStatus event_status = handle_event(global_id, local_obj, info->opcode, buf, info->size);
2542
if (event_status == MessageStatus::ERROR) {
2543
return ERR_BUG;
2544
}
2545
2546
if (event_status == MessageStatus::HANDLED) {
2547
DEBUG_LOG_WAYLAND_EMBED("Custom handler success.");
2548
handled = true;
2549
continue;
2550
}
2551
2552
if (event_status == MessageStatus::INVALID) {
2553
continue;
2554
}
2555
2556
DEBUG_LOG_WAYLAND_EMBED("Falling back to generic handler.");
2557
2558
if (handle_generic_msg(&c, local_obj.get(), message, info, buf)) {
2559
send_raw_message(c.socket, { { buf, info->size } }, sent_fds);
2560
}
2561
2562
handled = true;
2563
}
2564
}
2565
2566
if (!handled) {
2567
// No client handled this, it's going to be handled as a client-less event.
2568
// We do this only at the end to avoid handling certain events (e.g.
2569
// deletion) twice.
2570
handle_event(global_id, LocalObjectHandle(nullptr, INVALID_ID), info->opcode, buf, info->size);
2571
}
2572
} else {
2573
LocalObjectHandle local_obj = LocalObjectHandle(client, client ? client->get_local_id(global_id) : INVALID_ID);
2574
2575
MessageStatus event_status = handle_event(global_id, local_obj, info->opcode, buf, info->size);
2576
if (event_status == MessageStatus::ERROR) {
2577
return ERR_BUG;
2578
}
2579
2580
if (event_status == MessageStatus::HANDLED || event_status == MessageStatus::INVALID) {
2581
// We're done.
2582
return OK;
2583
}
2584
2585
// Generic passthrough.
2586
2587
if (client) {
2588
uint32_t local_id = client->get_local_id(global_id);
2589
ERR_FAIL_COND_V(local_id == INVALID_ID, OK);
2590
2591
DEBUG_LOG_WAYLAND_EMBED(vformat("%s::%s(%s) g0x%x -> l0x%x", interface->name, message->name, message->signature, global_id, local_id));
2592
buf[0] = local_id;
2593
2594
if (handle_generic_msg(client, local_obj.get(), message, info, buf)) {
2595
send_raw_message(client->socket, { { buf, info->size } }, sent_fds);
2596
}
2597
} else {
2598
WARN_PRINT_ONCE(vformat("[Wayland Embedder] Unexpected client-less event from %s#g0x%x. Object has probably leaked.", object->interface->name, global_id));
2599
handle_generic_msg(nullptr, object, message, info, buf);
2600
}
2601
}
2602
}
2603
2604
for (int fd : sent_fds) {
2605
DEBUG_LOG_WAYLAND_EMBED(vformat("Closing fd %d.", fd));
2606
close(fd);
2607
}
2608
2609
return OK;
2610
}
2611
2612
Error WaylandEmbedder::handle_sock(int p_fd) {
2613
ERR_FAIL_COND_V(p_fd < 0, ERR_INVALID_PARAMETER);
2614
2615
struct msg_info info = {};
2616
2617
{
2618
struct msghdr head_msg = {};
2619
uint32_t header[2];
2620
struct iovec vec = { header, sizeof header };
2621
2622
head_msg.msg_iov = &vec;
2623
head_msg.msg_iovlen = 1;
2624
2625
ssize_t head_rec = recvmsg(p_fd, &head_msg, MSG_PEEK);
2626
2627
if (head_rec == 0) {
2628
// Client disconnected.
2629
return ERR_CONNECTION_ERROR;
2630
}
2631
2632
if (head_rec == -1) {
2633
if (errno == ECONNRESET) {
2634
// No need to print the error, the client forcefully disconnected, that's
2635
// fine.
2636
return ERR_CONNECTION_ERROR;
2637
}
2638
2639
ERR_FAIL_V_MSG(FAILED, vformat("Can't read message header: %s", strerror(errno)));
2640
}
2641
2642
ERR_FAIL_COND_V_MSG(((size_t)head_rec) != vec.iov_len, ERR_CONNECTION_ERROR, vformat("Should've received %d bytes, instead got %d bytes", vec.iov_len, head_rec));
2643
2644
// Header is two 32-bit words: first is ID, second has size in most significant
2645
// half and opcode in the other half.
2646
info.raw_id = header[0];
2647
info.size = header[1] >> 16;
2648
info.opcode = header[1] & 0xFFFF;
2649
info.direction = p_fd != compositor_socket ? ProxyDirection::COMPOSITOR : ProxyDirection::CLIENT;
2650
}
2651
2652
if (msg_buf.size() < info.words()) {
2653
msg_buf.resize(info.words());
2654
}
2655
2656
ERR_FAIL_COND_V_MSG(info.size % WL_WORD_SIZE != 0, ERR_CONNECTION_ERROR, "Invalid message length.");
2657
2658
struct msghdr full_msg = {};
2659
struct iovec vec = { msg_buf.ptr(), info.size };
2660
{
2661
full_msg.msg_iov = &vec;
2662
full_msg.msg_iovlen = 1;
2663
full_msg.msg_control = ancillary_buf.ptr();
2664
full_msg.msg_controllen = ancillary_buf.size();
2665
2666
ssize_t full_rec = recvmsg(p_fd, &full_msg, 0);
2667
2668
if (full_rec == -1) {
2669
if (errno == ECONNRESET) {
2670
// No need to print the error, the client forcefully disconnected, that's
2671
// fine.
2672
return ERR_CONNECTION_ERROR;
2673
}
2674
2675
ERR_FAIL_V_MSG(FAILED, vformat("Can't read message: %s", strerror(errno)));
2676
}
2677
2678
ERR_FAIL_COND_V_MSG(((size_t)full_rec) != info.size, ERR_CONNECTION_ERROR, "Invalid message length.");
2679
2680
DEBUG_LOG_WAYLAND_EMBED(" === START PACKET === ");
2681
2682
#ifdef WAYLAND_EMBED_DEBUG_LOGS_ENABLED
2683
printf("[PROXY] Received bytes: ");
2684
for (ssize_t i = 0; i < full_rec; ++i) {
2685
printf("%.2x", ((const uint8_t *)msg_buf.ptr())[i]);
2686
}
2687
printf("\n");
2688
#endif
2689
}
2690
2691
if (full_msg.msg_controllen > 0) {
2692
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&full_msg);
2693
while (cmsg) {
2694
// TODO: Check for validity of message fields.
2695
size_t data_len = cmsg->cmsg_len - sizeof *cmsg;
2696
2697
if (cmsg->cmsg_type == SCM_RIGHTS) {
2698
// NOTE: Linux docs say that we can't just cast data to pointer type because
2699
// of alignment concerns. So we have to memcpy into a new buffer.
2700
int *cmsg_fds = (int *)malloc(data_len);
2701
memcpy(cmsg_fds, CMSG_DATA(cmsg), data_len);
2702
2703
size_t cmsg_fds_count = data_len / sizeof *cmsg_fds;
2704
for (size_t i = 0; i < cmsg_fds_count; ++i) {
2705
int fd = cmsg_fds[i];
2706
2707
if (info.direction == ProxyDirection::COMPOSITOR) {
2708
clients[p_fd].fds.push_back(fd);
2709
} else {
2710
compositor_fds.push_back(fd);
2711
}
2712
}
2713
2714
#ifdef WAYLAND_EMBED_DEBUG_LOGS_ENABLED
2715
printf("[PROXY] Received %ld file descriptors: ", cmsg_fds_count);
2716
for (size_t i = 0; i < cmsg_fds_count; ++i) {
2717
printf("%d ", cmsg_fds[i]);
2718
}
2719
printf("\n");
2720
#endif
2721
2722
free(cmsg_fds);
2723
}
2724
2725
cmsg = CMSG_NXTHDR(&full_msg, cmsg);
2726
}
2727
}
2728
full_msg.msg_control = nullptr;
2729
full_msg.msg_controllen = 0;
2730
2731
int fds_requested = 0;
2732
2733
Client *client = nullptr;
2734
if (p_fd == compositor_socket) {
2735
// Let's figure out the recipient of the message.
2736
for (KeyValue<int, Client> &pair : clients) {
2737
Client &c = pair.value;
2738
2739
if (c.local_ids.has(info.raw_id)) {
2740
client = &c;
2741
}
2742
}
2743
} else {
2744
CRASH_COND(!clients.has(p_fd));
2745
client = &clients[p_fd];
2746
}
2747
2748
if (handle_msg_info(client, &info, msg_buf.ptr(), &fds_requested) != OK) {
2749
return ERR_BUG;
2750
}
2751
2752
DEBUG_LOG_WAYLAND_EMBED(" === END PACKET === ");
2753
2754
return OK;
2755
}
2756
2757
void WaylandEmbedder::_thread_loop(void *p_data) {
2758
Thread::set_name("Wayland Embed");
2759
2760
ERR_FAIL_NULL(p_data);
2761
WaylandEmbedder *proxy = (WaylandEmbedder *)p_data;
2762
2763
DEBUG_LOG_WAYLAND_EMBED("Proxy thread started");
2764
2765
while (!proxy->thread_done.is_set()) {
2766
proxy->poll_sockets();
2767
}
2768
}
2769
2770
Error WaylandEmbedder::init() {
2771
ancillary_buf.resize(EMBED_ANCILLARY_BUF_SIZE);
2772
2773
proxy_socket = socket(AF_UNIX, SOCK_STREAM, 0);
2774
2775
struct sockaddr_un addr = {};
2776
addr.sun_family = AF_UNIX;
2777
2778
String runtime_dir_path = OS::get_singleton()->get_environment("XDG_RUNTIME_DIR");
2779
ERR_FAIL_COND_V_MSG(runtime_dir_path.is_empty(), ERR_DOES_NOT_EXIST, "XDG_RUNTIME_DIR is not set or empty.");
2780
2781
runtime_dir = DirAccess::create_for_path(runtime_dir_path);
2782
ERR_FAIL_COND_V(!runtime_dir.is_valid(), ERR_BUG);
2783
ERR_FAIL_COND_V_MSG(!runtime_dir->is_writable(runtime_dir_path), ERR_FILE_CANT_WRITE, "XDG_RUNTIME_DIR points to an invalid directory.");
2784
2785
int socket_id = 0;
2786
while (socket_path.is_empty()) {
2787
String test_socket_path = runtime_dir_path + "/godot-wayland-" + itos(socket_id);
2788
String test_socket_lock_path = test_socket_path + ".lock";
2789
2790
print_verbose(vformat("Trying to get socket %s", test_socket_path));
2791
print_verbose(vformat("Opening lock %s", test_socket_lock_path));
2792
int test_lock_fd = open(test_socket_lock_path.utf8().get_data(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
2793
2794
if (flock(test_lock_fd, LOCK_EX | LOCK_NB) == -1) {
2795
print_verbose(vformat("Can't lock %s", test_socket_lock_path));
2796
close(test_lock_fd);
2797
++socket_id;
2798
continue;
2799
} else {
2800
lock_fd = test_lock_fd;
2801
socket_path = test_socket_path;
2802
socket_lock_path = test_socket_lock_path;
2803
2804
break;
2805
}
2806
}
2807
2808
DirAccess::remove_absolute(socket_path);
2809
strncpy(addr.sun_path, socket_path.utf8().get_data(), sizeof(addr.sun_path) - 1);
2810
2811
if (bind(proxy_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
2812
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't bind embedding socket.");
2813
}
2814
2815
if (listen(proxy_socket, 1) == -1) {
2816
ERR_FAIL_V_MSG(ERR_CANT_OPEN, "Can't listen embedding socket.");
2817
}
2818
2819
struct wl_display *display = wl_display_connect(nullptr);
2820
ERR_FAIL_NULL_V(display, ERR_CANT_OPEN);
2821
compositor_socket = wl_display_get_fd(display);
2822
2823
pollfds.push_back({ proxy_socket, POLLIN, 0 });
2824
pollfds.push_back({ compositor_socket, POLLIN, 0 });
2825
2826
RegistryGlobalInfo control_global_info = {};
2827
control_global_info.interface = &godot_embedding_compositor_interface;
2828
control_global_info.version = godot_embedding_compositor_interface.version;
2829
2830
godot_embedding_compositor_name = registry_globals_counter++;
2831
registry_globals[godot_embedding_compositor_name] = control_global_info;
2832
2833
{
2834
uint32_t invalid_id = INVALID_ID;
2835
objects.request(invalid_id);
2836
2837
CRASH_COND(invalid_id != INVALID_ID);
2838
}
2839
2840
{
2841
uint32_t display_id = new_object(&wl_display_interface);
2842
CRASH_COND(display_id != DISPLAY_ID);
2843
2844
get_object(DISPLAY_ID)->shared = true;
2845
}
2846
2847
{
2848
uint32_t registry_id = new_object(&wl_registry_interface);
2849
CRASH_COND(registry_id != REGISTRY_ID);
2850
2851
get_object(REGISTRY_ID)->shared = true;
2852
}
2853
2854
// wl_display::get_registry(n)
2855
send_wayland_message(compositor_socket, DISPLAY_ID, 1, { REGISTRY_ID });
2856
2857
sync();
2858
2859
proxy_thread.start(_thread_loop, this);
2860
2861
return OK;
2862
}
2863
2864
void WaylandEmbedder::handle_fd(int p_fd, int p_revents) {
2865
if (p_fd == proxy_socket && p_revents & POLLIN) {
2866
// Client init.
2867
int new_fd = accept(proxy_socket, nullptr, nullptr);
2868
ERR_FAIL_COND_MSG(new_fd == -1, "Failed to accept client.");
2869
2870
struct ucred cred = {};
2871
socklen_t cred_size = sizeof cred;
2872
getsockopt(new_fd, SOL_SOCKET, SO_PEERCRED, &cred, &cred_size);
2873
2874
Client &client = clients.insert_new(new_fd, {})->value;
2875
2876
client.embedder = this;
2877
client.socket = new_fd;
2878
client.pid = cred.pid;
2879
2880
client.global_ids[DISPLAY_ID] = Client::GlobalIdInfo(DISPLAY_ID, nullptr);
2881
client.local_ids[DISPLAY_ID] = DISPLAY_ID;
2882
2883
pollfds.push_back({ new_fd, POLLIN, 0 });
2884
2885
if (main_client == nullptr) {
2886
main_client = &client;
2887
}
2888
2889
if (new_fd != main_client->socket && main_client->registry_globals_instances.has(godot_embedding_compositor_name)) {
2890
uint32_t new_local_id = main_client->allocate_server_id();
2891
2892
client.embedded_client_id = new_local_id;
2893
2894
for (uint32_t local_id : main_client->registry_globals_instances[godot_embedding_compositor_name]) {
2895
EmbeddedClientData *eclient_data = memnew(EmbeddedClientData);
2896
eclient_data->client = &client;
2897
2898
main_client->new_fake_object(new_local_id, &godot_embedded_client_interface, 1, eclient_data);
2899
2900
// godot_embedding_compositor::client(nu)
2901
send_wayland_message(main_client->socket, local_id, 0, { new_local_id, (uint32_t)cred.pid });
2902
}
2903
}
2904
2905
DEBUG_LOG_WAYLAND_EMBED(vformat("New client %d (pid %d) initialized.", client.socket, cred.pid));
2906
return;
2907
}
2908
2909
if (p_fd == compositor_socket && p_revents & POLLIN) {
2910
Error err = handle_sock(p_fd);
2911
2912
if (err == ERR_BUG) {
2913
ERR_PRINT("Unexpected error while handling socket, shutting down.");
2914
shutdown();
2915
return;
2916
}
2917
2918
return;
2919
}
2920
2921
const Client *client = clients.getptr(p_fd);
2922
if (client) {
2923
if (main_client && client == main_client && p_revents & (POLLHUP | POLLERR)) {
2924
DEBUG_LOG_WAYLAND_EMBED("Main client disconnected, shutting down.");
2925
shutdown();
2926
return;
2927
}
2928
2929
if (p_revents & POLLIN) {
2930
Error err = handle_sock(p_fd);
2931
if (err == ERR_BUG) {
2932
ERR_PRINT("Unexpected error while handling socket, shutting down.");
2933
shutdown();
2934
return;
2935
}
2936
2937
if (err != OK) {
2938
DEBUG_LOG_WAYLAND_EMBED("disconnecting");
2939
cleanup_socket(p_fd);
2940
return;
2941
}
2942
2943
return;
2944
} else if (p_revents & (POLLHUP | POLLERR | POLLNVAL)) {
2945
if (p_revents & POLLHUP) {
2946
DEBUG_LOG_WAYLAND_EMBED(vformat("Socket %d hangup.", p_fd));
2947
}
2948
if (p_revents & POLLERR) {
2949
DEBUG_LOG_WAYLAND_EMBED(vformat("Socket %d error.", p_fd));
2950
}
2951
if (p_revents & POLLNVAL) {
2952
DEBUG_LOG_WAYLAND_EMBED(vformat("Socket %d invalid FD.", p_fd));
2953
}
2954
2955
cleanup_socket(p_fd);
2956
2957
return;
2958
}
2959
}
2960
}
2961
2962
WaylandEmbedder::~WaylandEmbedder() {
2963
shutdown();
2964
if (proxy_thread.is_started()) {
2965
proxy_thread.wait_to_finish();
2966
}
2967
}
2968
2969
#endif // TOOLS_ENABLED
2970
2971
#endif // WAYLAND_ENABLED
2972
2973