Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/platform/linuxbsd/wayland/wayland_embedder.cpp
20942 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
#ifdef WAYLAND_EMBED_DEBUG_LOGS_ENABLED
1119
if (last_str_len > 0) {
1120
DEBUG_LOG_WAYLAND_EMBED(vformat("Unknown interface %s, marking packet as invalid.", (char *)(body + last_str_buf_idx + 1)));
1121
} else {
1122
DEBUG_LOG_WAYLAND_EMBED("Unknown interface, marking packet as invalid.");
1123
}
1124
#endif
1125
valid = false;
1126
break;
1127
}
1128
1129
if (info->direction == ProxyDirection::COMPOSITOR) {
1130
// FIXME: Create objects only if the packet is valid.
1131
uint32_t new_local_id = arg;
1132
body[buf_idx] = client->new_object(new_local_id, new_interface, new_version);
1133
1134
if (body[buf_idx] == INVALID_ID) {
1135
valid = false;
1136
break;
1137
}
1138
1139
} else if (info->direction == ProxyDirection::CLIENT) {
1140
uint32_t new_global_id = arg;
1141
1142
if (client) {
1143
body[buf_idx] = client->new_server_object(new_global_id, new_interface, new_version);
1144
} else {
1145
new_server_object(new_global_id, new_interface, new_version);
1146
}
1147
1148
if (body[buf_idx] == INVALID_ID) {
1149
valid = false;
1150
break;
1151
}
1152
}
1153
} break;
1154
1155
case 'o': {
1156
if (!client) {
1157
break;
1158
}
1159
1160
uint32_t obj_id = body[buf_idx];
1161
if (obj_id == 0) {
1162
// Object arguments can be nil.
1163
break;
1164
}
1165
1166
if (info->direction == ProxyDirection::CLIENT) {
1167
if (!client->local_ids.has(obj_id)) {
1168
DEBUG_LOG_WAYLAND_EMBED(vformat("Object argument g0x%x not found, marking packet as invalid.", obj_id));
1169
valid = false;
1170
break;
1171
}
1172
body[buf_idx] = instance_id != INVALID_ID ? instance_id : client->get_local_id(obj_id);
1173
} else if (info->direction == ProxyDirection::COMPOSITOR) {
1174
if (!client->global_ids.has(obj_id)) {
1175
DEBUG_LOG_WAYLAND_EMBED(vformat("Object argument l0x%x not found, marking packet as invalid.", obj_id));
1176
valid = false;
1177
break;
1178
}
1179
body[buf_idx] = client->get_global_id(obj_id);
1180
}
1181
} break;
1182
}
1183
1184
++arg_idx;
1185
++buf_idx;
1186
}
1187
1188
return valid;
1189
}
1190
1191
WaylandEmbedder::MessageStatus WaylandEmbedder::handle_request(LocalObjectHandle p_object, uint32_t p_opcode, const uint32_t *msg_data, size_t msg_len) {
1192
ERR_FAIL_COND_V(!p_object.is_valid(), MessageStatus::HANDLED);
1193
1194
WaylandObject *object = p_object.get();
1195
Client *client = p_object.get_client();
1196
1197
ERR_FAIL_NULL_V(object, MessageStatus::HANDLED);
1198
1199
// NOTE: Global ID may be null.
1200
uint32_t global_id = p_object.get_global_id();
1201
uint32_t local_id = p_object.get_local_id();
1202
1203
ERR_FAIL_NULL_V(object->interface, MessageStatus::ERROR);
1204
const struct wl_interface *interface = object->interface;
1205
1206
ERR_FAIL_COND_V((int)p_opcode >= interface->method_count, MessageStatus::ERROR);
1207
const struct wl_message message = interface->methods[p_opcode];
1208
1209
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));
1210
1211
const uint32_t *body = msg_data + 2;
1212
1213
if (registry_globals_names.has(global_id)) {
1214
int global_name = registry_globals_names[global_id];
1215
ERR_FAIL_COND_V(!registry_globals.has(global_name), MessageStatus::ERROR);
1216
RegistryGlobalInfo &global_info = registry_globals[global_name];
1217
1218
if (global_info.destroyed) {
1219
DEBUG_LOG_WAYLAND_EMBED("Skipping request for destroyed global object");
1220
return MessageStatus::HANDLED;
1221
}
1222
}
1223
1224
if (object->interface == &wl_display_interface && p_opcode == WL_DISPLAY_GET_REGISTRY) {
1225
// The gist of this is that the registry is a global and the compositor can
1226
// quite simply take for granted that a single client can access any global
1227
// bound from any registry. Let's remove all doubts by using a single
1228
// registry (also for efficiency) and doing fancy remaps.
1229
uint32_t local_registry_id = body[0];
1230
1231
// Note that the registry has already been allocated in the initialization
1232
// routine.
1233
1234
for (KeyValue<uint32_t, RegistryGlobalInfo> &pair : registry_globals) {
1235
uint32_t global_name = pair.key;
1236
RegistryGlobalInfo &global_info = pair.value;
1237
1238
if (global_info.destroyed) {
1239
continue;
1240
}
1241
1242
const struct wl_interface *global_interface = global_info.interface;
1243
1244
if (client != main_client && embedded_interface_deny_list.has(global_interface)) {
1245
DEBUG_LOG_WAYLAND_EMBED(vformat("Skipped global announcement %s for embedded client.", global_interface->name));
1246
continue;
1247
}
1248
1249
LocalVector<union wl_argument> args;
1250
args.push_back(wl_arg_uint(global_name));
1251
args.push_back(wl_arg_string(global_interface->name));
1252
args.push_back(wl_arg_uint(global_info.version));
1253
1254
send_wayland_event(client->socket, local_registry_id, wl_registry_interface, WL_REGISTRY_GLOBAL, args);
1255
}
1256
1257
client->wl_registry_instances.insert(local_registry_id);
1258
client->new_global_instance(local_registry_id, REGISTRY_ID, &wl_registry_interface, 1);
1259
1260
return MessageStatus::HANDLED;
1261
}
1262
1263
if (object->interface == &wl_registry_interface) {
1264
if (p_opcode == WL_REGISTRY_BIND) {
1265
// [Request] wl_registry::bind(usun)
1266
uint32_t global_name = body[0];
1267
uint32_t interface_name_len = body[1];
1268
//const char *interface_name = (const char *)(body + 2);
1269
uint32_t version = body[2 + wl_array_word_offset(interface_name_len)];
1270
uint32_t new_local_id_idx = 2 + wl_array_word_offset(interface_name_len) + 1;
1271
uint32_t new_local_id = body[new_local_id_idx];
1272
1273
if (!registry_globals.has(global_name)) {
1274
socket_error(client->socket, local_id, WL_DISPLAY_ERROR_INVALID_METHOD, vformat("Invalid global object #%d", global_name));
1275
return MessageStatus::HANDLED;
1276
}
1277
1278
RegistryGlobalInfo &global_info = registry_globals[global_name];
1279
ERR_FAIL_NULL_V(global_info.interface, MessageStatus::ERROR);
1280
1281
version = MIN(global_info.version, version);
1282
1283
if (global_info.interface == &godot_embedding_compositor_interface) {
1284
if (!client->registry_globals_instances.has(global_name)) {
1285
client->registry_globals_instances[global_name] = {};
1286
}
1287
1288
client->registry_globals_instances[global_name].insert(new_local_id);
1289
++global_info.instance_counter;
1290
DEBUG_LOG_WAYLAND_EMBED("Bound embedded compositor interface.");
1291
client->new_fake_object(new_local_id, &godot_embedding_compositor_interface, 1);
1292
return MessageStatus::HANDLED;
1293
}
1294
1295
WaylandObject *instance = nullptr;
1296
1297
client->registry_globals_instances[global_name].insert(new_local_id);
1298
++global_info.instance_counter;
1299
1300
if (!client->registry_globals_instances.has(global_name)) {
1301
client->registry_globals_instances[global_name] = {};
1302
}
1303
1304
uint32_t bind_gid = wl_registry_bind(REGISTRY_ID, global_name, version);
1305
if (bind_gid == INVALID_ID) {
1306
socket_error(client->socket, local_id, WL_DISPLAY_ERROR_IMPLEMENTATION, "Bind failed.");
1307
return MessageStatus::HANDLED;
1308
}
1309
1310
WaylandObject *bind_obj = get_object(bind_gid);
1311
if (bind_obj == nullptr) {
1312
socket_error(client->socket, local_id, WL_DISPLAY_ERROR_IMPLEMENTATION, "Bind failed.");
1313
return MessageStatus::HANDLED;
1314
}
1315
1316
if (!bind_obj->shared) {
1317
client->bind_global_id(bind_gid, new_local_id);
1318
instance = bind_obj;
1319
} else {
1320
instance = client->new_global_instance(new_local_id, global_info.reusable_objects[version], global_info.interface, version);
1321
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]));
1322
1323
// Some interfaces report their state as soon as they're bound. Since
1324
// instances are handled by us, we need to track and report the relevant
1325
// data ourselves.
1326
if (global_info.interface == &wl_drm_interface) {
1327
Error err = client->send_wl_drm_state(new_local_id, (WaylandDrmGlobalData *)global_info.data);
1328
if (err != OK) {
1329
return MessageStatus::ERROR;
1330
}
1331
} else if (global_info.interface == &wl_shm_interface) {
1332
WaylandShmGlobalData *global_data = (WaylandShmGlobalData *)global_info.data;
1333
ERR_FAIL_NULL_V(global_data, MessageStatus::ERROR);
1334
1335
for (uint32_t format : global_data->formats) {
1336
send_wayland_message(client->socket, new_local_id, WL_SHM_FORMAT, { format });
1337
}
1338
}
1339
}
1340
1341
ERR_FAIL_NULL_V(instance, MessageStatus::UNHANDLED);
1342
1343
if (global_info.interface == &wl_seat_interface) {
1344
WaylandSeatInstanceData *new_data = memnew(WaylandSeatInstanceData);
1345
instance->data = new_data;
1346
}
1347
1348
return MessageStatus::HANDLED;
1349
}
1350
}
1351
1352
if (object->interface == &wl_compositor_interface && p_opcode == WL_COMPOSITOR_CREATE_SURFACE) {
1353
uint32_t new_local_id = body[0];
1354
1355
WaylandSurfaceData *data = memnew(WaylandSurfaceData);
1356
data->client = client;
1357
1358
uint32_t new_global_id = client->new_object(new_local_id, &wl_surface_interface, object->version, data);
1359
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1360
1361
DEBUG_LOG_WAYLAND_EMBED(vformat("Keeping track of surface l0x%x g0x%x.", new_local_id, new_global_id));
1362
1363
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id });
1364
return MessageStatus::HANDLED;
1365
}
1366
1367
if (object->interface == &wl_surface_interface) {
1368
WaylandSurfaceData *surface_data = (WaylandSurfaceData *)object->data;
1369
ERR_FAIL_NULL_V(surface_data, MessageStatus::ERROR);
1370
1371
if (p_opcode == WL_SURFACE_DESTROY) {
1372
for (uint32_t wl_seat_name : wl_seat_names) {
1373
WaylandSeatGlobalData *global_seat_data = (WaylandSeatGlobalData *)registry_globals[wl_seat_name].data;
1374
ERR_FAIL_NULL_V(global_seat_data, MessageStatus::ERROR);
1375
1376
if (global_seat_data->pointed_surface_id == global_id) {
1377
global_seat_data->pointed_surface_id = INVALID_ID;
1378
}
1379
1380
if (global_seat_data->focused_surface_id == global_id) {
1381
global_seat_data->focused_surface_id = INVALID_ID;
1382
}
1383
}
1384
} else if (p_opcode == WL_SURFACE_COMMIT) {
1385
if (surface_data->role_object_handle.is_valid()) {
1386
WaylandObject *role_object = surface_data->role_object_handle.get();
1387
if (role_object && role_object->interface) {
1388
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()));
1389
}
1390
1391
if (role_object && role_object->interface == &xdg_toplevel_interface) {
1392
XdgToplevelData *toplevel_data = (XdgToplevelData *)role_object->data;
1393
ERR_FAIL_NULL_V(toplevel_data, MessageStatus::ERROR);
1394
// xdg shell spec requires clients to first send data and then commit the
1395
// surface.
1396
1397
if (toplevel_data->is_embedded() && !toplevel_data->configured) {
1398
toplevel_data->configured = true;
1399
// xdg_surface::configure
1400
send_wayland_message(client->socket, toplevel_data->xdg_surface_handle.get_local_id(), 0, { serial_counter++ });
1401
}
1402
}
1403
}
1404
1405
send_wayland_message(compositor_socket, global_id, p_opcode, {});
1406
return MessageStatus::HANDLED;
1407
}
1408
}
1409
1410
if (object->interface == &wl_seat_interface) {
1411
uint32_t global_seat_name = registry_globals_names[global_id];
1412
1413
RegistryGlobalInfo &seat_global_info = registry_globals[global_seat_name];
1414
WaylandSeatGlobalData *global_data = (WaylandSeatGlobalData *)seat_global_info.data;
1415
ERR_FAIL_NULL_V(global_data, MessageStatus::ERROR);
1416
1417
WaylandSeatInstanceData *instance_data = (WaylandSeatInstanceData *)object->data;
1418
ERR_FAIL_NULL_V(instance_data, MessageStatus::ERROR);
1419
1420
if (p_opcode == WL_SEAT_GET_POINTER) {
1421
ERR_FAIL_COND_V(global_id == INVALID_ID, MessageStatus::ERROR);
1422
// [Request] wl_seat::get_pointer(n);
1423
uint32_t new_local_id = body[0];
1424
1425
WaylandPointerData *new_data = memnew(WaylandPointerData);
1426
new_data->wl_seat_id = global_id;
1427
1428
uint32_t new_global_id = client->new_object(new_local_id, &wl_pointer_interface, object->version, new_data);
1429
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1430
1431
instance_data->wl_pointer_id = new_global_id;
1432
1433
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id });
1434
1435
return MessageStatus::HANDLED;
1436
}
1437
1438
if (p_opcode == WL_SEAT_GET_KEYBOARD) {
1439
ERR_FAIL_COND_V(global_id == INVALID_ID, MessageStatus::ERROR);
1440
// [Request] wl_seat::get_pointer(n);
1441
uint32_t new_local_id = body[0];
1442
1443
WaylandKeyboardData *new_data = memnew(WaylandKeyboardData);
1444
new_data->wl_seat_id = global_id;
1445
1446
uint32_t new_global_id = client->new_object(new_local_id, &wl_keyboard_interface, object->version, new_data);
1447
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1448
1449
instance_data->wl_keyboard_id = new_global_id;
1450
1451
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id });
1452
1453
return MessageStatus::HANDLED;
1454
}
1455
}
1456
1457
if (object->interface == &xdg_wm_base_interface) {
1458
if (p_opcode == XDG_WM_BASE_CREATE_POSITIONER) {
1459
uint32_t new_local_id = body[0];
1460
uint32_t new_global_id = client->new_object(new_local_id, &xdg_positioner_interface, object->version, memnew(XdgPositionerData));
1461
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1462
1463
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id });
1464
return MessageStatus::HANDLED;
1465
}
1466
1467
if (p_opcode == XDG_WM_BASE_GET_XDG_SURFACE) {
1468
// [Request] xdg_wm_base::get_xdg_surface(no).
1469
uint32_t new_local_id = body[0];
1470
uint32_t surface_id = body[1];
1471
1472
uint32_t global_surface_id = client->get_global_id(surface_id);
1473
1474
bool fake = (client != main_client);
1475
1476
XdgSurfaceData *data = memnew(XdgSurfaceData);
1477
data->wl_surface_id = global_surface_id;
1478
1479
if (fake) {
1480
client->new_fake_object(new_local_id, &xdg_surface_interface, object->version, data);
1481
DEBUG_LOG_WAYLAND_EMBED(vformat("Created fake xdg_surface l0x%x for surface l0x%x", new_local_id, surface_id));
1482
} else {
1483
uint32_t new_global_id = client->new_object(new_local_id, &xdg_surface_interface, object->version, data);
1484
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1485
1486
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));
1487
1488
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id, global_surface_id });
1489
}
1490
1491
return MessageStatus::HANDLED;
1492
}
1493
}
1494
1495
if (object->interface == &xdg_surface_interface) {
1496
XdgSurfaceData *xdg_surf_data = (XdgSurfaceData *)object->data;
1497
ERR_FAIL_NULL_V(xdg_surf_data, MessageStatus::ERROR);
1498
1499
WaylandSurfaceData *surface_data = (WaylandSurfaceData *)get_object(xdg_surf_data->wl_surface_id)->data;
1500
ERR_FAIL_NULL_V(surface_data, MessageStatus::ERROR);
1501
1502
bool is_embedded = client->fake_objects.has(local_id);
1503
1504
if (p_opcode == XDG_SURFACE_GET_POPUP) {
1505
// [Request] xdg_surface::get_popup(no?o).
1506
1507
uint32_t new_local_id = body[0];
1508
uint32_t local_parent_id = body[1];
1509
uint32_t local_positioner_id = body[2];
1510
1511
surface_data->role_object_handle = LocalObjectHandle(client, new_local_id);
1512
1513
XdgPopupData *popup_data = memnew(XdgPopupData);
1514
popup_data->parent_handle = LocalObjectHandle(client, local_parent_id);
1515
1516
if (!is_embedded) {
1517
uint32_t new_global_id = client->new_object(new_local_id, &xdg_popup_interface, object->version, popup_data);
1518
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1519
1520
uint32_t global_parent_id = client->get_global_id(local_parent_id);
1521
uint32_t global_positioner_id = client->get_global_id(local_positioner_id);
1522
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id, global_parent_id, global_positioner_id });
1523
1524
return MessageStatus::HANDLED;
1525
}
1526
1527
{
1528
// Popups are real, time to actually instantiate an xdg_surface.
1529
WaylandObject copy = *object;
1530
client->fake_objects.erase(local_id);
1531
1532
global_id = client->new_object(local_id, copy.interface, copy.version, copy.data);
1533
ERR_FAIL_COND_V(global_id == INVALID_ID, MessageStatus::HANDLED);
1534
object = get_object(global_id);
1535
1536
// xdg_wm_base::get_xdg_surface(no);
1537
send_wayland_message(compositor_socket, xdg_wm_base_id, 2, { global_id, xdg_surf_data->wl_surface_id });
1538
}
1539
1540
uint32_t new_global_id = client->new_object(new_local_id, &xdg_popup_interface, object->version, popup_data);
1541
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1542
1543
uint32_t global_parent_id = INVALID_ID;
1544
if (local_parent_id != INVALID_ID) {
1545
XdgSurfaceData *parent_xdg_surf_data = (XdgSurfaceData *)client->get_object(local_parent_id)->data;
1546
ERR_FAIL_NULL_V(parent_xdg_surf_data, MessageStatus::ERROR);
1547
1548
WaylandSurfaceData *parent_surface_data = (WaylandSurfaceData *)get_object(parent_xdg_surf_data->wl_surface_id)->data;
1549
ERR_FAIL_NULL_V(parent_surface_data, MessageStatus::ERROR);
1550
1551
WaylandObject *parent_role_obj = parent_surface_data->role_object_handle.get();
1552
ERR_FAIL_NULL_V(parent_role_obj, MessageStatus::ERROR);
1553
1554
XdgPositionerData *pos_data = (XdgPositionerData *)client->get_object(local_positioner_id)->data;
1555
ERR_FAIL_NULL_V(pos_data, MessageStatus::ERROR);
1556
1557
if (parent_role_obj->interface == &xdg_toplevel_interface) {
1558
XdgToplevelData *parent_toplevel_data = (XdgToplevelData *)parent_role_obj->data;
1559
ERR_FAIL_NULL_V(parent_toplevel_data, MessageStatus::ERROR);
1560
1561
if (parent_toplevel_data->is_embedded()) {
1562
// Embedded windows are subsurfaces of a parent window. We need to
1563
// "redirect" the popup request on the parent window and adjust the
1564
// positioner properly if needed.
1565
1566
XdgToplevelData *main_parent_toplevel_data = (XdgToplevelData *)parent_toplevel_data->parent_handle.get()->data;
1567
ERR_FAIL_NULL_V(main_parent_toplevel_data, MessageStatus::ERROR);
1568
1569
global_parent_id = main_parent_toplevel_data->xdg_surface_handle.get_global_id();
1570
1571
WaylandSubsurfaceData *subsurf_data = (WaylandSubsurfaceData *)get_object(parent_toplevel_data->wl_subsurface_id)->data;
1572
ERR_FAIL_NULL_V(subsurf_data, MessageStatus::ERROR);
1573
1574
Point2i adj_pos = subsurf_data->position + pos_data->anchor_rect.position;
1575
1576
// xdg_positioner::set_anchor_rect
1577
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 });
1578
}
1579
} else {
1580
global_parent_id = client->get_global_id(local_parent_id);
1581
}
1582
}
1583
1584
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id, global_parent_id, client->get_global_id(local_positioner_id) });
1585
return MessageStatus::HANDLED;
1586
}
1587
1588
if (p_opcode == XDG_SURFACE_GET_TOPLEVEL) {
1589
// [Request] xdg_surface::get_toplevel(n).
1590
uint32_t new_local_id = body[0];
1591
1592
surface_data->role_object_handle = LocalObjectHandle(client, new_local_id);
1593
1594
XdgToplevelData *data = memnew(XdgToplevelData);
1595
data->xdg_surface_handle = LocalObjectHandle(client, local_id);
1596
1597
if (is_embedded) {
1598
client->new_fake_object(new_local_id, &xdg_toplevel_interface, object->version, data);
1599
client->embedded_window_id = new_local_id;
1600
1601
// godot_embedded_client::window_embedded()
1602
send_wayland_message(main_client->socket, client->embedded_client_id, 1, {});
1603
} else {
1604
uint32_t new_global_id = client->new_object(new_local_id, &xdg_toplevel_interface, object->version, data);
1605
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1606
1607
if (main_toplevel_id == 0) {
1608
main_toplevel_id = new_global_id;
1609
DEBUG_LOG_WAYLAND_EMBED(vformat("main toplevel set to gx0%x.", main_toplevel_id));
1610
}
1611
1612
send_wayland_message(compositor_socket, global_id, p_opcode, { new_global_id });
1613
}
1614
1615
return MessageStatus::HANDLED;
1616
}
1617
}
1618
1619
if (object->interface == &xdg_positioner_interface) {
1620
XdgPositionerData *pos_data = (XdgPositionerData *)object->data;
1621
ERR_FAIL_NULL_V(pos_data, MessageStatus::ERROR);
1622
1623
if (p_opcode == XDG_POSITIONER_SET_ANCHOR_RECT) {
1624
// Args: int x, int y, int width, int height.
1625
pos_data->anchor_rect = Rect2i(body[0], body[1], body[2], body[3]);
1626
1627
send_wayland_message(compositor_socket, global_id, p_opcode, { body[0], body[1], body[2], body[3] });
1628
return MessageStatus::HANDLED;
1629
}
1630
}
1631
1632
if (object->interface == &xdg_toplevel_interface && p_opcode == XDG_TOPLEVEL_DESTROY) {
1633
if (client->fake_objects.has(local_id)) {
1634
XdgToplevelData *data = (XdgToplevelData *)object->data;
1635
ERR_FAIL_NULL_V(data, MessageStatus::ERROR);
1636
1637
XdgSurfaceData *xdg_surf_data = nullptr;
1638
if (data->xdg_surface_handle.is_valid()) {
1639
xdg_surf_data = (XdgSurfaceData *)data->xdg_surface_handle.get()->data;
1640
ERR_FAIL_NULL_V(xdg_surf_data, MessageStatus::ERROR);
1641
}
1642
ERR_FAIL_NULL_V(xdg_surf_data, MessageStatus::ERROR);
1643
1644
XdgSurfaceData *parent_xdg_surf_data = nullptr;
1645
{
1646
XdgToplevelData *parent_data = nullptr;
1647
if (data->parent_handle.get()) {
1648
parent_data = (XdgToplevelData *)data->parent_handle.get()->data;
1649
ERR_FAIL_NULL_V(parent_data, MessageStatus::ERROR);
1650
}
1651
1652
if (parent_data && parent_data->xdg_surface_handle.get()) {
1653
parent_xdg_surf_data = (XdgSurfaceData *)parent_data->xdg_surface_handle.get()->data;
1654
ERR_FAIL_NULL_V(parent_xdg_surf_data, MessageStatus::ERROR);
1655
}
1656
}
1657
1658
for (uint32_t wl_seat_name : wl_seat_names) {
1659
WaylandSeatGlobalData *global_seat_data = (WaylandSeatGlobalData *)registry_globals[wl_seat_name].data;
1660
ERR_FAIL_NULL_V(global_seat_data, MessageStatus::ERROR);
1661
1662
if (global_seat_data->focused_surface_id == xdg_surf_data->wl_surface_id) {
1663
if (xdg_surf_data) {
1664
seat_name_leave_surface(wl_seat_name, xdg_surf_data->wl_surface_id);
1665
}
1666
1667
if (parent_xdg_surf_data) {
1668
seat_name_enter_surface(wl_seat_name, parent_xdg_surf_data->wl_surface_id);
1669
}
1670
}
1671
}
1672
1673
// wl_display::delete_id
1674
send_wayland_message(client->socket, local_id, p_opcode, {});
1675
1676
if (local_id == client->embedded_window_id) {
1677
client->embedded_window_id = 0;
1678
}
1679
1680
if (data->wl_subsurface_id != INVALID_ID) {
1681
send_wayland_message(compositor_socket, data->wl_subsurface_id, WL_SUBSURFACE_DESTROY, {});
1682
}
1683
1684
client->delete_object(local_id);
1685
1686
return MessageStatus::HANDLED;
1687
}
1688
}
1689
1690
if (interface == &zwp_pointer_constraints_v1_interface) {
1691
// FIXME: This implementation leaves no way of unlocking the pointer when
1692
// embedded into the main window. We might need to be a bit more invasive.
1693
if (p_opcode == ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER) {
1694
// [Request] zwp_pointer_constraints_v1::lock_pointer(nooou).
1695
1696
uint32_t new_local_id = body[0];
1697
uint32_t local_surface_id = body[1];
1698
uint32_t local_pointer_id = body[2];
1699
uint32_t lifetime = body[4];
1700
1701
WaylandSurfaceData *surf_data = (WaylandSurfaceData *)client->get_object(local_surface_id)->data;
1702
ERR_FAIL_NULL_V(surf_data, MessageStatus::ERROR);
1703
1704
WaylandObject *role_obj = surf_data->role_object_handle.get();
1705
ERR_FAIL_NULL_V(role_obj, MessageStatus::ERROR);
1706
1707
if (role_obj->interface == &xdg_toplevel_interface) {
1708
XdgToplevelData *toplevel_data = (XdgToplevelData *)role_obj->data;
1709
ERR_FAIL_NULL_V(toplevel_data, MessageStatus::ERROR);
1710
1711
if (!toplevel_data->is_embedded()) {
1712
// Passthrough.
1713
return MessageStatus::UNHANDLED;
1714
}
1715
1716
// Subsurfaces don't normally work, at least on sway, as the locking
1717
// condition might rely on focus, which they don't get. We can remap them to
1718
// the parent surface and set a region though.
1719
1720
XdgToplevelData *parent_data = (XdgToplevelData *)toplevel_data->parent_handle.get()->data;
1721
ERR_FAIL_NULL_V(parent_data, MessageStatus::ERROR);
1722
1723
XdgSurfaceData *parent_xdg_surf_data = (XdgSurfaceData *)parent_data->xdg_surface_handle.get()->data;
1724
ERR_FAIL_NULL_V(parent_xdg_surf_data, MessageStatus::ERROR);
1725
1726
WaylandSubsurfaceData *subsurf_data = (WaylandSubsurfaceData *)get_object(toplevel_data->wl_subsurface_id)->data;
1727
ERR_FAIL_NULL_V(subsurf_data, MessageStatus::ERROR);
1728
1729
uint32_t new_global_id = client->new_object(new_local_id, &zwp_locked_pointer_v1_interface, object->version);
1730
ERR_FAIL_COND_V(new_global_id == INVALID_ID, MessageStatus::HANDLED);
1731
1732
uint32_t x = subsurf_data->position.x;
1733
uint32_t y = subsurf_data->position.y;
1734
uint32_t width = toplevel_data->size.width;
1735
uint32_t height = toplevel_data->size.height;
1736
1737
// NOTE: At least on sway I can't seem to be able to get this region
1738
// working but the calls check out.
1739
DEBUG_LOG_WAYLAND_EMBED(vformat("Creating custom region x%d y%d w%d h%d", x, y, width, height));
1740
1741
uint32_t new_region_id = allocate_global_id();
1742
get_object(new_region_id)->interface = &wl_region_interface;
1743
get_object(new_region_id)->version = get_object(wl_compositor_id)->version;
1744
1745
// wl_compostor::create_region(n).
1746
send_wayland_message(compositor_socket, wl_compositor_id, 1, { new_region_id });
1747
1748
// wl_region::add(iiii).
1749
send_wayland_message(compositor_socket, new_region_id, 1, { x, y, width, height });
1750
1751
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 });
1752
1753
// wl_region::destroy().
1754
send_wayland_message(compositor_socket, new_region_id, 0, {});
1755
1756
return MessageStatus::HANDLED;
1757
}
1758
}
1759
}
1760
1761
if (interface == &godot_embedded_client_interface) {
1762
EmbeddedClientData *eclient_data = (EmbeddedClientData *)object->data;
1763
ERR_FAIL_NULL_V(eclient_data, MessageStatus::ERROR);
1764
1765
Client *eclient = eclient_data->client;
1766
ERR_FAIL_NULL_V(eclient, MessageStatus::ERROR);
1767
1768
if (p_opcode == GODOT_EMBEDDED_CLIENT_DESTROY) {
1769
if (!eclient_data->disconnected) {
1770
close(eclient->socket);
1771
}
1772
1773
client->delete_object(local_id);
1774
1775
return MessageStatus::HANDLED;
1776
}
1777
1778
if (eclient_data->disconnected) {
1779
// Object is inert.
1780
return MessageStatus::HANDLED;
1781
}
1782
1783
ERR_FAIL_COND_V(eclient->embedded_window_id == 0, MessageStatus::ERROR);
1784
1785
XdgToplevelData *toplevel_data = (XdgToplevelData *)eclient->get_object(eclient->embedded_window_id)->data;
1786
ERR_FAIL_NULL_V(toplevel_data, MessageStatus::ERROR);
1787
1788
if (p_opcode == GODOT_EMBEDDED_CLIENT_SET_EMBEDDED_WINDOW_RECT && toplevel_data->wl_subsurface_id != INVALID_ID) {
1789
uint32_t x = body[0];
1790
uint32_t y = body[1];
1791
uint32_t width = body[2];
1792
uint32_t height = body[3];
1793
1794
WaylandSubsurfaceData *subsurf_data = (WaylandSubsurfaceData *)get_object(toplevel_data->wl_subsurface_id)->data;
1795
ERR_FAIL_NULL_V(subsurf_data, MessageStatus::ERROR);
1796
1797
toplevel_data->size.width = width;
1798
toplevel_data->size.height = height;
1799
1800
subsurf_data->position.x = x;
1801
subsurf_data->position.y = y;
1802
1803
// wl_subsurface::set_position
1804
send_wayland_message(compositor_socket, toplevel_data->wl_subsurface_id, 1, { x, y });
1805
1806
// xdg_toplevel::configure
1807
send_wayland_message(eclient->socket, eclient->embedded_window_id, 0, { width, height, 0 });
1808
1809
// xdg_surface::configure
1810
send_wayland_message(eclient->socket, toplevel_data->xdg_surface_handle.get_local_id(), 0, { configure_serial_counter++ });
1811
1812
return MessageStatus::HANDLED;
1813
} else if (p_opcode == GODOT_EMBEDDED_CLIENT_SET_EMBEDDED_WINDOW_PARENT) {
1814
uint32_t main_client_parent_id = body[0];
1815
1816
if (toplevel_data->parent_handle.get_local_id() == main_client_parent_id) {
1817
return MessageStatus::HANDLED;
1818
}
1819
1820
if (main_client_parent_id == INVALID_ID && toplevel_data->wl_subsurface_id != INVALID_ID) {
1821
// Window hiding logic.
1822
1823
// wl_subsurface::destroy()
1824
send_wayland_message(compositor_socket, toplevel_data->wl_subsurface_id, 0, {});
1825
1826
toplevel_data->parent_handle.invalidate();
1827
toplevel_data->wl_subsurface_id = INVALID_ID;
1828
1829
return MessageStatus::HANDLED;
1830
}
1831
1832
XdgToplevelData *parent_toplevel_data = (XdgToplevelData *)client->get_object(main_client_parent_id)->data;
1833
ERR_FAIL_NULL_V(parent_toplevel_data, MessageStatus::ERROR);
1834
XdgSurfaceData *parent_xdg_surf_data = (XdgSurfaceData *)parent_toplevel_data->xdg_surface_handle.get()->data;
1835
ERR_FAIL_NULL_V(parent_xdg_surf_data, MessageStatus::ERROR);
1836
1837
XdgSurfaceData *xdg_surf_data = (XdgSurfaceData *)toplevel_data->xdg_surface_handle.get()->data;
1838
ERR_FAIL_NULL_V(xdg_surf_data, MessageStatus::ERROR);
1839
1840
if (toplevel_data->wl_subsurface_id != INVALID_ID) {
1841
// wl_subsurface::destroy()
1842
send_wayland_message(compositor_socket, toplevel_data->wl_subsurface_id, 0, {});
1843
}
1844
1845
uint32_t new_sub_id = allocate_global_id();
1846
WaylandObject *new_sub_object = get_object(new_sub_id);
1847
new_sub_object->interface = &wl_subsurface_interface;
1848
new_sub_object->data = memnew(WaylandSubsurfaceData);
1849
new_sub_object->version = get_object(wl_subcompositor_id)->version;
1850
1851
toplevel_data->wl_subsurface_id = new_sub_id;
1852
toplevel_data->parent_handle = LocalObjectHandle(main_client, main_client_parent_id);
1853
1854
DEBUG_LOG_WAYLAND_EMBED(vformat("Binding subsurface g0x%x.", new_sub_id));
1855
1856
// wl_subcompositor::get_subsurface
1857
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 });
1858
1859
// wl_subsurface::set_desync
1860
send_wayland_message(compositor_socket, new_sub_id, 5, {});
1861
1862
return MessageStatus::HANDLED;
1863
} else if (p_opcode == GODOT_EMBEDDED_CLIENT_FOCUS_WINDOW) {
1864
XdgSurfaceData *xdg_surf_data = (XdgSurfaceData *)toplevel_data->xdg_surface_handle.get()->data;
1865
ERR_FAIL_NULL_V(xdg_surf_data, MessageStatus::ERROR);
1866
1867
for (uint32_t wl_seat_name : wl_seat_names) {
1868
RegistryGlobalInfo &global_seat_info = registry_globals[wl_seat_name];
1869
WaylandSeatGlobalData *global_seat_data = (WaylandSeatGlobalData *)global_seat_info.data;
1870
1871
if (global_seat_data->focused_surface_id != INVALID_ID) {
1872
seat_name_leave_surface(wl_seat_name, global_seat_data->focused_surface_id);
1873
}
1874
global_seat_data->focused_surface_id = xdg_surf_data->wl_surface_id;
1875
1876
seat_name_enter_surface(wl_seat_name, xdg_surf_data->wl_surface_id);
1877
}
1878
} else if (p_opcode == GODOT_EMBEDDED_CLIENT_EMBEDDED_WINDOW_REQUEST_CLOSE) {
1879
// xdg_toplevel::close
1880
send_wayland_message(eclient->socket, eclient->embedded_window_id, 1, {});
1881
1882
return MessageStatus::HANDLED;
1883
}
1884
}
1885
1886
// Server-allocated objects are a bit annoying to handle for us. Right now we
1887
// use a heuristic. See: https://ppaalanen.blogspot.com/2014/07/wayland-protocol-design-object-lifespan.html
1888
if (strcmp(message.name, "destroy") == 0 || strcmp(message.name, "release") == 0) {
1889
if (object->shared) {
1890
// We must not delete shared objects.
1891
client->delete_object(local_id);
1892
return MessageStatus::HANDLED;
1893
}
1894
1895
if (global_id != INVALID_ID) {
1896
send_wayland_message(compositor_socket, global_id, p_opcode, {});
1897
object->destroyed = true;
1898
}
1899
1900
if (local_id & 0xff000000) {
1901
DEBUG_LOG_WAYLAND_EMBED(vformat("!!!!!! Deallocating server object l0x%x", local_id));
1902
client->delete_object(local_id);
1903
}
1904
1905
return MessageStatus::HANDLED;
1906
}
1907
1908
if (client->fake_objects.has(local_id)) {
1909
// Object is fake, we're done.
1910
DEBUG_LOG_WAYLAND_EMBED("Dropping unhandled request for fake object.");
1911
return MessageStatus::HANDLED;
1912
}
1913
1914
if (global_id == INVALID_ID) {
1915
DEBUG_LOG_WAYLAND_EMBED("Dropping request with invalid global object id");
1916
return MessageStatus::HANDLED;
1917
}
1918
1919
return MessageStatus::UNHANDLED;
1920
}
1921
1922
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) {
1923
WaylandObject *global_object = get_object(p_global_id);
1924
ERR_FAIL_NULL_V_MSG(global_object, MessageStatus::ERROR, "Compositor messages must always have a global object.");
1925
1926
#ifdef WAYLAND_EMBED_DEBUG_LOGS_ENABLED
1927
ERR_FAIL_NULL_V(global_object->interface, MessageStatus::ERROR);
1928
const struct wl_interface *interface = global_object->interface;
1929
1930
ERR_FAIL_COND_V((int)p_opcode >= interface->event_count, MessageStatus::ERROR);
1931
const struct wl_message message = interface->events[p_opcode];
1932
1933
if (p_local_handle.is_valid()) {
1934
int socket = p_local_handle.get_client()->socket;
1935
DEBUG_LOG_WAYLAND_EMBED(vformat("Client #%d <- %s::%s(%s) g0x%x", socket, interface->name, message.name, message.signature, p_global_id));
1936
} else {
1937
DEBUG_LOG_WAYLAND_EMBED(vformat("Client N/A <- %s::%s(%s) g0x%x", interface->name, message.name, message.signature, p_global_id));
1938
}
1939
#endif //WAYLAND_EMBED_DEBUG_LOGS_ENABLED
1940
1941
const uint32_t *body = msg_data + 2;
1942
//size_t body_len = msg_len - (WL_WORD_SIZE * 2);
1943
1944
// FIXME: Make sure that it makes sense to track this protocol. Not only is it
1945
// old and getting deprecated, but I can't even get this code branch to hit
1946
// probably because, at the time of writing, we only get the "main" display
1947
// through the proxy.
1948
if (global_object->interface == &wl_drm_interface) {
1949
// wl_drm can't ever be destroyed, so we need to track its state as it's going
1950
// to be instanced at least few times.
1951
uint32_t global_name = registry_globals_names[p_global_id];
1952
WaylandDrmGlobalData *global_data = (WaylandDrmGlobalData *)registry_globals[global_name].data;
1953
ERR_FAIL_NULL_V(global_data, MessageStatus::ERROR);
1954
1955
if (p_opcode == WL_DRM_DEVICE) {
1956
// signature: s
1957
uint32_t name_len = body[0];
1958
uint8_t *name = (uint8_t *)(body + 1);
1959
global_data->device = String::utf8((const char *)name, name_len);
1960
1961
return MessageStatus::UNHANDLED;
1962
}
1963
1964
if (p_opcode == WL_DRM_FORMAT) {
1965
// signature: u
1966
uint32_t format = body[0];
1967
global_data->formats.push_back(format);
1968
1969
return MessageStatus::UNHANDLED;
1970
}
1971
1972
if (p_opcode == WL_DRM_AUTHENTICATED) {
1973
// signature: N/A
1974
global_data->authenticated = true;
1975
1976
return MessageStatus::UNHANDLED;
1977
}
1978
1979
if (p_opcode == WL_DRM_CAPABILITIES) {
1980
// signature: u
1981
uint32_t capabilities = body[0];
1982
global_data->capabilities = capabilities;
1983
}
1984
1985
return MessageStatus::UNHANDLED;
1986
}
1987
1988
if (global_object->interface == &wl_shm_interface) {
1989
uint32_t global_name = registry_globals_names[p_global_id];
1990
WaylandShmGlobalData *global_data = (WaylandShmGlobalData *)registry_globals[global_name].data;
1991
ERR_FAIL_NULL_V(global_data, MessageStatus::ERROR);
1992
1993
if (p_opcode == WL_SHM_FORMAT) {
1994
// Signature: u
1995
uint32_t format = body[0];
1996
global_data->formats.push_back(format);
1997
}
1998
}
1999
2000
if (!p_local_handle.is_valid()) {
2001
// Some requests might not have a valid local object handle for various
2002
// reasons, such as when certain events are directed to this proxy or when the
2003
// destination client of a message disconnected in the meantime.
2004
2005
if (global_object->interface == &wl_display_interface) {
2006
if (p_opcode == WL_DISPLAY_DELETE_ID) {
2007
// [Event] wl_display::delete_id(u)
2008
uint32_t global_delete_id = body[0];
2009
DEBUG_LOG_WAYLAND_EMBED(vformat("Compositor requested deletion of g0x%x (no client)", global_delete_id));
2010
2011
delete_object(global_delete_id);
2012
2013
return MessageStatus::HANDLED;
2014
} else if (p_opcode == WL_DISPLAY_ERROR) {
2015
// [Event] wl_display::error(ous)
2016
uint32_t obj_id = body[0];
2017
uint32_t err_code = body[1];
2018
2019
CRASH_NOW_MSG(vformat("Error obj g0x%x code %d: %s", obj_id, err_code, (const char *)(body + 3)));
2020
}
2021
}
2022
2023
if (global_object->interface == &wl_callback_interface && p_opcode == WL_CALLBACK_DONE) {
2024
if (sync_callback_id != INVALID_ID && p_global_id == sync_callback_id) {
2025
sync_callback_id = 0;
2026
DEBUG_LOG_WAYLAND_EMBED("Sync response received");
2027
return MessageStatus::HANDLED;
2028
}
2029
}
2030
2031
if (global_object->interface == &wl_registry_interface) {
2032
if (p_opcode == WL_REGISTRY_GLOBAL) {
2033
// [Event] wl_registry::global(usu).
2034
2035
uint32_t global_name = body[0];
2036
uint32_t interface_name_len = body[1];
2037
const char *interface_name = (const char *)(body + 2);
2038
uint32_t global_version = body[2 + wl_array_word_offset(interface_name_len)];
2039
2040
DEBUG_LOG_WAYLAND_EMBED("Global c#%d %s %d", global_name, interface_name, global_version);
2041
2042
const struct wl_interface *global_interface = wl_interface_from_string(interface_name, interface_name_len);
2043
if (global_interface) {
2044
RegistryGlobalInfo global_info = {};
2045
global_info.interface = global_interface;
2046
global_info.version = MIN(global_version, (uint32_t)global_interface->version);
2047
DEBUG_LOG_WAYLAND_EMBED("Clamped global %s to version %d.", interface_name, global_info.version);
2048
global_info.compositor_name = global_name;
2049
2050
int new_global_name = registry_globals_counter++;
2051
2052
if (global_info.interface == &wl_shm_interface) {
2053
DEBUG_LOG_WAYLAND_EMBED("Allocating global wl_shm data.");
2054
global_info.data = memnew(WaylandShmGlobalData);
2055
}
2056
2057
if (global_info.interface == &wl_seat_interface) {
2058
DEBUG_LOG_WAYLAND_EMBED("Allocating global wl_seat data.");
2059
global_info.data = memnew(WaylandSeatGlobalData);
2060
wl_seat_names.push_back(new_global_name);
2061
}
2062
2063
if (global_info.interface == &wl_drm_interface) {
2064
DEBUG_LOG_WAYLAND_EMBED("Allocating global wl_drm data.");
2065
global_info.data = memnew(WaylandDrmGlobalData);
2066
}
2067
2068
registry_globals[new_global_name] = global_info;
2069
2070
// We need some interfaces directly. It's better to bind a "copy" ourselves
2071
// than to wait for the client to ask one.
2072
if (global_interface == &xdg_wm_base_interface && xdg_wm_base_id == 0) {
2073
xdg_wm_base_id = wl_registry_bind(p_global_id, new_global_name, global_info.version);
2074
ERR_FAIL_COND_V(xdg_wm_base_id == INVALID_ID, MessageStatus::ERROR);
2075
} else if (global_interface == &wl_compositor_interface && wl_compositor_id == 0) {
2076
wl_compositor_id = wl_registry_bind(p_global_id, new_global_name, global_info.version);
2077
ERR_FAIL_COND_V(wl_compositor_id == INVALID_ID, MessageStatus::ERROR);
2078
} else if (global_interface == &wl_subcompositor_interface && wl_subcompositor_id == 0) {
2079
wl_subcompositor_id = wl_registry_bind(p_global_id, new_global_name, global_info.version);
2080
ERR_FAIL_COND_V(wl_subcompositor_id == INVALID_ID, MessageStatus::ERROR);
2081
}
2082
2083
DEBUG_LOG_WAYLAND_EMBED(vformat("Local registry object name: l#%d", new_global_name));
2084
2085
if (clients.is_empty()) {
2086
// Let's not waste time.
2087
return MessageStatus::HANDLED;
2088
}
2089
2090
// Notify all clients.
2091
LocalVector<wl_argument> args;
2092
args.push_back(wl_arg_uint(new_global_name));
2093
args.push_back(wl_arg_string(interface_name));
2094
args.push_back(wl_arg_uint(global_info.version));
2095
for (KeyValue<int, Client> &pair : clients) {
2096
Client &client = pair.value;
2097
for (uint32_t local_registry_id : client.wl_registry_instances) {
2098
send_wayland_event(client.socket, local_registry_id, wl_registry_interface, WL_REGISTRY_GLOBAL, args);
2099
}
2100
}
2101
2102
return MessageStatus::HANDLED;
2103
} else {
2104
DEBUG_LOG_WAYLAND_EMBED("Skipping unknown global %s version %d.", interface_name, global_version);
2105
2106
return MessageStatus::HANDLED;
2107
}
2108
} else if (p_opcode == WL_REGISTRY_GLOBAL_REMOVE) {
2109
uint32_t compositor_name = body[0];
2110
uint32_t local_name = 0;
2111
RegistryGlobalInfo *global_info = nullptr;
2112
2113
// FIXME: Use a map or something.
2114
for (KeyValue<uint32_t, RegistryGlobalInfo> &pair : registry_globals) {
2115
uint32_t name = pair.key;
2116
RegistryGlobalInfo &info = pair.value;
2117
2118
if (info.compositor_name == compositor_name) {
2119
local_name = name;
2120
global_info = &info;
2121
break;
2122
}
2123
}
2124
2125
ERR_FAIL_NULL_V(global_info, MessageStatus::ERROR);
2126
2127
if (global_info->instance_counter == 0) {
2128
memdelete(global_info->data);
2129
registry_globals.erase(local_name);
2130
} else {
2131
global_info->destroyed = true;
2132
}
2133
2134
// Notify all clients.
2135
LocalVector<wl_argument> args;
2136
args.push_back(wl_arg_uint(local_name));
2137
for (KeyValue<int, Client> &pair : clients) {
2138
Client &client = pair.value;
2139
for (uint32_t local_registry_id : client.wl_registry_instances) {
2140
send_wayland_event(client.socket, local_registry_id, wl_registry_interface, WL_REGISTRY_GLOBAL_REMOVE, args);
2141
}
2142
}
2143
2144
return MessageStatus::HANDLED;
2145
}
2146
}
2147
2148
DEBUG_LOG_WAYLAND_EMBED("No valid local object handle, falling back to generic handler.");
2149
return MessageStatus::UNHANDLED;
2150
}
2151
2152
Client *client = p_local_handle.get_client();
2153
2154
ERR_FAIL_NULL_V(client, MessageStatus::ERROR);
2155
2156
WaylandObject *object = p_local_handle.get();
2157
uint32_t local_id = p_local_handle.get_local_id();
2158
2159
if (global_object->interface == &wl_display_interface) {
2160
if (p_opcode == WL_DISPLAY_DELETE_ID) {
2161
// [Event] wl_display::delete_id(u)
2162
uint32_t global_delete_id = body[0];
2163
uint32_t local_delete_id = client->get_local_id(global_delete_id);
2164
DEBUG_LOG_WAYLAND_EMBED(vformat("Compositor requested delete of g0x%x l0x%x", global_delete_id, local_delete_id));
2165
if (local_delete_id == INVALID_ID) {
2166
// No idea what this object is, might be of the other client. This
2167
// definitely does not make sense to us, so we're done.
2168
return MessageStatus::INVALID;
2169
}
2170
2171
client->delete_object(local_delete_id);
2172
2173
send_wayland_message(client->socket, DISPLAY_ID, WL_DISPLAY_DELETE_ID, { local_delete_id });
2174
2175
return MessageStatus::HANDLED;
2176
}
2177
2178
return MessageStatus::UNHANDLED;
2179
}
2180
2181
if (object->interface == &wl_keyboard_interface) {
2182
WaylandKeyboardData *data = (WaylandKeyboardData *)object->data;
2183
ERR_FAIL_NULL_V(data, MessageStatus::ERROR);
2184
2185
uint32_t global_seat_name = registry_globals_names[data->wl_seat_id];
2186
RegistryGlobalInfo &global_seat_info = registry_globals[global_seat_name];
2187
WaylandSeatGlobalData *global_seat_data = (WaylandSeatGlobalData *)global_seat_info.data;
2188
ERR_FAIL_NULL_V(global_seat_data, MessageStatus::ERROR);
2189
2190
if (p_opcode == WL_KEYBOARD_ENTER) {
2191
// [Event] wl_keyboard::enter(uoa)
2192
uint32_t surface = body[1];
2193
2194
if (global_seat_data->focused_surface_id != surface) {
2195
DEBUG_LOG_WAYLAND_EMBED(vformat("Focused g0x%x", surface));
2196
global_seat_data->focused_surface_id = surface;
2197
}
2198
} else if (p_opcode == WL_KEYBOARD_LEAVE) {
2199
// [Event] wl_keyboard::leave(uo)
2200
uint32_t surface = body[1];
2201
2202
if (global_seat_data->focused_surface_id == surface) {
2203
global_seat_data->focused_surface_id = INVALID_ID;
2204
}
2205
} else if (p_opcode == WL_KEYBOARD_KEY) {
2206
// NOTE: modifiers event can be sent even without focus, according to the
2207
// spec, so there's no need to skip it.
2208
if (global_seat_data->focused_surface_id != INVALID_ID && !client->local_ids.has(global_seat_data->focused_surface_id)) {
2209
DEBUG_LOG_WAYLAND_EMBED(vformat("Skipped wl_keyboard event due to unfocused surface 0x%x", global_seat_data->focused_surface_id));
2210
return MessageStatus::HANDLED;
2211
}
2212
}
2213
2214
return MessageStatus::UNHANDLED;
2215
}
2216
2217
if (object->interface == &wl_pointer_interface) {
2218
WaylandPointerData *data = (WaylandPointerData *)object->data;
2219
ERR_FAIL_NULL_V(data, MessageStatus::ERROR);
2220
2221
uint32_t global_seat_name = registry_globals_names[data->wl_seat_id];
2222
RegistryGlobalInfo &global_seat_info = registry_globals[global_seat_name];
2223
WaylandSeatGlobalData *global_seat_data = (WaylandSeatGlobalData *)global_seat_info.data;
2224
ERR_FAIL_NULL_V(global_seat_data, MessageStatus::ERROR);
2225
2226
WaylandSeatInstanceData *seat_data = (WaylandSeatInstanceData *)object->data;
2227
ERR_FAIL_NULL_V(seat_data, MessageStatus::ERROR);
2228
2229
if (p_opcode == WL_POINTER_BUTTON && global_seat_data->pointed_surface_id != INVALID_ID) {
2230
// [Event] wl_pointer::button(uuuu);
2231
uint32_t button = body[2];
2232
uint32_t state = body[3];
2233
2234
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));
2235
2236
bool client_pointed = client->local_ids.has(global_seat_data->pointed_surface_id);
2237
2238
if (button != BTN_LEFT || state != WL_POINTER_BUTTON_STATE_RELEASED) {
2239
return client_pointed ? MessageStatus::UNHANDLED : MessageStatus::HANDLED;
2240
}
2241
2242
if (global_seat_data->focused_surface_id == global_seat_data->pointed_surface_id) {
2243
return client_pointed ? MessageStatus::UNHANDLED : MessageStatus::HANDLED;
2244
}
2245
2246
if (!global_surface_is_window(global_seat_data->pointed_surface_id)) {
2247
return client_pointed ? MessageStatus::UNHANDLED : MessageStatus::HANDLED;
2248
}
2249
2250
if (global_seat_data->focused_surface_id != INVALID_ID) {
2251
seat_name_leave_surface(global_seat_name, global_seat_data->focused_surface_id);
2252
}
2253
2254
global_seat_data->focused_surface_id = global_seat_data->pointed_surface_id;
2255
seat_name_enter_surface(global_seat_name, global_seat_data->focused_surface_id);
2256
} else if (p_opcode == WL_POINTER_ENTER) {
2257
// [Event] wl_pointer::enter(uoff).
2258
uint32_t surface = body[1];
2259
WaylandSurfaceData *surface_data = (WaylandSurfaceData *)get_object(surface)->data;
2260
ERR_FAIL_NULL_V(surface_data, MessageStatus::ERROR);
2261
2262
if (global_seat_data->pointed_surface_id != surface) {
2263
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));
2264
2265
global_seat_data->pointed_surface_id = surface;
2266
}
2267
} else if (p_opcode == WL_POINTER_LEAVE) {
2268
// [Event] wl_pointer::leave(uo).
2269
uint32_t surface = body[1];
2270
WaylandSurfaceData *surface_data = (WaylandSurfaceData *)get_object(surface)->data;
2271
ERR_FAIL_NULL_V(surface_data, MessageStatus::ERROR);
2272
2273
if (global_seat_data->pointed_surface_id == surface) {
2274
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));
2275
global_seat_data->pointed_surface_id = INVALID_ID;
2276
}
2277
}
2278
2279
return MessageStatus::UNHANDLED;
2280
}
2281
2282
if (object->interface == &xdg_popup_interface) {
2283
if (p_opcode == XDG_POPUP_CONFIGURE) {
2284
// [Event] xdg_popup::configure(iiii);
2285
int32_t x = body[0];
2286
int32_t y = body[1];
2287
int32_t width = body[2];
2288
int32_t height = body[3];
2289
2290
XdgPopupData *data = (XdgPopupData *)object->data;
2291
ERR_FAIL_NULL_V(data, MessageStatus::ERROR);
2292
2293
XdgSurfaceData *parent_xdg_surf_data = (XdgSurfaceData *)data->parent_handle.get()->data;
2294
ERR_FAIL_NULL_V(parent_xdg_surf_data, MessageStatus::ERROR);
2295
2296
WaylandSurfaceData *parent_surface_data = (WaylandSurfaceData *)get_object(parent_xdg_surf_data->wl_surface_id)->data;
2297
ERR_FAIL_NULL_V(parent_surface_data, MessageStatus::ERROR);
2298
2299
WaylandObject *parent_role_obj = parent_surface_data->role_object_handle.get();
2300
ERR_FAIL_NULL_V(parent_role_obj, MessageStatus::ERROR);
2301
2302
if (parent_role_obj->interface == &xdg_toplevel_interface) {
2303
XdgToplevelData *parent_toplevel_data = (XdgToplevelData *)parent_role_obj->data;
2304
ERR_FAIL_NULL_V(parent_toplevel_data, MessageStatus::ERROR);
2305
2306
if (parent_toplevel_data->is_embedded()) {
2307
WaylandSubsurfaceData *subsurf_data = (WaylandSubsurfaceData *)get_object(parent_toplevel_data->wl_subsurface_id)->data;
2308
ERR_FAIL_NULL_V(subsurf_data, MessageStatus::ERROR);
2309
2310
// The coordinates passed will be shifted by the embedded window position,
2311
// so we need to fix them back.
2312
Point2i fixed_position = Point2i(x, y) - subsurf_data->position;
2313
2314
DEBUG_LOG_WAYLAND_EMBED(vformat("Correcting popup configure position to %s", fixed_position));
2315
2316
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 });
2317
2318
return MessageStatus::HANDLED;
2319
}
2320
}
2321
}
2322
}
2323
2324
return MessageStatus::UNHANDLED;
2325
}
2326
2327
void WaylandEmbedder::shutdown() {
2328
thread_done.set();
2329
2330
{
2331
// First making a list of all clients so that we can iteratively delete them.
2332
LocalVector<int> sockets;
2333
for (KeyValue<int, Client> &pair : clients) {
2334
sockets.push_back(pair.key);
2335
}
2336
2337
for (int socket : sockets) {
2338
cleanup_socket(socket);
2339
}
2340
}
2341
2342
close(compositor_socket);
2343
compositor_socket = -1;
2344
2345
for (KeyValue<uint32_t, RegistryGlobalInfo> &pair : registry_globals) {
2346
RegistryGlobalInfo &info = pair.value;
2347
if (info.data) {
2348
memdelete(info.data);
2349
info.data = nullptr;
2350
}
2351
}
2352
}
2353
2354
Error WaylandEmbedder::handle_msg_info(Client *client, const struct msg_info *info, uint32_t *buf, LocalVector<int> &r_sent_fds) {
2355
ERR_FAIL_NULL_V(info, ERR_BUG);
2356
ERR_FAIL_NULL_V_MSG(info->direction == ProxyDirection::COMPOSITOR && client, ERR_BUG, "Wait, where did this message come from?");
2357
2358
WaylandObject *object = nullptr;
2359
2360
uint32_t global_id = INVALID_ID;
2361
if (info->direction == ProxyDirection::CLIENT) {
2362
global_id = info->raw_id;
2363
} else if (info->direction == ProxyDirection::COMPOSITOR) {
2364
global_id = client->get_global_id(info->raw_id);
2365
}
2366
2367
if (global_id != INVALID_ID) {
2368
object = get_object(global_id);
2369
} else if (client) {
2370
object = client->get_object(info->raw_id);
2371
}
2372
2373
if (object == nullptr) {
2374
if (info->direction == ProxyDirection::COMPOSITOR) {
2375
uint32_t local_id = info->raw_id;
2376
ERR_PRINT(vformat("Couldn't find requested object l0x%x for client %d, disconnecting.", local_id, client->socket));
2377
2378
socket_error(client->socket, local_id, WL_DISPLAY_ERROR_INVALID_OBJECT, vformat("Object l0x%x not found.", local_id));
2379
return OK;
2380
} else {
2381
CRASH_NOW_MSG(vformat("No object found for r0x%x", info->raw_id));
2382
}
2383
}
2384
2385
const struct wl_interface *interface = nullptr;
2386
interface = object->interface;
2387
2388
if (interface == nullptr && info->raw_id & 0xff000000) {
2389
// Regular clients have no confirmation about deleted server objects (why
2390
// should they?) but since we share connections there's the risk of receiving
2391
// messages about deleted server objects. The simplest solution is to ignore
2392
// unknown server-side objects. Not the safest thing, I know, but it should do
2393
// the job.
2394
DEBUG_LOG_WAYLAND_EMBED(vformat("Ignoring unknown server-side object r0x%x", info->raw_id));
2395
return OK;
2396
}
2397
2398
ERR_FAIL_NULL_V_MSG(interface, ERR_BUG, vformat("Object r0x%x has no interface", info->raw_id));
2399
2400
const struct wl_message *message = nullptr;
2401
if (info->direction == ProxyDirection::CLIENT) {
2402
ERR_FAIL_COND_V(info->opcode >= interface->event_count, ERR_BUG);
2403
message = &interface->events[info->opcode];
2404
} else {
2405
ERR_FAIL_COND_V(info->opcode >= interface->method_count, ERR_BUG);
2406
message = &interface->methods[info->opcode];
2407
}
2408
ERR_FAIL_NULL_V(message, ERR_BUG);
2409
2410
int fds_requested = String(message->signature).count("h");
2411
if (fds_requested > 0) {
2412
DEBUG_LOG_WAYLAND_EMBED(vformat("Requested %d FDs.", fds_requested));
2413
2414
List<int> &fd_queue = info->direction == ProxyDirection::COMPOSITOR ? client->fds : compositor_fds;
2415
for (int i = 0; i < fds_requested; ++i) {
2416
ERR_FAIL_COND_V_MSG(fd_queue.is_empty(), ERR_BUG, "Out of FDs.");
2417
DEBUG_LOG_WAYLAND_EMBED(vformat("Fetching FD %d.", fd_queue.front()->get()));
2418
r_sent_fds.push_back(fd_queue.front()->get());
2419
fd_queue.pop_front();
2420
}
2421
2422
DEBUG_LOG_WAYLAND_EMBED(vformat("Remaining FDs: %d.", fd_queue.size()));
2423
}
2424
2425
if (object->destroyed) {
2426
DEBUG_LOG_WAYLAND_EMBED("Ignoring message for inert object.");
2427
2428
// Inert object.
2429
return OK;
2430
}
2431
2432
if (info->direction == ProxyDirection::COMPOSITOR) {
2433
MessageStatus request_status = handle_request(LocalObjectHandle(client, info->raw_id), info->opcode, buf, info->size);
2434
if (request_status == MessageStatus::ERROR) {
2435
return ERR_BUG;
2436
}
2437
2438
if (request_status == MessageStatus::HANDLED) {
2439
DEBUG_LOG_WAYLAND_EMBED("Custom handler success.");
2440
return OK;
2441
}
2442
2443
if (global_id != INVALID_ID) {
2444
buf[0] = global_id;
2445
}
2446
2447
DEBUG_LOG_WAYLAND_EMBED("Falling back to generic handler.");
2448
2449
if (handle_generic_msg(client, object, message, info, buf)) {
2450
send_raw_message(compositor_socket, { { buf, info->size } }, r_sent_fds);
2451
}
2452
} else {
2453
uint32_t global_name = 0;
2454
2455
bool is_global = false;
2456
if (registry_globals_names.has(global_id)) {
2457
global_name = registry_globals_names[global_id];
2458
is_global = true;
2459
}
2460
2461
// FIXME: For compatibility, mirror events with instanced registry globals as
2462
// object arguments. For example, `wl_surface.enter` returns a `wl_output`. If
2463
// said `wl_output` has been instanced multiple times, we need to resend the
2464
// same event with each instance as the argument, or the client might miss the
2465
// event by looking for the "wrong" instance.
2466
//
2467
// Note that this missing behavior is exclusively a compatibility mechanism
2468
// for old compositors which only implement undestroyable globals. We
2469
// otherwise passthrough every bind request and then the compositor takes care
2470
// of everything.
2471
// See: https://lore.freedesktop.org/wayland-devel/[email protected]/
2472
if (object->shared) {
2473
bool handled = false;
2474
2475
for (KeyValue<int, Client> &pair : clients) {
2476
Client &c = pair.value;
2477
if (c.socket < 0) {
2478
continue;
2479
}
2480
2481
if (!c.local_ids.has(global_id)) {
2482
DEBUG_LOG_WAYLAND_EMBED("!!!!!!!!!!! Instance missing?");
2483
continue;
2484
}
2485
2486
if (is_global) {
2487
if (!c.registry_globals_instances.has(global_name)) {
2488
continue;
2489
}
2490
2491
DEBUG_LOG_WAYLAND_EMBED(vformat("Broadcasting to all global instances for client %d (socket %d)", c.pid, c.socket));
2492
for (uint32_t instance_id : c.registry_globals_instances[global_name]) {
2493
DEBUG_LOG_WAYLAND_EMBED(vformat("Global instance l0x%x", instance_id));
2494
2495
LocalObjectHandle local_obj = LocalObjectHandle(&c, instance_id);
2496
if (!local_obj.is_valid()) {
2497
continue;
2498
}
2499
2500
MessageStatus event_status = handle_event(global_id, local_obj, info->opcode, buf, info->size);
2501
2502
if (event_status == MessageStatus::ERROR) {
2503
return ERR_BUG;
2504
}
2505
2506
if (event_status == MessageStatus::HANDLED) {
2507
DEBUG_LOG_WAYLAND_EMBED("Custom handler success.");
2508
handled = true;
2509
continue;
2510
}
2511
2512
if (event_status == MessageStatus::INVALID) {
2513
continue;
2514
}
2515
2516
DEBUG_LOG_WAYLAND_EMBED("Falling back to generic handler.");
2517
2518
buf[0] = instance_id;
2519
2520
if (handle_generic_msg(&c, local_obj.get(), message, info, buf, instance_id)) {
2521
send_raw_message(c.socket, { { buf, info->size } }, r_sent_fds);
2522
}
2523
2524
handled = true;
2525
}
2526
} else if (interface == &wl_display_interface) {
2527
// NOTE: The only shared non-global objects are `wl_display` and
2528
// `wl_registry`, both of which require custom handlers. Additionally, of
2529
// those only `wl_display` has client-specific handlers, which is what this
2530
// branch manages.
2531
2532
LocalObjectHandle local_obj = LocalObjectHandle(&c, c.get_local_id(global_id));
2533
if (!local_obj.is_valid()) {
2534
continue;
2535
}
2536
2537
DEBUG_LOG_WAYLAND_EMBED(vformat("Shared non-global l0x%x g0x%x", c.get_local_id(global_id), global_id));
2538
2539
MessageStatus event_status = handle_event(global_id, local_obj, info->opcode, buf, info->size);
2540
if (event_status == MessageStatus::ERROR) {
2541
return ERR_BUG;
2542
}
2543
2544
if (event_status == MessageStatus::HANDLED) {
2545
DEBUG_LOG_WAYLAND_EMBED("Custom handler success.");
2546
handled = true;
2547
continue;
2548
}
2549
2550
if (event_status == MessageStatus::INVALID) {
2551
continue;
2552
}
2553
2554
DEBUG_LOG_WAYLAND_EMBED("Falling back to generic handler.");
2555
2556
if (handle_generic_msg(&c, local_obj.get(), message, info, buf)) {
2557
send_raw_message(c.socket, { { buf, info->size } }, r_sent_fds);
2558
}
2559
2560
handled = true;
2561
}
2562
}
2563
2564
if (!handled) {
2565
// No client handled this, it's going to be handled as a client-less event.
2566
// We do this only at the end to avoid handling certain events (e.g.
2567
// deletion) twice.
2568
handle_event(global_id, LocalObjectHandle(nullptr, INVALID_ID), info->opcode, buf, info->size);
2569
}
2570
} else {
2571
LocalObjectHandle local_obj = LocalObjectHandle(client, client ? client->get_local_id(global_id) : INVALID_ID);
2572
2573
MessageStatus event_status = handle_event(global_id, local_obj, info->opcode, buf, info->size);
2574
if (event_status == MessageStatus::ERROR) {
2575
return ERR_BUG;
2576
}
2577
2578
if (event_status == MessageStatus::HANDLED || event_status == MessageStatus::INVALID) {
2579
// We're done.
2580
return OK;
2581
}
2582
2583
// Generic passthrough.
2584
2585
if (client) {
2586
uint32_t local_id = client->get_local_id(global_id);
2587
ERR_FAIL_COND_V(local_id == INVALID_ID, OK);
2588
2589
DEBUG_LOG_WAYLAND_EMBED(vformat("%s::%s(%s) g0x%x -> l0x%x", interface->name, message->name, message->signature, global_id, local_id));
2590
buf[0] = local_id;
2591
2592
if (handle_generic_msg(client, local_obj.get(), message, info, buf)) {
2593
send_raw_message(client->socket, { { buf, info->size } }, r_sent_fds);
2594
}
2595
} else {
2596
WARN_PRINT_ONCE(vformat("[Wayland Embedder] Unexpected client-less event from %s#g0x%x. Object has probably leaked.", object->interface->name, global_id));
2597
handle_generic_msg(nullptr, object, message, info, buf);
2598
}
2599
}
2600
}
2601
2602
return OK;
2603
}
2604
2605
Error WaylandEmbedder::handle_sock(int p_fd) {
2606
ERR_FAIL_COND_V(p_fd < 0, ERR_INVALID_PARAMETER);
2607
2608
struct msg_info info = {};
2609
2610
{
2611
struct msghdr head_msg = {};
2612
uint32_t header[2];
2613
struct iovec vec = { header, sizeof header };
2614
2615
head_msg.msg_iov = &vec;
2616
head_msg.msg_iovlen = 1;
2617
2618
ssize_t head_rec = recvmsg(p_fd, &head_msg, MSG_PEEK);
2619
2620
if (head_rec == 0) {
2621
// Client disconnected.
2622
return ERR_CONNECTION_ERROR;
2623
}
2624
2625
if (head_rec == -1) {
2626
if (errno == ECONNRESET) {
2627
// No need to print the error, the client forcefully disconnected, that's
2628
// fine.
2629
return ERR_CONNECTION_ERROR;
2630
}
2631
2632
ERR_FAIL_V_MSG(FAILED, vformat("Can't read message header: %s", strerror(errno)));
2633
}
2634
2635
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));
2636
2637
// Header is two 32-bit words: first is ID, second has size in most significant
2638
// half and opcode in the other half.
2639
info.raw_id = header[0];
2640
info.size = header[1] >> 16;
2641
info.opcode = header[1] & 0xFFFF;
2642
info.direction = p_fd != compositor_socket ? ProxyDirection::COMPOSITOR : ProxyDirection::CLIENT;
2643
}
2644
2645
if (msg_buf.size() < info.words()) {
2646
msg_buf.resize(info.words());
2647
}
2648
2649
ERR_FAIL_COND_V_MSG(info.size % WL_WORD_SIZE != 0, ERR_CONNECTION_ERROR, "Invalid message length.");
2650
2651
struct msghdr full_msg = {};
2652
struct iovec vec = { msg_buf.ptr(), info.size };
2653
{
2654
full_msg.msg_iov = &vec;
2655
full_msg.msg_iovlen = 1;
2656
full_msg.msg_control = ancillary_buf.ptr();
2657
full_msg.msg_controllen = ancillary_buf.size();
2658
2659
ssize_t full_rec = recvmsg(p_fd, &full_msg, 0);
2660
2661
if (full_rec == -1) {
2662
if (errno == ECONNRESET) {
2663
// No need to print the error, the client forcefully disconnected, that's
2664
// fine.
2665
return ERR_CONNECTION_ERROR;
2666
}
2667
2668
ERR_FAIL_V_MSG(FAILED, vformat("Can't read message: %s", strerror(errno)));
2669
}
2670
2671
ERR_FAIL_COND_V_MSG(((size_t)full_rec) != info.size, ERR_CONNECTION_ERROR, "Invalid message length.");
2672
2673
DEBUG_LOG_WAYLAND_EMBED(" === START PACKET === ");
2674
2675
#ifdef WAYLAND_EMBED_DEBUG_LOGS_ENABLED
2676
printf("[PROXY] Received bytes: ");
2677
for (ssize_t i = 0; i < full_rec; ++i) {
2678
printf("%.2x", ((const uint8_t *)msg_buf.ptr())[i]);
2679
}
2680
printf("\n");
2681
#endif
2682
}
2683
2684
if (full_msg.msg_controllen > 0) {
2685
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&full_msg);
2686
while (cmsg) {
2687
// TODO: Check for validity of message fields.
2688
size_t data_len = cmsg->cmsg_len - sizeof *cmsg;
2689
2690
if (cmsg->cmsg_type == SCM_RIGHTS) {
2691
// NOTE: Linux docs say that we can't just cast data to pointer type because
2692
// of alignment concerns. So we have to memcpy into a new buffer.
2693
int *cmsg_fds = (int *)malloc(data_len);
2694
memcpy(cmsg_fds, CMSG_DATA(cmsg), data_len);
2695
2696
size_t cmsg_fds_count = data_len / sizeof *cmsg_fds;
2697
for (size_t i = 0; i < cmsg_fds_count; ++i) {
2698
int fd = cmsg_fds[i];
2699
2700
if (info.direction == ProxyDirection::COMPOSITOR) {
2701
clients[p_fd].fds.push_back(fd);
2702
} else {
2703
compositor_fds.push_back(fd);
2704
}
2705
}
2706
2707
#ifdef WAYLAND_EMBED_DEBUG_LOGS_ENABLED
2708
printf("[PROXY] Received %ld file descriptors: ", cmsg_fds_count);
2709
for (size_t i = 0; i < cmsg_fds_count; ++i) {
2710
printf("%d ", cmsg_fds[i]);
2711
}
2712
printf("\n");
2713
#endif
2714
2715
free(cmsg_fds);
2716
}
2717
2718
cmsg = CMSG_NXTHDR(&full_msg, cmsg);
2719
}
2720
}
2721
full_msg.msg_control = nullptr;
2722
full_msg.msg_controllen = 0;
2723
2724
Client *client = nullptr;
2725
if (p_fd == compositor_socket) {
2726
// Let's figure out the recipient of the message.
2727
for (KeyValue<int, Client> &pair : clients) {
2728
Client &c = pair.value;
2729
2730
if (c.local_ids.has(info.raw_id)) {
2731
client = &c;
2732
}
2733
}
2734
} else {
2735
CRASH_COND(!clients.has(p_fd));
2736
client = &clients[p_fd];
2737
}
2738
2739
LocalVector<int> sent_fds;
2740
Error err = handle_msg_info(client, &info, msg_buf.ptr(), sent_fds);
2741
2742
for (int fd : sent_fds) {
2743
DEBUG_LOG_WAYLAND_EMBED(vformat("Closing fd %d.", fd));
2744
close(fd);
2745
}
2746
2747
DEBUG_LOG_WAYLAND_EMBED(" === END PACKET === ");
2748
2749
if (err != OK) {
2750
return ERR_BUG;
2751
}
2752
2753
return OK;
2754
}
2755
2756
void WaylandEmbedder::_thread_loop(void *p_data) {
2757
Thread::set_name("Wayland Embed");
2758
2759
ERR_FAIL_NULL(p_data);
2760
WaylandEmbedder *proxy = (WaylandEmbedder *)p_data;
2761
2762
DEBUG_LOG_WAYLAND_EMBED("Proxy thread started");
2763
2764
while (!proxy->thread_done.is_set()) {
2765
proxy->poll_sockets();
2766
}
2767
}
2768
2769
Error WaylandEmbedder::init() {
2770
ancillary_buf.resize(EMBED_ANCILLARY_BUF_SIZE);
2771
2772
proxy_socket = socket(AF_UNIX, SOCK_STREAM, 0);
2773
2774
struct sockaddr_un addr = {};
2775
addr.sun_family = AF_UNIX;
2776
2777
String runtime_dir_path = OS::get_singleton()->get_environment("XDG_RUNTIME_DIR");
2778
ERR_FAIL_COND_V_MSG(runtime_dir_path.is_empty(), ERR_DOES_NOT_EXIST, "XDG_RUNTIME_DIR is not set or empty.");
2779
2780
runtime_dir = DirAccess::create_for_path(runtime_dir_path);
2781
ERR_FAIL_COND_V(!runtime_dir.is_valid(), ERR_BUG);
2782
ERR_FAIL_COND_V_MSG(!runtime_dir->is_writable(runtime_dir_path), ERR_FILE_CANT_WRITE, "XDG_RUNTIME_DIR points to an invalid directory.");
2783
2784
int socket_id = 0;
2785
while (socket_path.is_empty()) {
2786
String test_socket_path = runtime_dir_path + "/godot-wayland-" + itos(socket_id);
2787
String test_socket_lock_path = test_socket_path + ".lock";
2788
2789
print_verbose(vformat("Trying to get socket %s", test_socket_path));
2790
print_verbose(vformat("Opening lock %s", test_socket_lock_path));
2791
int test_lock_fd = open(test_socket_lock_path.utf8().get_data(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
2792
2793
if (flock(test_lock_fd, LOCK_EX | LOCK_NB) == -1) {
2794
print_verbose(vformat("Can't lock %s", test_socket_lock_path));
2795
close(test_lock_fd);
2796
++socket_id;
2797
continue;
2798
} else {
2799
lock_fd = test_lock_fd;
2800
socket_path = test_socket_path;
2801
socket_lock_path = test_socket_lock_path;
2802
2803
break;
2804
}
2805
}
2806
2807
DirAccess::remove_absolute(socket_path);
2808
strncpy(addr.sun_path, socket_path.utf8().get_data(), sizeof(addr.sun_path) - 1);
2809
2810
if (bind(proxy_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
2811
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't bind embedding socket.");
2812
}
2813
2814
if (listen(proxy_socket, 1) == -1) {
2815
ERR_FAIL_V_MSG(ERR_CANT_OPEN, "Can't listen embedding socket.");
2816
}
2817
2818
struct wl_display *display = wl_display_connect(nullptr);
2819
ERR_FAIL_NULL_V(display, ERR_CANT_OPEN);
2820
compositor_socket = wl_display_get_fd(display);
2821
2822
pollfds.push_back({ proxy_socket, POLLIN, 0 });
2823
pollfds.push_back({ compositor_socket, POLLIN, 0 });
2824
2825
RegistryGlobalInfo control_global_info = {};
2826
control_global_info.interface = &godot_embedding_compositor_interface;
2827
control_global_info.version = godot_embedding_compositor_interface.version;
2828
2829
godot_embedding_compositor_name = registry_globals_counter++;
2830
registry_globals[godot_embedding_compositor_name] = control_global_info;
2831
2832
{
2833
uint32_t invalid_id = INVALID_ID;
2834
objects.request(invalid_id);
2835
2836
CRASH_COND(invalid_id != INVALID_ID);
2837
}
2838
2839
{
2840
uint32_t display_id = new_object(&wl_display_interface);
2841
CRASH_COND(display_id != DISPLAY_ID);
2842
2843
get_object(DISPLAY_ID)->shared = true;
2844
}
2845
2846
{
2847
uint32_t registry_id = new_object(&wl_registry_interface);
2848
CRASH_COND(registry_id != REGISTRY_ID);
2849
2850
get_object(REGISTRY_ID)->shared = true;
2851
}
2852
2853
// wl_display::get_registry(n)
2854
send_wayland_message(compositor_socket, DISPLAY_ID, 1, { REGISTRY_ID });
2855
2856
sync();
2857
2858
proxy_thread.start(_thread_loop, this);
2859
2860
return OK;
2861
}
2862
2863
void WaylandEmbedder::handle_fd(int p_fd, int p_revents) {
2864
if (p_fd == proxy_socket && p_revents & POLLIN) {
2865
// Client init.
2866
int new_fd = accept(proxy_socket, nullptr, nullptr);
2867
ERR_FAIL_COND_MSG(new_fd == -1, "Failed to accept client.");
2868
2869
struct ucred cred = {};
2870
socklen_t cred_size = sizeof cred;
2871
getsockopt(new_fd, SOL_SOCKET, SO_PEERCRED, &cred, &cred_size);
2872
2873
Client &client = clients.insert_new(new_fd, {})->value;
2874
2875
client.embedder = this;
2876
client.socket = new_fd;
2877
client.pid = cred.pid;
2878
2879
client.global_ids[DISPLAY_ID] = Client::GlobalIdInfo(DISPLAY_ID, nullptr);
2880
client.local_ids[DISPLAY_ID] = DISPLAY_ID;
2881
2882
pollfds.push_back({ new_fd, POLLIN, 0 });
2883
2884
if (main_client == nullptr) {
2885
main_client = &client;
2886
}
2887
2888
if (new_fd != main_client->socket && main_client->registry_globals_instances.has(godot_embedding_compositor_name)) {
2889
uint32_t new_local_id = main_client->allocate_server_id();
2890
2891
client.embedded_client_id = new_local_id;
2892
2893
for (uint32_t local_id : main_client->registry_globals_instances[godot_embedding_compositor_name]) {
2894
EmbeddedClientData *eclient_data = memnew(EmbeddedClientData);
2895
eclient_data->client = &client;
2896
2897
main_client->new_fake_object(new_local_id, &godot_embedded_client_interface, 1, eclient_data);
2898
2899
// godot_embedding_compositor::client(nu)
2900
send_wayland_message(main_client->socket, local_id, 0, { new_local_id, (uint32_t)cred.pid });
2901
}
2902
}
2903
2904
DEBUG_LOG_WAYLAND_EMBED(vformat("New client %d (pid %d) initialized.", client.socket, cred.pid));
2905
return;
2906
}
2907
2908
if (p_fd == compositor_socket && p_revents & POLLIN) {
2909
Error err = handle_sock(p_fd);
2910
2911
if (err == ERR_BUG) {
2912
ERR_PRINT("Unexpected error while handling socket, shutting down.");
2913
shutdown();
2914
return;
2915
}
2916
2917
return;
2918
}
2919
2920
const Client *client = clients.getptr(p_fd);
2921
if (client) {
2922
if (main_client && client == main_client && p_revents & (POLLHUP | POLLERR)) {
2923
DEBUG_LOG_WAYLAND_EMBED("Main client disconnected, shutting down.");
2924
shutdown();
2925
return;
2926
}
2927
2928
if (p_revents & POLLIN) {
2929
Error err = handle_sock(p_fd);
2930
if (err == ERR_BUG) {
2931
ERR_PRINT("Unexpected error while handling socket, shutting down.");
2932
shutdown();
2933
return;
2934
}
2935
2936
if (err != OK) {
2937
DEBUG_LOG_WAYLAND_EMBED("disconnecting");
2938
cleanup_socket(p_fd);
2939
return;
2940
}
2941
2942
return;
2943
} else if (p_revents & (POLLHUP | POLLERR | POLLNVAL)) {
2944
if (p_revents & POLLHUP) {
2945
DEBUG_LOG_WAYLAND_EMBED(vformat("Socket %d hangup.", p_fd));
2946
}
2947
if (p_revents & POLLERR) {
2948
DEBUG_LOG_WAYLAND_EMBED(vformat("Socket %d error.", p_fd));
2949
}
2950
if (p_revents & POLLNVAL) {
2951
DEBUG_LOG_WAYLAND_EMBED(vformat("Socket %d invalid FD.", p_fd));
2952
}
2953
2954
cleanup_socket(p_fd);
2955
2956
return;
2957
}
2958
}
2959
}
2960
2961
WaylandEmbedder::~WaylandEmbedder() {
2962
shutdown();
2963
if (proxy_thread.is_started()) {
2964
proxy_thread.wait_to_finish();
2965
}
2966
}
2967
2968
#endif // TOOLS_ENABLED
2969
2970
#endif // WAYLAND_ENABLED
2971
2972