Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
authorCampbell Barton <campbell@blender.org>2022-10-27 09:24:51 +0300
committerCampbell Barton <campbell@blender.org>2022-10-27 11:23:46 +0300
commite75be000e3e83b53e0fc18c5719f41de37bd6a75 (patch)
tree884b50f7c8ce83b64bbd7d38cb648757603382a2 /intern
parent1e7776907c004ad8c6081b4cfcdeda5ec793b174 (diff)
GHOST/Wayland: replace deferred registration with an update callback
There were two issues caused by deferred registration (added by [0]), one crash on startup (T102075), another unreported issue with the GLX/EGL context failing to initialize. Unfortunately I'm unable to reproduce the errors but it seems likely deferring interface registration is not well supported so this commit uses an alternative solution to some interfaces depending on others for initialization. Instead of relying on the order of registration, a separate "update" callback has been added which is called after binding interfaces. This has the advantage that it can be called when adding/removing interfaces at run-time to avoid the dangling pointers being left in locally allocated structures. In practice adding/removing interfaces happens so rarely (only with "outputs" as far as I'm aware) that this benefit is theoretical at the moment. This should resolve T102075. [0]: 9fe9705bc0af9d881905d75957c8dd467f8c8cb3
Diffstat (limited to 'intern')
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp287
1 files changed, 171 insertions, 116 deletions
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index 87e5f9bb8d5..d4eabfb815d 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -763,17 +763,17 @@ static GWL_SeatStatePointer *gwl_seat_state_pointer_from_cursor_surface(
* \{ */
struct GWL_RegistryEntry;
-struct GWL_RegistryAdd_Deferred;
struct GWL_Display {
GHOST_SystemWayland *system = nullptr;
/**
- * An array of registration arguments aligned with `gwl_registry_handlers`.
- * Only used during registration at startup.
+ * True when initializing registration, while updating all other entries wont cause problems,
+ * it will preform many redundant update calls.
*/
- struct GWL_RegistryAdd_Deferred **registry_add_deferred = nullptr;
- /** Registry entries, kept to allow removal at run-time. */
+ bool registry_skip_update_all = false;
+
+ /** Registry entries, kept to allow updating & removal at run-time. */
struct GWL_RegistryEntry *registry_entry = nullptr;
struct wl_registry *wl_registry = nullptr;
@@ -852,21 +852,42 @@ static void gwl_display_destroy(GWL_Display *display)
* \{ */
struct GWL_RegisteryAdd_Params {
- struct GWL_Display *display = nullptr;
uint32_t name = 0;
- uint32_t version = 0;
/** Index within `gwl_registry_handlers`. */
int interface_slot = 0;
+ uint32_t version = 0;
};
/**
* Add callback for object registry.
+ * \note Any operations that depend on other interfaces being registered must be performed in the
+ * #GWL_RegistryHandler_UpdateFn callback as the order interfaces are added is out of our control.
+ *
* \param display: The display which holes a reference to the global object.
* \param params: Various arguments needed for registration.
*/
using GWL_RegistryHandler_AddFn = void (*)(GWL_Display *display,
const GWL_RegisteryAdd_Params *params);
+struct GWL_RegisteryUpdate_Params {
+ uint32_t name = 0;
+ /** Index within `gwl_registry_handlers`. */
+ int interface_slot = 0;
+ uint32_t version = 0;
+
+ /** Set to #GWL_RegistryEntry.user_data. */
+ void *user_data = nullptr;
+};
+
+/**
+ * Optional update callback to refresh internal data when another interface has been added/removed.
+ *
+ * \param display: The display which holes a reference to the global object.
+ * \param params: Various arguments needed for updating.
+ */
+using GWL_RegistryHandler_UpdateFn = void (*)(GWL_Display *display,
+ const GWL_RegisteryUpdate_Params *params);
+
/**
* Remove callback for object registry.
* \param display: The display which holes a reference to the global object.
@@ -883,7 +904,11 @@ struct GWL_RegistryHandler {
/** Pointer to the name (not the name it's self), needed as the values aren't set on startup. */
const char *const *interface_p = nullptr;
+ /** Add the interface. */
GWL_RegistryHandler_AddFn add_fn = nullptr;
+ /** Optional update the interface (when other interfaces have been added/removed). */
+ GWL_RegistryHandler_UpdateFn update_fn = nullptr;
+ /** Remove the interface. */
GWL_RegistryEntry_RemoveFn remove_fn = nullptr;
};
@@ -910,6 +935,10 @@ struct GWL_RegistryEntry {
*/
uint32_t name = WL_NAME_UNSET;
/**
+ * Version passed by the add callback.
+ */
+ uint32_t version;
+ /**
* The index in `gwl_registry_handlers`,
* useful for accessing the interface name (for logging for example).
*/
@@ -917,14 +946,14 @@ struct GWL_RegistryEntry {
};
static void gwl_registry_entry_add(GWL_Display *display,
- const int interface_slot,
- const uint32_t name,
+ const GWL_RegisteryAdd_Params *params,
void *user_data)
{
GWL_RegistryEntry *reg = new GWL_RegistryEntry;
- reg->interface_slot = interface_slot;
- reg->name = name;
+ reg->interface_slot = params->interface_slot;
+ reg->name = params->name;
+ reg->version = params->version;
reg->user_data = user_data;
reg->next = display->registry_entry;
@@ -1016,6 +1045,49 @@ static void gwl_registry_entry_remove_all(GWL_Display *display)
display->registry_entry = nullptr;
}
+/**
+ * Run GWL_RegistryHandler.update_fn an all registered interface instances.
+ * This is needed to refresh the state of interfaces that may reference other interfaces.
+ * Called when interfaces are added/removed.
+ *
+ * \param interface_slot_exclude: Skip updating slots of this type.
+ * Note that while harmless dependencies only exist between different types,
+ * so there is no reason to update all other outputs that an output was removed (for e.g.).
+ * Pass as -1 to update all slots.
+ *
+ * NOTE(@campbellbarton): Updating all other items on a single change is typically worth avoiding.
+ * In practice this isn't a problem as so there are so few elements in `display->registry_entry`,
+ * so few use update functions and adding/removal at runtime is rarely called (plugging/unplugging)
+ * hardware for e.g. So while it's possible to store dependency links to avoid unnecessary
+ * looping over data - so it ends up being a non issue.
+ */
+static void gwl_registry_entry_update_all(GWL_Display *display, const int interface_slot_exclude)
+{
+ GHOST_ASSERT(interface_slot_exclude == -1 || (uint(interface_slot_exclude) <
+ uint(gwl_registry_handler_interface_slot_max())),
+ "Invalid exclude slot");
+
+ for (GWL_RegistryEntry *reg = display->registry_entry; reg; reg = reg->next) {
+ if (reg->interface_slot == interface_slot_exclude) {
+ continue;
+ }
+ const GWL_RegistryHandler *handler = gwl_registry_handler_from_interface_slot(
+ reg->interface_slot);
+ if (handler->update_fn == nullptr) {
+ continue;
+ }
+
+ GWL_RegisteryUpdate_Params params = {
+ .name = reg->name,
+ .interface_slot = reg->interface_slot,
+ .version = reg->version,
+
+ .user_data = reg->user_data,
+ };
+ handler->update_fn(display, &params);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -4153,8 +4225,7 @@ static void gwl_registry_compositor_add(GWL_Display *display,
{
display->wl_compositor = static_cast<wl_compositor *>(
wl_registry_bind(display->wl_registry, params->name, &wl_compositor_interface, 3));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_compositor_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4175,8 +4246,7 @@ static void gwl_registry_xdg_wm_base_add(GWL_Display *display,
wl_registry_bind(display->wl_registry, params->name, &xdg_wm_base_interface, 1));
xdg_wm_base_add_listener(decor.shell, &shell_listener, nullptr);
decor.shell_name = params->name;
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_xdg_wm_base_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4199,8 +4269,7 @@ static void gwl_registry_xdg_decoration_manager_add(GWL_Display *display,
decor.manager = static_cast<zxdg_decoration_manager_v1 *>(wl_registry_bind(
display->wl_registry, params->name, &zxdg_decoration_manager_v1_interface, 1));
decor.manager_name = params->name;
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_xdg_decoration_manager_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4221,13 +4290,7 @@ static void gwl_registry_xdg_output_manager_add(GWL_Display *display,
{
display->xdg_output_manager = static_cast<zxdg_output_manager_v1 *>(
wl_registry_bind(display->wl_registry, params->name, &zxdg_output_manager_v1_interface, 2));
- for (GWL_Output *output : display->outputs) {
- output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager,
- output->wl_output);
- zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
- }
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_xdg_output_manager_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4236,10 +4299,6 @@ static void gwl_registry_xdg_output_manager_remove(GWL_Display *display,
struct zxdg_output_manager_v1 **value_p = &display->xdg_output_manager;
zxdg_output_manager_v1_destroy(*value_p);
*value_p = nullptr;
-
- for (GWL_Output *output : display->outputs) {
- output->xdg_output = nullptr;
- }
}
/* #GWL_Display.wl_output */
@@ -4255,15 +4314,22 @@ static void gwl_registry_wl_output_add(GWL_Display *display, const GWL_Registery
display->outputs.push_back(output);
wl_output_add_listener(output->wl_output, &output_listener, output);
-
+ gwl_registry_entry_add(display, params, static_cast<void *>(output));
+}
+static void gwl_registry_wl_output_update(GWL_Display *display,
+ const GWL_RegisteryUpdate_Params *params)
+{
+ GWL_Output *output = static_cast<GWL_Output *>(params->user_data);
if (display->xdg_output_manager) {
- output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager,
- output->wl_output);
- zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
+ if (output->xdg_output == nullptr) {
+ output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager,
+ output->wl_output);
+ zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
+ }
+ }
+ else {
+ output->xdg_output = nullptr;
}
-
- gwl_registry_entry_add(
- display, params->interface_slot, params->name, static_cast<void *>(output));
}
static void gwl_registry_wl_output_remove(GWL_Display *display,
void *user_data,
@@ -4294,18 +4360,31 @@ static void gwl_registry_wl_seat_add(GWL_Display *display, const GWL_RegisteryAd
wl_registry_bind(display->wl_registry, params->name, &wl_seat_interface, 5));
display->seats.push_back(seat);
wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
+ gwl_registry_entry_add(display, params, static_cast<void *>(seat));
+}
+static void gwl_registry_wl_seat_update(GWL_Display *display,
+ const GWL_RegisteryUpdate_Params *params)
+{
+ GWL_Seat *seat = static_cast<GWL_Seat *>(params->user_data);
- /* Register data device per seat for IPC between Wayland clients. */
+ /* Register data device per seat for IPC between WAYLAND clients. */
if (display->wl_data_device_manager) {
- seat->wl_data_device = wl_data_device_manager_get_data_device(display->wl_data_device_manager,
- seat->wl_seat);
- wl_data_device_add_listener(seat->wl_data_device, &data_device_listener, seat);
+ if (seat->wl_data_device == nullptr) {
+ seat->wl_data_device = wl_data_device_manager_get_data_device(
+ display->wl_data_device_manager, seat->wl_seat);
+ wl_data_device_add_listener(seat->wl_data_device, &data_device_listener, seat);
+ }
+ }
+ else {
+ seat->wl_data_device = nullptr;
}
if (display->wp_tablet_manager) {
- seat->wp_tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(display->wp_tablet_manager,
- seat->wl_seat);
- zwp_tablet_seat_v2_add_listener(seat->wp_tablet_seat, &tablet_seat_listener, seat);
+ if (seat->wp_tablet_seat == nullptr) {
+ seat->wp_tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(display->wp_tablet_manager,
+ seat->wl_seat);
+ zwp_tablet_seat_v2_add_listener(seat->wp_tablet_seat, &tablet_seat_listener, seat);
+ }
}
if (display->wp_primary_selection_device_manager) {
@@ -4318,8 +4397,9 @@ static void gwl_registry_wl_seat_add(GWL_Display *display, const GWL_RegisteryAd
&seat->primary_selection);
}
}
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, static_cast<void *>(seat));
+ else {
+ seat->wp_primary_selection_device = nullptr;
+ }
}
static void gwl_registry_wl_seat_remove(GWL_Display *display, void *user_data, const bool on_exit)
{
@@ -4415,8 +4495,7 @@ static void gwl_registry_wl_shm_add(GWL_Display *display, const GWL_RegisteryAdd
{
display->wl_shm = static_cast<wl_shm *>(
wl_registry_bind(display->wl_registry, params->name, &wl_shm_interface, 1));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wl_shm_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4434,8 +4513,7 @@ static void gwl_registry_wl_data_device_manager_add(GWL_Display *display,
{
display->wl_data_device_manager = static_cast<wl_data_device_manager *>(
wl_registry_bind(display->wl_registry, params->name, &wl_data_device_manager_interface, 3));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wl_data_device_manager_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4453,8 +4531,7 @@ static void gwl_registry_wp_tablet_manager_add(GWL_Display *display,
{
display->wp_tablet_manager = static_cast<zwp_tablet_manager_v2 *>(
wl_registry_bind(display->wl_registry, params->name, &zwp_tablet_manager_v2_interface, 1));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wp_tablet_manager_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4473,8 +4550,7 @@ static void gwl_registry_wp_relative_pointer_manager_add(GWL_Display *display,
display->wp_relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1 *>(
wl_registry_bind(
display->wl_registry, params->name, &zwp_relative_pointer_manager_v1_interface, 1));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wp_relative_pointer_manager_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4492,8 +4568,7 @@ static void gwl_registry_wp_pointer_constraints_add(GWL_Display *display,
{
display->wp_pointer_constraints = static_cast<zwp_pointer_constraints_v1 *>(wl_registry_bind(
display->wl_registry, params->name, &zwp_pointer_constraints_v1_interface, 1));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wp_pointer_constraints_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4511,8 +4586,7 @@ static void gwl_registry_wp_pointer_gestures_add(GWL_Display *display,
{
display->wp_pointer_gestures = static_cast<zwp_pointer_gestures_v1 *>(
wl_registry_bind(display->wl_registry, params->name, &zwp_pointer_gestures_v1_interface, 3));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wp_pointer_gestures_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4534,8 +4608,7 @@ static void gwl_registry_wp_primary_selection_device_manager_add(
params->name,
&zwp_primary_selection_device_manager_v1_interface,
1));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wp_primary_selection_device_manager_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4548,81 +4621,90 @@ static void gwl_registry_wp_primary_selection_device_manager_remove(GWL_Display
}
/**
- * Map interfaces to to initialization functions.
+ * Map interfaces to initialization functions.
*
- * \note This list also defines the order interfaces added & removed.
- * - On startup interface registration is performed from first to last.
- * - On exit interface removal runs from last to first.
+ * \note This list also defines the order interfaces are removed.
+ * On exit interface removal runs from last to first to avoid potential bugs
+ * caused by undefined order of removal.
*
* In general fundamental, low level objects such as the compositor and shared memory
* should be declared earlier and other interfaces that may use them should be declared later.
- *
- * This is useful for predictable registration, especially when one interface depends on another.
- * It also helps avoid potential bugs caused by undefined order of removal.
*/
static const GWL_RegistryHandler gwl_registry_handlers[] = {
/* Low level interfaces. */
{
&wl_compositor_interface.name,
gwl_registry_compositor_add,
+ nullptr,
gwl_registry_compositor_remove,
},
{
&wl_shm_interface.name,
gwl_registry_wl_shm_add,
+ nullptr,
gwl_registry_wl_shm_remove,
},
{
&xdg_wm_base_interface.name,
gwl_registry_xdg_wm_base_add,
+ nullptr,
gwl_registry_xdg_wm_base_remove,
},
/* Managers. */
{
&zxdg_decoration_manager_v1_interface.name,
gwl_registry_xdg_decoration_manager_add,
+ nullptr,
gwl_registry_xdg_decoration_manager_remove,
},
{
&zxdg_output_manager_v1_interface.name,
gwl_registry_xdg_output_manager_add,
+ nullptr,
gwl_registry_xdg_output_manager_remove,
},
{
&wl_data_device_manager_interface.name,
gwl_registry_wl_data_device_manager_add,
+ nullptr,
gwl_registry_wl_data_device_manager_remove,
},
{
&zwp_primary_selection_device_manager_v1_interface.name,
gwl_registry_wp_primary_selection_device_manager_add,
+ nullptr,
gwl_registry_wp_primary_selection_device_manager_remove,
},
{
&zwp_tablet_manager_v2_interface.name,
gwl_registry_wp_tablet_manager_add,
+ nullptr,
gwl_registry_wp_tablet_manager_remove,
},
{
&zwp_relative_pointer_manager_v1_interface.name,
gwl_registry_wp_relative_pointer_manager_add,
+ nullptr,
gwl_registry_wp_relative_pointer_manager_remove,
},
/* Higher level interfaces. */
{
&zwp_pointer_constraints_v1_interface.name,
gwl_registry_wp_pointer_constraints_add,
+ nullptr,
gwl_registry_wp_pointer_constraints_remove,
},
{
&zwp_pointer_gestures_v1_interface.name,
gwl_registry_wp_pointer_gestures_add,
+ nullptr,
gwl_registry_wp_pointer_gestures_remove,
},
/* Display outputs. */
{
&wl_output_interface.name,
gwl_registry_wl_output_add,
+ gwl_registry_wl_output_update,
gwl_registry_wl_output_remove,
},
/* Seats.
@@ -4631,6 +4713,7 @@ static const GWL_RegistryHandler gwl_registry_handlers[] = {
{
&wl_seat_interface.name,
gwl_registry_wl_seat_add,
+ gwl_registry_wl_seat_update,
gwl_registry_wl_seat_remove,
},
{nullptr, nullptr, nullptr},
@@ -4663,20 +4746,6 @@ static const GWL_RegistryHandler *gwl_registry_handler_from_interface_slot(int i
return &gwl_registry_handlers[interface_slot];
}
-/**
- * Support deferred registration, needed so interface registration order on startup is predictable.
- * (defined by the interface order in `gwl_registry_handlers`)
- */
-struct GWL_RegistryAdd_Deferred {
- GWL_RegistryAdd_Deferred *next = nullptr;
-
- /* Arguments to #global_handle_add, excluding some known args:
- * `data`, `wl_registry` & `interface` are known by the caller
- * and don't need to be stored here. */
- uint32_t name = 0;
- uint32_t version = 0;
-};
-
static void global_handle_add(void *data,
[[maybe_unused]] struct wl_registry *wl_registry,
const uint32_t name,
@@ -4691,27 +4760,14 @@ static void global_handle_add(void *data,
bool added = false;
if (interface_slot != -1) {
- /* Defer registration until later (running on startup). */
- if (display->registry_add_deferred) {
- GWL_RegistryAdd_Deferred *reg_add = new GWL_RegistryAdd_Deferred;
- reg_add->name = name;
- reg_add->version = version;
-
- /* Add to the list. */
- GWL_RegistryAdd_Deferred **reg_p = &display->registry_add_deferred[interface_slot];
- reg_add->next = *reg_p;
- *reg_p = reg_add;
- return;
- }
-
const GWL_RegistryHandler *handler = &gwl_registry_handlers[interface_slot];
const GWL_RegistryEntry *registry_entry_prev = display->registry_entry;
/* The interface name that is ensured not to be freed. */
GWL_RegisteryAdd_Params params = {
.name = name,
- .version = version,
.interface_slot = interface_slot,
+ .version = version,
};
handler->add_fn(display, &params);
@@ -4736,6 +4792,14 @@ static void global_handle_add(void *data,
interface,
version,
name);
+
+ /* Initialization avoids excessive calls by calling update after all have been initialized. */
+ if (added) {
+ if (display->registry_skip_update_all == false) {
+ /* See doc-string for rationale on updating all on add/removal. */
+ gwl_registry_entry_update_all(display, interface_slot);
+ }
+ }
}
/**
@@ -4754,19 +4818,21 @@ static void global_handle_remove(void *data,
GWL_Display *display = static_cast<GWL_Display *>(data);
GHOST_ASSERT(display->wl_registry == wl_registry, "Registry argument must match!");
- /* Deferred registration only happens on startup, ensure interfaces are never removed
- * when in the process of adding, while it seems unlikely compositors would do this.
- * Better check as it's unsupported (it could be supported if this assert is ever reached). */
- GHOST_ASSERT(!display->registry_add_deferred,
- "Interface removal while deferred adding not supported");
-
int interface_slot = 0;
- bool found = gwl_registry_entry_remove_by_name(display, name, &interface_slot);
+ const bool removed = gwl_registry_entry_remove_by_name(display, name, &interface_slot);
+
CLOG_INFO(LOG,
2,
"remove (name=%u, interface=%s)",
name,
- found ? *gwl_registry_handlers[interface_slot].interface_p : "(unknown)");
+ removed ? *gwl_registry_handlers[interface_slot].interface_p : "(unknown)");
+
+ if (removed) {
+ if (display->registry_skip_update_all == false) {
+ /* See doc-string for rationale on updating all on add/removal. */
+ gwl_registry_entry_update_all(display, interface_slot);
+ }
+ }
}
static const struct wl_registry_listener registry_listener = {
@@ -4802,10 +4868,7 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background)
/* Register interfaces. */
{
- constexpr size_t registry_add_num = ARRAY_SIZE(gwl_registry_handlers) - 1;
- GWL_RegistryAdd_Deferred *registry_add_table[registry_add_num] = {nullptr};
- display_->registry_add_deferred = registry_add_table;
-
+ display_->registry_skip_update_all = true;
struct wl_registry *registry = wl_display_get_registry(display_->wl_display);
display_->wl_registry = registry;
wl_registry_add_listener(registry, &registry_listener, display_);
@@ -4814,18 +4877,10 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background)
/* Call callbacks for registered listeners. */
wl_display_roundtrip(display_->wl_display);
- /* Run #global_handle_add again without deferred registration (for predictable order). */
- display_->registry_add_deferred = nullptr;
+ /* Account for dependencies between interfaces. */
+ gwl_registry_entry_update_all(display_, -1);
- for (size_t interface_slot = 0; interface_slot < registry_add_num; interface_slot++) {
- const char *interface = *gwl_registry_handlers[interface_slot].interface_p;
- while (registry_add_table[interface_slot]) {
- GWL_RegistryAdd_Deferred *reg_add = registry_add_table[interface_slot];
- global_handle_add(display_, registry, reg_add->name, interface, reg_add->version);
- registry_add_table[interface_slot] = reg_add->next;
- delete reg_add;
- }
- }
+ display_->registry_skip_update_all = false;
}
#ifdef WITH_GHOST_WAYLAND_LIBDECOR