From 5c27bc81d8f80d4b7c28822cfb0d9f6f31497fa0 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Mon, 3 Apr 2023 12:57:36 -0400
Subject: [PATCH] wayland: Use release for display and seat objects, if
available
wl_seat and wl_output gained release methods, which should be preferred over destroy methods if they are available.
Bumps wl_output to version 3.
---
src/video/wayland/SDL_waylandevents.c | 24 +++++--
src/video/wayland/SDL_waylandvideo.c | 99 +++++++++------------------
src/video/wayland/SDL_waylandvideo.h | 4 +-
3 files changed, 56 insertions(+), 71 deletions(-)
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index aa376556ff8f..8b56941cb634 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -2730,16 +2730,28 @@ void Wayland_display_destroy_input(SDL_VideoData *d)
}
if (input->keyboard) {
- wl_keyboard_destroy(input->keyboard);
+ if (wl_keyboard_get_version(input->keyboard) >= WL_KEYBOARD_RELEASE_SINCE_VERSION) {
+ wl_keyboard_release(input->keyboard);
+ } else {
+ wl_keyboard_destroy(input->keyboard);
+ }
}
if (input->pointer) {
- wl_pointer_destroy(input->pointer);
+ if (wl_pointer_get_version(input->pointer) >= WL_POINTER_RELEASE_SINCE_VERSION) {
+ wl_pointer_release(input->pointer);
+ } else {
+ wl_pointer_destroy(input->pointer);
+ }
}
if (input->touch) {
SDL_DelTouch(1);
- wl_touch_destroy(input->touch);
+ if (wl_touch_get_version(input->touch) >= WL_TOUCH_RELEASE_SINCE_VERSION) {
+ wl_touch_release(input->touch);
+ } else {
+ wl_touch_destroy(input->touch);
+ }
}
if (input->tablet) {
@@ -2747,7 +2759,11 @@ void Wayland_display_destroy_input(SDL_VideoData *d)
}
if (input->seat) {
- wl_seat_destroy(input->seat);
+ if (wl_seat_get_version(input->seat) >= WL_SEAT_RELEASE_SINCE_VERSION) {
+ wl_seat_release(input->seat);
+ } else {
+ wl_seat_destroy(input->seat);
+ }
}
if (input->xkb.compose_state) {
diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index 5dd2e49e4609..8985593bdf05 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -188,6 +188,7 @@ static SDL_VideoDevice *Wayland_CreateDevice(void)
data->initializing = SDL_TRUE;
data->display = display;
+ WAYLAND_wl_list_init(&data->output_list);
/* Initialize all variables that we clean on shutdown */
device = SDL_calloc(1, sizeof(SDL_VideoDevice));
@@ -660,12 +661,12 @@ static const struct wl_output_listener output_listener = {
display_handle_scale
};
-static int Wayland_add_display(SDL_VideoData *d, uint32_t id)
+static int Wayland_add_display(SDL_VideoData *d, uint32_t id, uint32_t version)
{
struct wl_output *output;
SDL_DisplayData *data;
- output = wl_registry_bind(d->registry, id, &wl_output_interface, 2);
+ output = wl_registry_bind(d->registry, id, &wl_output_interface, version);
if (output == NULL) {
return SDL_SetError("Failed to retrieve output.");
}
@@ -679,17 +680,7 @@ static int Wayland_add_display(SDL_VideoData *d, uint32_t id)
SDL_WAYLAND_register_output(output);
/* Keep a list of outputs for deferred xdg-output initialization. */
- if (d->output_list != NULL) {
- SDL_DisplayData *node = d->output_list;
-
- while (node->next != NULL) {
- node = node->next;
- }
-
- node->next = data;
- } else {
- d->output_list = data;
- }
+ WAYLAND_wl_list_insert(&d->output_list, &data->link);
if (data->videodata->xdg_output_manager) {
data->xdg_output = zxdg_output_manager_v1_get_xdg_output(data->videodata->xdg_output_manager, output);
@@ -698,49 +689,34 @@ static int Wayland_add_display(SDL_VideoData *d, uint32_t id)
return 0;
}
-static void Wayland_free_display(SDL_VideoData *d, uint32_t id)
+static void Wayland_free_display(SDL_VideoDisplay *display)
{
- SDL_DisplayID *displays;
- SDL_VideoDisplay *display;
- SDL_DisplayData *data;
- int i;
+ if (display) {
+ SDL_DisplayData *display_data = display->driverdata;
+ int i;
- displays = SDL_GetDisplays(NULL);
- if (displays) {
- for (i = 0; displays[i]; ++i) {
- display = SDL_GetVideoDisplay(displays[i]);
- data = display->driverdata;
- if (data->registry_id == id) {
- if (d->output_list != NULL) {
- SDL_DisplayData *node = d->output_list;
- if (node == data) {
- d->output_list = node->next;
- } else {
- while (node->next != data && node->next != NULL) {
- node = node->next;
- }
- if (node->next != NULL) {
- node->next = node->next->next;
- }
- }
- }
- SDL_DelVideoDisplay(displays[i], SDL_FALSE);
- if (data->xdg_output) {
- zxdg_output_v1_destroy(data->xdg_output);
- }
- wl_output_destroy(data->output);
- SDL_free(data);
- break;
- }
+ if (wl_output_get_version(display_data->output) >= WL_OUTPUT_RELEASE_SINCE_VERSION) {
+ wl_output_release(display_data->output);
+ } else {
+ wl_output_destroy(display_data->output);
+ }
+
+ /* Unlink this display. */
+ WAYLAND_wl_list_remove(&display_data->link);
+
+ /* Null the driverdata member of the mode structs, or they will be wrongly freed. */
+ for (i = display->num_fullscreen_modes; i--;) {
+ display->fullscreen_modes[i].driverdata = NULL;
}
- SDL_free(displays);
+ display->desktop_mode.driverdata = NULL;
+ SDL_DelVideoDisplay(display->id, SDL_FALSE);
}
}
static void Wayland_init_xdg_output(SDL_VideoData *d)
{
SDL_DisplayData *node;
- for (node = d->output_list; node != NULL; node = node->next) {
+ wl_list_for_each(node, &d->output_list, link) {
node->xdg_output = zxdg_output_manager_v1_get_xdg_output(node->videodata->xdg_output_manager, node->output);
zxdg_output_v1_add_listener(node->xdg_output, &xdg_output_listener, node);
}
@@ -795,7 +771,7 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint
if (SDL_strcmp(interface, "wl_compositor") == 0) {
d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, SDL_min(4, version));
} else if (SDL_strcmp(interface, "wl_output") == 0) {
- Wayland_add_display(d, id);
+ Wayland_add_display(d, id, SDL_min(version, 3));
} else if (SDL_strcmp(interface, "wl_seat") == 0) {
Wayland_display_add_input(d, id, version);
} else if (SDL_strcmp(interface, "xdg_wm_base") == 0) {
@@ -856,8 +832,15 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint
static void display_remove_global(void *data, struct wl_registry *registry, uint32_t id)
{
SDL_VideoData *d = data;
+ SDL_DisplayData *node;
+
/* We don't get an interface, just an ID, so assume it's a wl_output :shrug: */
- Wayland_free_display(d, id);
+ wl_list_for_each (node, &d->output_list, link) {
+ if (node->registry_id == id) {
+ Wayland_free_display(SDL_GetVideoDisplay(node->display));
+ break;
+ }
+ }
}
static const struct wl_registry_listener registry_listener = {
@@ -969,28 +952,14 @@ static int Wayland_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *
static void Wayland_VideoCleanup(_THIS)
{
SDL_VideoData *data = _this->driverdata;
- int i, j;
+ int i;
Wayland_FiniMouse(data);
for (i = _this->num_displays - 1; i >= 0; --i) {
SDL_VideoDisplay *display = &_this->displays[i];
-
- if (display->driverdata->xdg_output) {
- zxdg_output_v1_destroy(display->driverdata->xdg_output);
- }
-
- wl_output_destroy(display->driverdata->output);
- SDL_free(display->driverdata);
- display->driverdata = NULL;
-
- for (j = display->num_fullscreen_modes; j--;) {
- display->fullscreen_modes[j].driverdata = NULL;
- }
- display->desktop_mode.driverdata = NULL;
- SDL_DelVideoDisplay(display->id, SDL_FALSE);
+ Wayland_free_display(display);
}
- data->output_list = NULL;
Wayland_display_destroy_input(data);
Wayland_display_destroy_pointer_constraints(data);
diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h
index 6f70442f2893..b6b94bc9cdd8 100644
--- a/src/video/wayland/SDL_waylandvideo.h
+++ b/src/video/wayland/SDL_waylandvideo.h
@@ -82,7 +82,7 @@ struct SDL_VideoData
struct xkb_context *xkb_context;
struct SDL_WaylandInput *input;
struct SDL_WaylandTabletManager *tablet_manager;
- SDL_DisplayData *output_list;
+ struct wl_list output_list;
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
struct SDL_WaylandTouch *touch;
@@ -110,7 +110,7 @@ struct SDL_DisplayData
SDL_DisplayID display;
SDL_VideoDisplay placeholder;
int wl_output_done_count;
- SDL_DisplayData *next;
+ struct wl_list link;
};
/* Needed here to get wl_surface declaration, fixes GitHub#4594 */