From 9c8b1fd8b69717e5978105c6733e6c6a87ed40c1 Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Sat, 29 Oct 2022 22:34:05 -0400 Subject: [PATCH] wayland: Cleanup work to aid reconnect support Co-authored-by: David Edmundson --- src/events/SDL_mouse.c | 24 +++++ src/events/SDL_mouse_c.h | 5 + src/video/wayland/SDL_waylanddyn.h | 1 + src/video/wayland/SDL_waylandevents.c | 17 ++- src/video/wayland/SDL_waylandsym.h | 6 ++ src/video/wayland/SDL_waylandvideo.c | 148 ++++++++++++++++++++------ src/video/wayland/SDL_waylandvideo.h | 2 + 7 files changed, 167 insertions(+), 36 deletions(-) diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index f315674ff..994b6a6db 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -266,6 +266,30 @@ SDL_GetMouseFocus(void) return mouse->focus; } +/* TODO RECONNECT: Hello from the Wayland video driver! + * This was once removed from SDL, but it's been added back in comment form + * because we will need it when Wayland adds compositor reconnect support. + * If you need this before we do, great! Otherwise, leave this alone, we'll + * uncomment it at the right time. + * -flibit + */ +#if 0 +void +SDL_ResetMouse(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + Uint32 buttonState = GetButtonState(mouse, SDL_FALSE); + int i; + + for (i = 1; i <= sizeof(buttonState)*8; ++i) { + if (buttonState & SDL_BUTTON(i)) { + SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, i); + } + } + SDL_assert(GetButtonState(mouse, SDL_FALSE) == 0); +} +#endif /* 0 */ + void SDL_SetMouseFocus(SDL_Window * window) { diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h index e9dda276b..6dd023041 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -164,6 +164,11 @@ extern int SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, float x, /* Warp the mouse within the window, potentially overriding relative mode */ extern void SDL_PerformWarpMouseInWindow(SDL_Window *window, int x, int y, SDL_bool ignore_relative_mode); +/* TODO RECONNECT: Set mouse state to "zero" */ +#if 0 +extern void SDL_ResetMouse(void); +#endif /* 0 */ + /* Shutdown the mouse subsystem */ extern void SDL_MouseQuit(void); diff --git a/src/video/wayland/SDL_waylanddyn.h b/src/video/wayland/SDL_waylanddyn.h index 1346e9814..12341e16f 100644 --- a/src/video/wayland/SDL_waylanddyn.h +++ b/src/video/wayland/SDL_waylanddyn.h @@ -102,6 +102,7 @@ void SDL_WAYLAND_UnloadSymbols(void); #define wl_proxy_get_tag (*WAYLAND_wl_proxy_get_tag) #define wl_proxy_marshal_flags (*WAYLAND_wl_proxy_marshal_flags) #define wl_proxy_marshal_array_flags (*WAYLAND_wl_proxy_marshal_array_flags) +#define wl_display_reconnect (*WAYLAND_wl_display_reconnect) #define wl_seat_interface (*WAYLAND_wl_seat_interface) #define wl_surface_interface (*WAYLAND_wl_surface_interface) diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 65e829c10..01e5ad404 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -420,11 +420,18 @@ Wayland_PumpEvents(_THIS) if (err < 0 && !d->display_disconnected) { /* Something has failed with the Wayland connection -- for example, * the compositor may have shut down and closed its end of the socket, - * or there is a library-specific error. No recovery is possible. */ - d->display_disconnected = 1; - /* Only send a single quit message, as application shutdown might call - * SDL_PumpEvents */ - SDL_SendQuit(); + * or there is a library-specific error. + * + * Try to recover once, then quit. + */ + if (!Wayland_VideoReconnect(_this)) { + d->display_disconnected = 1; + + /* Only send a single quit message, as application shutdown might call + * SDL_PumpEvents + */ + SDL_SendQuit(); + } } } diff --git a/src/video/wayland/SDL_waylandsym.h b/src/video/wayland/SDL_waylandsym.h index 0473fa1b1..987bc499d 100644 --- a/src/video/wayland/SDL_waylandsym.h +++ b/src/video/wayland/SDL_waylandsym.h @@ -86,6 +86,12 @@ SDL_WAYLAND_SYM(struct wl_proxy*, wl_proxy_marshal_flags, (struct wl_proxy *prox SDL_WAYLAND_SYM(struct wl_proxy*, wl_proxy_marshal_array_flags, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, union wl_argument *args)) #endif +#if 0 /* TODO RECONNECT: See waylandvideo.c for more information! */ +#if SDL_WAYLAND_CHECK_VERSION(broken, on, purpose) +SDL_WAYLAND_SYM(int, wl_display_reconnect, (struct wl_display*)); +#endif +#endif /* 0 */ + SDL_WAYLAND_INTERFACE(wl_seat_interface) SDL_WAYLAND_INTERFACE(wl_surface_interface) SDL_WAYLAND_INTERFACE(wl_shm_pool_interface) diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index 666e4efb0..318d96e08 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -1028,7 +1028,7 @@ Wayland_GetDisplayDPI(_THIS, SDL_VideoDisplay * sdl_display, float * ddpi, float } void -Wayland_VideoQuit(_THIS) +Wayland_VideoCleanup(_THIS) { SDL_VideoData *data = _this->driverdata; int i, j; @@ -1036,7 +1036,7 @@ Wayland_VideoQuit(_THIS) Wayland_QuitWin(data); Wayland_FiniMouse(data); - for (i = 0; i < _this->num_displays; ++i) { + for (i = _this->num_displays - 1; i >= 0; --i) { SDL_VideoDisplay *display = &_this->displays[i]; if (((SDL_WaylandOutputData*)display->driverdata)->xdg_output) { @@ -1051,54 +1051,158 @@ Wayland_VideoQuit(_THIS) display->display_modes[j].driverdata = NULL; } display->desktop_mode.driverdata = NULL; + SDL_DelVideoDisplay(i); } Wayland_display_destroy_input(data); Wayland_display_destroy_pointer_constraints(data); Wayland_display_destroy_relative_pointer_manager(data); - if (data->activation_manager) + if (data->activation_manager) { xdg_activation_v1_destroy(data->activation_manager); + data->activation_manager = NULL; + } - if (data->idle_inhibit_manager) + if (data->idle_inhibit_manager) { zwp_idle_inhibit_manager_v1_destroy(data->idle_inhibit_manager); + data->idle_inhibit_manager = NULL; + } - if (data->key_inhibitor_manager) + if (data->key_inhibitor_manager) { zwp_keyboard_shortcuts_inhibit_manager_v1_destroy(data->key_inhibitor_manager); + data->key_inhibitor_manager = NULL; + } Wayland_QuitKeyboard(_this); - if (data->text_input_manager) + if (data->text_input_manager) { zwp_text_input_manager_v3_destroy(data->text_input_manager); + data->text_input_manager = NULL; + } if (data->xkb_context) { WAYLAND_xkb_context_unref(data->xkb_context); data->xkb_context = NULL; } #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH - if (data->windowmanager) + if (data->windowmanager) { qt_windowmanager_destroy(data->windowmanager); + data->windowmanager = NULL; + } - if (data->surface_extension) + if (data->surface_extension) { qt_surface_extension_destroy(data->surface_extension); + data->surface_extension = NULL; + } Wayland_touch_destroy(data); #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ - if (data->tablet_manager) + if (data->tablet_manager) { zwp_tablet_manager_v2_destroy((struct zwp_tablet_manager_v2*)data->tablet_manager); + data->tablet_manager = NULL; + } - if (data->data_device_manager) + if (data->data_device_manager) { wl_data_device_manager_destroy(data->data_device_manager); + data->data_device_manager = NULL; + } - if (data->shm) + if (data->shm) { wl_shm_destroy(data->shm); + data->shm = NULL; + } - if (data->shell.xdg) + if (data->shell.xdg) { xdg_wm_base_destroy(data->shell.xdg); + data->shell.xdg = NULL; + } - if (data->decoration_manager) + if (data->decoration_manager) { zxdg_decoration_manager_v1_destroy(data->decoration_manager); + data->decoration_manager = NULL; + } + + if (data->xdg_output_manager) { + zxdg_output_manager_v1_destroy(data->xdg_output_manager); + data->xdg_output_manager = NULL; + } + + if (data->viewporter) { + wp_viewporter_destroy(data->viewporter); + data->viewporter = NULL; + } + + if (data->primary_selection_device_manager) { + zwp_primary_selection_device_manager_v1_destroy(data->primary_selection_device_manager); + data->primary_selection_device_manager = NULL; + } + + if (data->compositor) { + wl_compositor_destroy(data->compositor); + data->compositor = NULL; + } + + if (data->registry) { + wl_registry_destroy(data->registry); + data->registry = NULL; + } +} + +SDL_bool +Wayland_VideoReconnect(_THIS) +{ +#if 0 /* TODO RECONNECT: Uncomment all when https://invent.kde.org/plasma/kwin/-/wikis/Restarting is completed */ + SDL_VideoData *data = _this->driverdata; + + SDL_Window *window = NULL; + + SDL_GLContext current_ctx = SDL_GL_GetCurrentContext(); + SDL_Window *current_window = SDL_GL_GetCurrentWindow(); + + Wayland_FiniMouse(data); + + SDL_GL_MakeCurrent(NULL, NULL); + Wayland_VideoCleanup(_this); + + SDL_ResetKeyboard(); + SDL_ResetMouse(); + if (WAYLAND_wl_display_reconnect(data->display) < 0) { + return SDL_FALSE; + } + + Wayland_VideoInit(_this); + + window = _this->windows; + while (window) { + /* We're going to cheat _just_ for a second and strip the OpenGL flag. + * The Wayland driver actually forces it in CreateWindow, and + * RecreateWindow does a bunch of unloading/loading of libGL, so just + * strip the flag so RecreateWindow doesn't mess with the GL context, + * and CreateWindow will add it right back! + * -flibit + */ + window->flags &= ~SDL_WINDOW_OPENGL; + + SDL_RecreateWindow(window, window->flags); + window = window->next; + } + + if (current_window && current_ctx) { + SDL_GL_MakeCurrent (current_window, current_ctx); + } + return SDL_TRUE; +#else + return SDL_FALSE; +#endif /* 0 */ +} + +void +Wayland_VideoQuit(_THIS) +{ + SDL_VideoData *data = _this->driverdata; + + Wayland_VideoCleanup(_this); #ifdef HAVE_LIBDECOR_H if (data->shell.libdecor) { @@ -1107,24 +1211,6 @@ Wayland_VideoQuit(_THIS) } #endif - if (data->xdg_output_manager) { - zxdg_output_manager_v1_destroy(data->xdg_output_manager); - } - - if (data->viewporter) { - wp_viewporter_destroy(data->viewporter); - } - - if (data->primary_selection_device_manager) { - zwp_primary_selection_device_manager_v1_destroy(data->primary_selection_device_manager); - } - - if (data->compositor) - wl_compositor_destroy(data->compositor); - - if (data->registry) - wl_registry_destroy(data->registry); - SDL_free(data->classname); } diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h index e1825cbae..e7f66fe2d 100644 --- a/src/video/wayland/SDL_waylandvideo.h +++ b/src/video/wayland/SDL_waylandvideo.h @@ -126,6 +126,8 @@ extern SDL_bool SDL_WAYLAND_own_output(struct wl_output *output); extern SDL_bool Wayland_LoadLibdecor(SDL_VideoData *data, SDL_bool ignore_xdg); +extern SDL_bool Wayland_VideoReconnect(_THIS); + #endif /* SDL_waylandvideo_h_ */ /* vi: set ts=4 sw=4 expandtab: */