diff --git a/pkg/dcimgui/ext.cpp b/pkg/dcimgui/ext.cpp index d4732e0fa..a502c438e 100644 --- a/pkg/dcimgui/ext.cpp +++ b/pkg/dcimgui/ext.cpp @@ -27,4 +27,25 @@ CIMGUI_API void ImGuiStyle_ImGuiStyle(cimgui::ImGuiStyle* self) ::ImGuiStyle defaults; *reinterpret_cast<::ImGuiStyle*>(self) = defaults; } + +// Perform the OpenGL3 backend shutdown and then zero out the imgl3w +// function pointer table. ImGui_ImplOpenGL3_Shutdown() calls +// imgl3wShutdown() which dlcloses the GL library handles but does not +// zero out the function pointers. A subsequent ImGui_ImplOpenGL3_Init() +// sees the stale (non-null) pointers, skips loader re-initialization, +// and crashes when calling through them. Zeroing the table forces the +// next Init to reload the GL function pointers via imgl3wInit(). +#ifndef IMGUI_DISABLE +#if __has_include("backends/imgui_impl_opengl3.h") +#include "backends/imgui_impl_opengl3.h" +#include "backends/imgui_impl_opengl3_loader.h" + +CIMGUI_API void ImGui_ImplOpenGL3_ShutdownWithLoaderCleanup() +{ + ::ImGui_ImplOpenGL3_Shutdown(); + memset(&imgl3wProcs, 0, sizeof(imgl3wProcs)); +} +#endif +#endif + } diff --git a/pkg/dcimgui/main.zig b/pkg/dcimgui/main.zig index 59bfca4f2..40a4325c0 100644 --- a/pkg/dcimgui/main.zig +++ b/pkg/dcimgui/main.zig @@ -16,6 +16,10 @@ pub extern fn ImGui_ImplOpenGL3_Shutdown() callconv(.c) void; pub extern fn ImGui_ImplOpenGL3_NewFrame() callconv(.c) void; pub extern fn ImGui_ImplOpenGL3_RenderDrawData(draw_data: *c.ImDrawData) callconv(.c) void; +// Extension: shutdown the OpenGL3 backend and zero out the imgl3w function +// pointer table so a subsequent Init can re-initialize the loader. +pub extern fn ImGui_ImplOpenGL3_ShutdownWithLoaderCleanup() callconv(.c) void; + // Metal backend pub extern fn ImGui_ImplMetal_Init(device: *anyopaque) callconv(.c) bool; pub extern fn ImGui_ImplMetal_Shutdown() callconv(.c) void; diff --git a/src/apprt/gtk/class/imgui_widget.zig b/src/apprt/gtk/class/imgui_widget.zig index 01b3f3e5c..0ef753a87 100644 --- a/src/apprt/gtk/class/imgui_widget.zig +++ b/src/apprt/gtk/class/imgui_widget.zig @@ -257,8 +257,18 @@ pub const ImguiWidget = extern struct { priv.tick_callback_id = 0; } + // Unrealize is not guaranteed to be called with a current GL context, + // so we make it current for ImGui cleanup. + priv.gl_area.makeCurrent(); + if (priv.gl_area.getError()) |err| { + log.warn("GLArea for Dear ImGui widget failed to realize: {s}", .{err.f_message orelse "(unknown)"}); + return; + } + self.setCurrentContext() catch return; - cimgui.ImGui_ImplOpenGL3_Shutdown(); + cimgui.ImGui_ImplOpenGL3_ShutdownWithLoaderCleanup(); + cimgui.c.ImGui_DestroyContext(priv.ig_context); + priv.ig_context = null; } /// Handle a request to resize the GLArea