diff --git a/client/src/app.c b/client/src/app.c index 8531b373..f18bc947 100644 --- a/client/src/app.c +++ b/client/src/app.c @@ -858,6 +858,8 @@ void app_registerOverlay(const struct LG_OverlayOps * ops, const void * params) ops->earlyInit(); } +static bool l_overlaysInitialized = false; + void app_initOverlays(void) { struct Overlay * overlay; @@ -868,9 +870,12 @@ void app_initOverlays(void) if (!overlay->ops->init(&overlay->udata, overlay->params)) { DEBUG_ERROR("Overlay `%s` failed to initialize", overlay->ops->name); - overlay->ops = NULL; + ll_removeNL(g_state.overlays, item); + free(item); + free(overlay); } } + l_overlaysInitialized = true; ll_unlock(g_state.overlays); /* Do not seed ImGui's clock with absolute host uptime. ImGui stores the @@ -1066,9 +1071,11 @@ void app_freeOverlays(void) struct Overlay * overlay; while(ll_shift(g_state.overlays, (void **)&overlay)) { - overlay->ops->free(overlay->udata); + if (l_overlaysInitialized) + overlay->ops->free(overlay->udata); free(overlay); } + l_overlaysInitialized = false; } void app_setOverlay(bool enable) diff --git a/client/src/main.c b/client/src/main.c index 6462d2f1..e24184c5 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -1078,13 +1078,6 @@ static int renderThread(void * unused) app_setState(APP_STATE_SHUTDOWN); - if (g_state.overlays) - { - app_freeOverlays(); - ll_free(g_state.overlays); - g_state.overlays = NULL; - } - lgTimerDestroy(tickTimer); lgTimerDestroy(fpsTimer); @@ -3505,6 +3498,9 @@ static void lg_shutdown(void) } LG_LOCK_FREE(l_cursorRepaint.lock); + // An evdev batch may call input handlers; join before input teardown + evdev_stop(); + if (g_state.transport.ops) { lgInput_dropTransport(); @@ -3540,6 +3536,7 @@ static void lg_shutdown(void) if (g_state.ds) g_state.ds->shutdown(); + lgClipboard_free(); app_releaseAllKeybinds(); @@ -3548,6 +3545,16 @@ static void lg_shutdown(void) if (g_state.ds && g_state.dsInitialized) g_state.ds->free(); + // Input callbacks have stopped; the evdev state and overlays can go + evdev_free(); + + if (g_state.overlays) + { + app_freeOverlays(); + ll_free(g_state.overlays); + g_state.overlays = NULL; + } + renderQueue_setSourceFns(NULL, NULL, NULL); renderQueue_free(); LG_LOCK_FREE(g_state.videoSourceLock); diff --git a/client/src/overlay_utils.c b/client/src/overlay_utils.c index 70d2e23c..f89658d5 100644 --- a/client/src/overlay_utils.c +++ b/client/src/overlay_utils.c @@ -182,5 +182,9 @@ void overlayFreeImage(OverlayImage * image) if (!image->tex) return; - RENDERER(freeTexture, image->tex); + // During shutdown the renderer is freed first, taking all textures with it + if (g_state.lgr) + RENDERER(freeTexture, image->tex); + + image->tex = NULL; }