From c73d1a5520ee6418932c4a3baf60bcb4cfddda18 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Thu, 13 Apr 2023 13:16:39 +0100 Subject: [PATCH] Wayland: Reconnect using the new approach using a new wl_display In the case of a reconnect, application code is notified via SDL_EVENT_RENDER_DEVICE_RESET. --- src/events/SDL_mouse.c | 9 ----- src/events/SDL_mouse_c.h | 3 -- src/video/wayland/SDL_waylandevents.c | 9 ++++- src/video/wayland/SDL_waylandmouse.c | 2 - src/video/wayland/SDL_waylandmouse.h | 2 - src/video/wayland/SDL_waylandvideo.c | 57 +++++++++++++++++++-------- 6 files changed, 49 insertions(+), 33 deletions(-) diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index ee9d4a25776c5..67e88f6183b89 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -292,14 +292,6 @@ SDL_Window *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(); @@ -313,7 +305,6 @@ void SDL_ResetMouse(void) } 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 0887b5626b133..131d7ffa812a2 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -158,10 +158,7 @@ extern int SDL_SendMouseWheel(Uint64 timestamp, SDL_Window *window, SDL_MouseID /* Warp the mouse within the window, potentially overriding relative mode */ extern void SDL_PerformWarpMouseInWindow(SDL_Window *window, float x, float 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_QuitMouse(void); diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 90e4584a5d8f1..4320a54b15693 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -475,7 +475,14 @@ void Wayland_PumpEvents(SDL_VideoDevice *_this) * * Try to recover once, then quit. */ - if (!Wayland_VideoReconnect(_this)) { + int errCode = WAYLAND_wl_display_get_error(d->display); + SDL_bool reconnected = SDL_FALSE; + + if (SDL_getenv("SDL_VIDEO_WAYLAND_RECONNECT") && (errCode == EPIPE || errCode == ECONNRESET)) { + reconnected = Wayland_VideoReconnect(_this); + } + + if (!reconnected) { d->display_disconnected = 1; /* Only send a single quit message, as application shutdown might call diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c index 815c504381b98..8e70138267341 100644 --- a/src/video/wayland/SDL_waylandmouse.c +++ b/src/video/wayland/SDL_waylandmouse.c @@ -696,7 +696,6 @@ static Uint32 SDLCALL Wayland_GetGlobalMouseState(float *x, float *y) return ret; } -#if 0 /* TODO RECONNECT: See waylandvideo.c for more information! */ static void Wayland_RecreateCursor(SDL_Cursor *cursor, SDL_VideoData *vdata) { Wayland_CursorData *cdata = (Wayland_CursorData *) cursor->driverdata; @@ -750,7 +749,6 @@ void Wayland_RecreateCursors(void) } } } -#endif /* 0 */ void Wayland_InitMouse(void) { diff --git a/src/video/wayland/SDL_waylandmouse.h b/src/video/wayland/SDL_waylandmouse.h index ac194af0c064e..4975fbaa5db3d 100644 --- a/src/video/wayland/SDL_waylandmouse.h +++ b/src/video/wayland/SDL_waylandmouse.h @@ -26,8 +26,6 @@ extern void Wayland_InitMouse(void); extern void Wayland_FiniMouse(SDL_VideoData *data); -#if 0 /* TODO RECONNECT: See waylandvideo.c for more information! */ extern void Wayland_RecreateCursors(void); -#endif /* 0 */ #endif diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index a891b9079e9f4..9be9adeeba3ed 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -888,7 +888,9 @@ int Wayland_VideoInit(SDL_VideoDevice *_this) wl_registry_add_listener(data->registry, ®istry_listener, data); // First roundtrip to receive all registry objects. - WAYLAND_wl_display_roundtrip(data->display); + if (WAYLAND_wl_display_roundtrip(data->display) < 0) { + return SDL_SetError("Failed to load Wayland initial globals"); + } /* Now that we have all the protocols, load libdecor if applicable */ Wayland_LoadLibdecor(data, SDL_FALSE); @@ -1047,49 +1049,72 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this) SDL_bool Wayland_VideoReconnect(SDL_VideoDevice *_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(); + struct wl_display *new_display = WAYLAND_wl_display_connect(NULL); + struct wl_display *old_display = data->display; + + SDL_Event event; + + if (!new_display) { + return SDL_FALSE; + } + if (WAYLAND_wl_display_roundtrip(new_display) < 0) { + WAYLAND_wl_display_disconnect(new_display); + return SDL_FALSE; + } SDL_GL_MakeCurrent(NULL, NULL); + Wayland_VideoCleanup(_this); + window = _this->windows; + while (window) { + SDL_free(window->outputs); + window->outputs = NULL; + window = window->next; + } + SDL_ResetKeyboard(); SDL_ResetMouse(); - if (WAYLAND_wl_display_reconnect(data->display) < 0) { + + data->display = new_display; + data->initializing = SDL_TRUE; + + if (Wayland_VideoInit(_this) != 0) { return SDL_FALSE; } - Wayland_VideoInit(_this); - +/* When EGL supports migrating displays across connections we need to +* enable the following code. +*/ +#if 0 window = _this->windows; while (window) { - /* We're going to cheat _just_ for a second and strip the OpenGL flag. + /* + * 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; */ - window->flags &= ~SDL_WINDOW_OPENGL; SDL_RecreateWindow(window, window->flags); window = window->next; } +#endif + + event.type = SDL_EVENT_RENDER_DEVICE_RESET; + SDL_PushEvent(&event); Wayland_RecreateCursors(); - if (current_window && current_ctx) { - SDL_GL_MakeCurrent (current_window, current_ctx); - } + WAYLAND_wl_display_disconnect(old_display); + return SDL_TRUE; -#else - return SDL_FALSE; -#endif /* 0 */ } void Wayland_VideoQuit(SDL_VideoDevice *_this)