From 84a9d532b6f635a6017b90e65b627c36fd1afd20 Mon Sep 17 00:00:00 2001 From: Dario Mylonopoulos Date: Tue, 9 Dec 2025 18:13:59 +0100 Subject: [PATCH] Backends: GLFW: Load X11 functions dynamically to avoid x11 linking requirement. (#9116, #9109) Amend 6b2cdf2 (#8884, #8474, #8289) --- backends/imgui_impl_glfw.cpp | 57 ++++++++++++++++++--- docs/CHANGELOG.txt | 2 + examples/example_glfw_opengl2/Makefile | 2 +- examples/example_glfw_opengl3/Makefile | 2 +- examples/example_glfw_vulkan/CMakeLists.txt | 1 - examples/example_glfw_vulkan/Makefile | 2 +- 6 files changed, 55 insertions(+), 11 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index bb3e50593..81a8da463 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -32,6 +32,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) // 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2026-01-18: [Docking] Dynamically load X11 functions to avoid -lx11 linking requirement introduced on 2025-09-10. // 2025-12-12: Added IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND to forcefully disable either. // 2025-12-10: Avoid repeated glfwSetCursor()/glfwSetInputMode() calls when unnecessary. Lowers overhead for very high framerates (e.g. 10k+ FPS). // 2025-11-06: Lower minimum requirement to GLFW 3.0. Though a recent version e.g GLFW 3.4 is highly recommended. @@ -147,6 +148,7 @@ #ifndef GLFW_EXPOSE_NATIVE_X11 // for glfwGetX11Display(), glfwGetX11Window() on Freedesktop (Linux, BSD, etc.) #define GLFW_EXPOSE_NATIVE_X11 #include +#include // for dlopen() #endif #include #undef Status // X11 headers are leaking this. @@ -215,6 +217,13 @@ enum GlfwClientApi GlfwClientApi_Unknown, // Anything else fits here. }; +#if GLFW_HAS_X11 +typedef Atom (*PFN_XInternAtom)(Display*, const char* ,Bool); +typedef int (*PFN_XChangeProperty)(Display*, Window, Atom, Atom, int, int, const unsigned char*, int); +typedef int (*PFN_XChangeWindowAttributes)(Display*, Window, unsigned long, XSetWindowAttributes*); +typedef int (*PFN_XFlush)(Display*); +#endif + // GLFW data struct ImGui_ImplGlfw_Data { @@ -252,6 +261,15 @@ struct ImGui_ImplGlfw_Data WNDPROC PrevWndProc; #endif +#if GLFW_HAS_X11 + // Module and function pointers loaded at initialization to avoid linking statically with X11. + void* X11Module; + PFN_XInternAtom XInternAtom; + PFN_XChangeProperty XChangeProperty; + PFN_XChangeWindowAttributes XChangeWindowAttributes; + PFN_XFlush XFlush; +#endif + ImGui_ImplGlfw_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -792,6 +810,26 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc); #endif +#if GLFW_HAS_X11 + if (!bd->IsWayland) + { + // Load X11 module dynamically. Copied from the way that GLFW does it in x11_init.c +#if defined(__CYGWIN__) + const char* x11_module_path = "libX11-6.so"; +#elif defined(__OpenBSD__) || defined(__NetBSD__) + const char* x11_module_path = "libX11.so"; +#else + const char* x11_module_path = "libX11.so.6"; +#endif + bd->X11Module = dlopen(x11_module_path, RTLD_LAZY | RTLD_LOCAL); + bd->XInternAtom = (PFN_XInternAtom)dlsym(bd->X11Module, "XInternAtom"); + bd->XChangeProperty = (PFN_XChangeProperty)dlsym(bd->X11Module, "XChangeProperty"); + bd->XChangeWindowAttributes = (PFN_XChangeWindowAttributes)dlsym(bd->X11Module, "XChangeWindowAttributes"); + bd->XFlush = (PFN_XFlush)dlsym(bd->X11Module, "XFlush"); + IM_ASSERT(bd->XInternAtom != nullptr && bd->XChangeProperty != nullptr && bd->XChangeWindowAttributes != nullptr && bd->XFlush != nullptr); + } +#endif + // Emscripten: the same application can run on various platforms, so we detect the Apple platform at runtime // to override io.ConfigMacOSXBehaviors from its default (which is always false in Emscripten). #ifdef __EMSCRIPTEN__ @@ -855,6 +893,11 @@ void ImGui_ImplGlfw_Shutdown() bd->PrevWndProc = nullptr; #endif +#if GLFW_HAS_X11 + if (bd->X11Module != nullptr) + dlclose(bd->X11Module); +#endif + io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport); @@ -1272,20 +1315,20 @@ static void ImGui_ImplGlfw_WindowSizeCallback(GLFWwindow* window, int, int) #if !defined(__APPLE__) && !defined(_WIN32) && !defined(__EMSCRIPTEN__) && GLFW_HAS_GETPLATFORM #define IMGUI_GLFW_HAS_SETWINDOWFLOATING -static void ImGui_ImplGlfw_SetWindowFloating(GLFWwindow* window) +static void ImGui_ImplGlfw_SetWindowFloating(ImGui_ImplGlfw_Data* bd, GLFWwindow* window) { #ifdef GLFW_EXPOSE_NATIVE_X11 if (glfwGetPlatform() == GLFW_PLATFORM_X11) { Display* display = glfwGetX11Display(); Window xwindow = glfwGetX11Window(window); - Atom wm_type = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); - Atom wm_type_dialog = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False); - XChangeProperty(display, xwindow, wm_type, XA_ATOM, 32, PropModeReplace, (unsigned char*)&wm_type_dialog, 1); + Atom wm_type = bd->XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); + Atom wm_type_dialog = bd->XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False); + bd->XChangeProperty(display, xwindow, wm_type, XA_ATOM, 32, PropModeReplace, (unsigned char*)&wm_type_dialog, 1); XSetWindowAttributes attrs; attrs.override_redirect = False; - XChangeWindowAttributes(display, xwindow, CWOverrideRedirect, &attrs); - XFlush(display); + bd->XChangeWindowAttributes(display, xwindow, CWOverrideRedirect, &attrs); + bd->XFlush(display); } #endif // GLFW_EXPOSE_NATIVE_X11 #ifdef GLFW_EXPOSE_NATIVE_WAYLAND @@ -1322,7 +1365,7 @@ static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport) ImGui_ImplGlfw_ContextMap_Add(vd->Window, bd->Context); viewport->PlatformHandle = (void*)vd->Window; #ifdef IMGUI_GLFW_HAS_SETWINDOWFLOATING - ImGui_ImplGlfw_SetWindowFloating(vd->Window); + ImGui_ImplGlfw_SetWindowFloating(bd, vd->Window); #endif #ifdef _WIN32 viewport->PlatformHandleRaw = glfwGetWin32Window(vd->Window); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index dd89c8302..e87040d32 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -185,6 +185,8 @@ Docking+Viewports Branch: gamepad/keyboard to move a window to another viewport. (#9053) [@lut0pia, @ocornut] - Fixed implicit/fallback "Debug" window from staying visible if once docked. (#9151) - Backends: + - GLFW: dynamically load X11 functions to avoid -lx11 linking requirement introduced + in 1.92.3. (#9116, #9109) [@ramenguy99] - SDL2, SDL3: adjust IME offset to match other backends and master branch. (#6071, #1953) - Win32: viewports created by backend forcefully direct messages to DefWindowProcW() in order to support Unicode text input. (#9099, #3653, #5961) [@ulhc] diff --git a/examples/example_glfw_opengl2/Makefile b/examples/example_glfw_opengl2/Makefile index ecfdec7b1..a8a0128dc 100644 --- a/examples/example_glfw_opengl2/Makefile +++ b/examples/example_glfw_opengl2/Makefile @@ -33,7 +33,7 @@ LIBS = ifeq ($(UNAME_S), Linux) #LINUX ECHO_MESSAGE = "Linux" - LIBS += $(LINUX_GL_LIBS) -lX11 `pkg-config --static --libs glfw3` + LIBS += $(LINUX_GL_LIBS) `pkg-config --static --libs glfw3` CXXFLAGS += `pkg-config --cflags glfw3` CFLAGS = $(CXXFLAGS) diff --git a/examples/example_glfw_opengl3/Makefile b/examples/example_glfw_opengl3/Makefile index 4c2dc523f..252ce5714 100644 --- a/examples/example_glfw_opengl3/Makefile +++ b/examples/example_glfw_opengl3/Makefile @@ -41,7 +41,7 @@ LIBS = ifeq ($(UNAME_S), Linux) #LINUX ECHO_MESSAGE = "Linux" - LIBS += $(LINUX_GL_LIBS) -lX11 `pkg-config --static --libs glfw3` + LIBS += $(LINUX_GL_LIBS) `pkg-config --static --libs glfw3` CXXFLAGS += `pkg-config --cflags glfw3` CFLAGS = $(CXXFLAGS) diff --git a/examples/example_glfw_vulkan/CMakeLists.txt b/examples/example_glfw_vulkan/CMakeLists.txt index fae580bfc..75475dbae 100644 --- a/examples/example_glfw_vulkan/CMakeLists.txt +++ b/examples/example_glfw_vulkan/CMakeLists.txt @@ -36,7 +36,6 @@ find_package(Vulkan REQUIRED) #NAMES vulkan vulkan-1) #set(LIBRARIES "glfw;${VULKAN_LIBRARY}") set(LIBRARIES "glfw;Vulkan::Vulkan") -# FIXME: Linux needs linking with "X11" as well? # Use vulkan headers from glfw: include_directories(${GLFW_DIR}/deps) diff --git a/examples/example_glfw_vulkan/Makefile b/examples/example_glfw_vulkan/Makefile index f2a9ab518..1a84082d1 100644 --- a/examples/example_glfw_vulkan/Makefile +++ b/examples/example_glfw_vulkan/Makefile @@ -33,7 +33,7 @@ LIBS = ifeq ($(UNAME_S), Linux) #LINUX ECHO_MESSAGE = "Linux" - LIBS += $(LINUX_GL_LIBS) -lX11 `pkg-config --static --libs glfw3 vulkan` + LIBS += $(LINUX_GL_LIBS) `pkg-config --static --libs glfw3 vulkan` CXXFLAGS += `pkg-config --cflags glfw3 vulkan` CFLAGS = $(CXXFLAGS)