diff --git a/lib/third_party/imgui/backend/include/imgui_impl_glfw.h b/lib/third_party/imgui/backend/include/imgui_impl_glfw.h index 532372790..c3dcfa79a 100644 --- a/lib/third_party/imgui/backend/include/imgui_impl_glfw.h +++ b/lib/third_party/imgui/backend/include/imgui_impl_glfw.h @@ -1,20 +1,20 @@ // dear imgui: Platform Backend for GLFW // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..) // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) -// (Requires: GLFW 3.1+. Prefer GLFW 3.3+ for full feature support.) +// (Requires: GLFW 3.0+. Prefer GLFW 3.3+/3.4+ for full feature support.) // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only). // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors) with GLFW 3.1+. Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // [X] Multiple Dear ImGui contexts support. // Missing features or Issues: -// [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. -// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. -// [ ] Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor). +// [ ] Platform: Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. +// [ ] Platform: Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. +// [ ] Platform: Multi-viewport: Missing ImGuiBackendFlags_HasParentViewport support. The viewport->ParentViewportID field is ignored, and therefore io.ConfigViewportsNoDefaultParent has no effect either. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -50,7 +50,7 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_InstallEmscriptenCallbacks(GLFWwindow* wi IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window); IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window); -// GFLW callbacks options: +// GLFW callbacks options: // - Set 'chain_for_all_windows=true' to enable chaining callbacks for all windows (including secondary viewports created by backends or by user) IMGUI_IMPL_API void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows); diff --git a/lib/third_party/imgui/backend/source/imgui_impl_glfw.cpp b/lib/third_party/imgui/backend/source/imgui_impl_glfw.cpp index 58bf2bd32..8daf0100f 100644 --- a/lib/third_party/imgui/backend/source/imgui_impl_glfw.cpp +++ b/lib/third_party/imgui/backend/source/imgui_impl_glfw.cpp @@ -1,20 +1,20 @@ // dear imgui: Platform Backend for GLFW // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..) // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) -// (Requires: GLFW 3.1+. Prefer GLFW 3.3+ or GLFW 3.4+ for full feature support.) +// (Requires: GLFW 3.0+. Prefer GLFW 3.3+/3.4+ for full feature support.) // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only). // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors) with GLFW 3.1+. Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // [X] Multiple Dear ImGui contexts support. // Missing features or Issues: -// [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. -// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. -// [ ] Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor). +// [ ] Platform: Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. +// [ ] Platform: Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. +// [ ] Platform: Multi-viewport: Missing ImGuiBackendFlags_HasParentViewport support. The viewport->ParentViewportID field is ignored, and therefore io.ConfigViewportsNoDefaultParent has no effect either. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -31,7 +31,14 @@ // 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-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2026-02-10: Try to set IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND automatically if corresponding headers are not accessible. (#9225) +// 2026-01-25: [Docking] Improve workarounds for cases where GLFW is unable to provide any reliable monitor info. Preserve existing monitor list when none of the new one is valid. (#9195, #7902, #5683) +// 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. +// 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. // 2025-09-15: Content Scales are always reported as 1.0 on Wayland. FramebufferScale are always reported as 1.0 on X11. (#8920, #8921) // 2025-09-10: [Docking] Improve multi-viewport behavior in tiling WMs on X11 via the ImGui_ImplGlfw_SetWindowFloating() function. Note: using GLFW backend on Linux/BSD etc. requires linking with -lX11. (#8884, #8474, #8289) // 2025-07-08: Made ImGui_ImplGlfw_GetContentScaleForWindow(), ImGui_ImplGlfw_GetContentScaleForMonitor() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) @@ -108,13 +115,34 @@ // Clang warnings with -Weverything #if defined(__clang__) #pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast -#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. +#pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is. #elif defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe +#endif + +#if defined(__has_include) +#if !__has_include() || !__has_include() +#define IMGUI_IMPL_GLFW_DISABLE_X11 +#endif +#if !__has_include() +#define IMGUI_IMPL_GLFW_DISABLE_WAYLAND +#endif #endif // GLFW +#if !defined(IMGUI_IMPL_GLFW_DISABLE_X11) && (defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)) +#define GLFW_HAS_X11 1 +#else +#define GLFW_HAS_X11 0 +#endif +#if !defined(IMGUI_IMPL_GLFW_DISABLE_WAYLAND) && (defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)) +#define GLFW_HAS_WAYLAND 1 +#else +#define GLFW_HAS_WAYLAND 0 +#endif #include #ifdef _WIN32 #undef APIENTRY @@ -122,20 +150,19 @@ #define GLFW_EXPOSE_NATIVE_WIN32 #endif #include +#elif defined(__APPLE__) +#ifndef GLFW_EXPOSE_NATIVE_COCOA // for glfwGetCocoaWindow() +#define GLFW_EXPOSE_NATIVE_COCOA #endif -// IMHEX PATCH BEGIN -// REASON: including this file means either including either ObjC (not supported by gcc) -// or code with a non-standard C++ extension (Blocks) -// Furthermore, we can't compile this file/ImGui with clang++ because the C++ ABI is not the same with clang and gcc -//#ifdef __APPLE__ -//#define GLFW_EXPOSE_NATIVE_COCOA -//#include // for glfwGetCocoaWindow() -// #endif -// IMHEX PATCH END - -#if !defined(__EMSCRIPTEN__) - #include - #undef Status // X11 headers are leaking this. +#include +#elif GLFW_HAS_X11 +#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. #endif #ifndef _WIN32 @@ -166,6 +193,7 @@ static std::string clipboardContent; // We gather version tests as define in order to easily see which features are version-dependent. #define GLFW_VERSION_COMBINED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION) +#define GLFW_HAS_CREATECURSOR (GLFW_VERSION_COMBINED >= 3100) // 3.1+ glfwCreateCursor() #define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_COMBINED >= 3200) // 3.2+ GLFW_FLOATING #define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_COMBINED >= 3300) // 3.3+ GLFW_HOVERED #define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwSetWindowOpacity @@ -193,11 +221,6 @@ static std::string clipboardContent; #define GLFW_HAS_GETKEYNAME (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwGetKeyName() #define GLFW_HAS_GETERROR (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetError() #define GLFW_HAS_GETPLATFORM (GLFW_VERSION_COMBINED >= 3400) // 3.4+ glfwGetPlatform() -#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) -#define GLFW_HAS_X11_OR_WAYLAND 1 -#else -#define GLFW_HAS_X11_OR_WAYLAND 0 -#endif // Map GLFWWindow* to ImGuiContext*. // - Would be simpler if we could use glfwSetWindowUserPointer()/glfwGetWindowUserPointer(), but this is a single and shared resource. @@ -206,7 +229,7 @@ static std::string clipboardContent; struct ImGui_ImplGlfw_WindowToContext { GLFWwindow* Window; ImGuiContext* Context; }; static ImVector g_ContextMap; static void ImGui_ImplGlfw_ContextMap_Add(GLFWwindow* window, ImGuiContext* ctx) { g_ContextMap.push_back(ImGui_ImplGlfw_WindowToContext{ window, ctx }); } -static void ImGui_ImplGlfw_ContextMap_Remove(GLFWwindow* window) { for (ImGui_ImplGlfw_WindowToContext& entry : g_ContextMap) if (entry.Window == window) { g_ContextMap.erase_unsorted(&entry); return; } } +static void ImGui_ImplGlfw_ContextMap_Remove(GLFWwindow* window) { for (ImGui_ImplGlfw_WindowToContext& entry : g_ContextMap) if (entry.Window == window) { g_ContextMap.erase_unsorted(&entry); if (g_ContextMap.empty()) g_ContextMap.clear(); return; } } static ImGuiContext* ImGui_ImplGlfw_ContextMap_Get(GLFWwindow* window) { for (ImGui_ImplGlfw_WindowToContext& entry : g_ContextMap) if (entry.Window == window) return entry.Context; return nullptr; } enum GlfwClientApi @@ -216,6 +239,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 { @@ -224,7 +254,10 @@ struct ImGui_ImplGlfw_Data GlfwClientApi ClientApi; double Time; GLFWwindow* MouseWindow; +#if GLFW_HAS_CREATECURSOR GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT]; + GLFWcursor* LastMouseCursor; +#endif bool MouseIgnoreButtonUpWaitForFocusLoss; bool MouseIgnoreButtonUp; ImVec2 LastValidMousePos; @@ -250,6 +283,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)); } }; @@ -279,47 +321,24 @@ static void ImGui_ImplGlfw_InitMultiViewportSupport(); static void ImGui_ImplGlfw_ShutdownMultiViewportSupport(); // Functions - static bool ImGui_ImplGlfw_IsWayland() { -#if !GLFW_HAS_X11_OR_WAYLAND +#if !GLFW_HAS_WAYLAND return false; #elif GLFW_HAS_GETPLATFORM return glfwGetPlatform() == GLFW_PLATFORM_WAYLAND; #else const char* version = glfwGetVersionString(); - if (strstr(version, "Wayland") == NULL) // e.g. Ubuntu 22.04 ships with GLFW 3.3.6 compiled without Wayland + if (strstr(version, "Wayland") == nullptr) // e.g. Ubuntu 22.04 ships with GLFW 3.3.6 compiled without Wayland return false; #ifdef GLFW_EXPOSE_NATIVE_X11 - if (glfwGetX11Display() != NULL) + if (glfwGetX11Display() != nullptr) return false; #endif return true; #endif } -static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) -{ -// IMHEX PATCH BEGIN -#ifdef __EMSCRIPTEN__ - return clipboardContent.c_str(); -#else - return glfwGetClipboardString((GLFWwindow*)user_data); -#endif -// IMHEX PATCH END -} - -static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text) -{ - glfwSetClipboardString((GLFWwindow*)user_data, text); - // IMHEX PATCH BEGIN -#ifdef __EMSCRIPTEN__ - clipboardContent = text; - emscripten_browser_clipboard::copy(clipboardContent); -#endif - // IMHEX PATCH END -} - // Not static to allow third-party code to use that if they want to (but undocumented) ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode); ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode) @@ -465,10 +484,10 @@ static void ImGui_ImplGlfw_UpdateKeyModifiers(ImGuiIO& io, GLFWwindow* window, i }(); if (isX11) { - io.AddKeyEvent(ImGuiMod_Ctrl, (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS)); - io.AddKeyEvent(ImGuiMod_Shift, (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS)); - io.AddKeyEvent(ImGuiMod_Alt, (glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS)); - io.AddKeyEvent(ImGuiMod_Super, (glfwGetKey(window, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS)); + io.AddKeyEvent(ImGuiMod_Ctrl, (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS)); + io.AddKeyEvent(ImGuiMod_Shift, (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS)); + io.AddKeyEvent(ImGuiMod_Alt, (glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS)); + io.AddKeyEvent(ImGuiMod_Super, (glfwGetKey(window, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS)); } else #endif { @@ -496,7 +515,9 @@ void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int acti return; ImGuiIO& io = ImGui::GetIO(bd->Context); + // IMHEX PATCH BEGIN ImGui_ImplGlfw_UpdateKeyModifiers(io, window, mods); + // IMHEX PATCH END if (button >= 0 && button < ImGuiMouseButton_COUNT) io.AddMouseButtonEvent(button, action == GLFW_PRESS); } @@ -537,7 +558,7 @@ static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode) { const char char_names[] = "`-=[]\\,;\'./"; const int char_keys[] = { GLFW_KEY_GRAVE_ACCENT, GLFW_KEY_MINUS, GLFW_KEY_EQUAL, GLFW_KEY_LEFT_BRACKET, GLFW_KEY_RIGHT_BRACKET, GLFW_KEY_BACKSLASH, GLFW_KEY_COMMA, GLFW_KEY_SEMICOLON, GLFW_KEY_APOSTROPHE, GLFW_KEY_PERIOD, GLFW_KEY_SLASH, 0 }; - IM_ASSERT(IM_ARRAYSIZE(char_names) == IM_ARRAYSIZE(char_keys)); + IM_ASSERT(IM_COUNTOF(char_names) == IM_COUNTOF(char_keys)); if (key_name[0] >= '0' && key_name[0] <= '9') { key = GLFW_KEY_0 + (key_name[0] - '0'); } else if (key_name[0] >= 'A' && key_name[0] <= 'Z') { key = GLFW_KEY_A + (key_name[0] - 'A'); } else if (key_name[0] >= 'a' && key_name[0] <= 'z') { key = GLFW_KEY_A + (key_name[0] - 'a'); } @@ -560,9 +581,11 @@ void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, i return; ImGuiIO& io = ImGui::GetIO(bd->Context); + // IMHEX PATCH BEGIN ImGui_ImplGlfw_UpdateKeyModifiers(io, window, mods); + // IMHEX PATCH END - if (keycode >= 0 && keycode < IM_ARRAYSIZE(bd->KeyOwnerWindows)) + if (keycode >= 0 && keycode < IM_COUNTOF(bd->KeyOwnerWindows)) bd->KeyOwnerWindows[keycode] = (action == GLFW_PRESS) ? window : nullptr; keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode); @@ -736,7 +759,9 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_glfw (%d)", GLFW_VERSION_COMBINED); io.BackendPlatformUserData = (void*)bd; io.BackendPlatformName = bd->BackendPlatformName; +#if GLFW_HAS_CREATECURSOR io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) +#endif io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) bool has_viewports = false; @@ -759,9 +784,6 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw bd->IsWayland = ImGui_ImplGlfw_IsWayland(); ImGui_ImplGlfw_ContextMap_Add(window, bd->Context); - if (bd->IsWayland) - io.ConfigDpiScaleFonts = true; - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); #if GLFW_VERSION_COMBINED < 3300 platform_io.Platform_SetClipboardTextFn = [](ImGuiContext*, const char* text) { glfwSetClipboardString(ImGui_ImplGlfw_GetBackendData()->Window, text); }; @@ -788,6 +810,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist, // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting. // Missing cursors will return nullptr and our _UpdateMouseCursor() function will use the Arrow cursor instead.) +#if GLFW_HAS_CREATECURSOR GLFWerrorfun prev_error_callback = glfwSetErrorCallback(nullptr); bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); @@ -806,6 +829,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); #endif glfwSetErrorCallback(prev_error_callback); +#endif #if GLFW_HAS_GETERROR && !defined(__EMSCRIPTEN__) // Eat errors (see #5908) (void)glfwGetError(nullptr); #endif @@ -824,11 +848,8 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw main_viewport->PlatformHandle = (void*)bd->Window; #ifdef _WIN32 main_viewport->PlatformHandleRaw = glfwGetWin32Window(bd->Window); -// IMHEX PATCH BEGIN -// REASON: The patch with #include -// #elif defined(__APPLE__) -// main_viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(bd->Window); -// IMHEX PATCH END +#elif defined(__APPLE__) + main_viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(bd->Window); #else IM_UNUSED(main_viewport); #endif @@ -844,6 +865,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__ @@ -884,20 +925,21 @@ void ImGui_ImplGlfw_Shutdown() { ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplGlfw_ShutdownMultiViewportSupport(); - if (bd->InstalledCallbacks) ImGui_ImplGlfw_RestoreCallbacks(bd->Window); #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 if (bd->CanvasSelector) emscripten_set_wheel_callback(bd->CanvasSelector, nullptr, false, nullptr); #endif - +#if GLFW_HAS_CREATECURSOR for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) glfwDestroyCursor(bd->MouseCursors[cursor_n]); - +#endif // Windows: restore our WndProc hook #ifdef _WIN32 ImGuiViewport* main_viewport = ImGui::GetMainViewport(); @@ -906,9 +948,15 @@ 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); + platform_io.ClearPlatformHandlers(); ImGui_ImplGlfw_ContextMap_Remove(bd->Window); IM_DELETE(bd); } @@ -998,20 +1046,28 @@ static void ImGui_ImplGlfw_UpdateMouseCursor() GLFWwindow* window = (GLFWwindow*)platform_io.Viewports[n]->PlatformHandle; if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) { - // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + if (bd->LastMouseCursor != nullptr) + { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + bd->LastMouseCursor = nullptr; + } } else { // Show OS mouse cursor // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here. - // IMHEX PATCH BEGIN - #if !defined(_WIN32) - glfwSetCursor(window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]); - #endif - +// IMHEX PATCH BEGIN +#if GLFW_HAS_CREATECURSOR && !defined(_WIN32) +// IMHEX PATCH END + GLFWcursor* cursor = bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]; + if (bd->LastMouseCursor != cursor) + { + glfwSetCursor(window, cursor); + bd->LastMouseCursor = cursor; + } +#endif glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - // IMHEX PATCH END } } } @@ -1072,13 +1128,10 @@ static void ImGui_ImplGlfw_UpdateGamepads() static void ImGui_ImplGlfw_UpdateMonitors() { ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - int monitors_count = 0; GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count); - if (monitors_count == 0) // Preserve existing monitor list if there are none. Happens on macOS sleeping (#5683) - return; - platform_io.Monitors.resize(0); + bool updated_monitors = false; for (int n = 0; n < monitors_count; n++) { ImGuiPlatformMonitor monitor; @@ -1087,6 +1140,8 @@ static void ImGui_ImplGlfw_UpdateMonitors() const GLFWvidmode* vid_mode = glfwGetVideoMode(glfw_monitors[n]); if (vid_mode == nullptr) continue; // Failed to get Video mode (e.g. Emscripten does not support this function) + if (vid_mode->width <= 0 || vid_mode->height <= 0) + continue; // Failed to query suitable monitor info (#9195) monitor.MainPos = monitor.WorkPos = ImVec2((float)x, (float)y); monitor.MainSize = monitor.WorkSize = ImVec2((float)vid_mode->width, (float)vid_mode->height); #if GLFW_HAS_MONITOR_WORK_AREA @@ -1100,9 +1155,15 @@ static void ImGui_ImplGlfw_UpdateMonitors() #endif float scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfw_monitors[n]); if (scale == 0.0f) - continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902. + continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0 (#7902) monitor.DpiScale = scale; monitor.PlatformHandle = (void*)glfw_monitors[n]; // [...] GLFW doc states: "guaranteed to be valid only until the monitor configuration changes" + + // Preserve existing monitor list until a valid one is added. + // Happens on macOS sleeping (#5683) and seemingly occasionally on Windows (#9195) + if (!updated_monitors) + platform_io.Monitors.resize(0); + updated_monitors = true; platform_io.Monitors.push_back(monitor); } } @@ -1112,7 +1173,7 @@ static void ImGui_ImplGlfw_UpdateMonitors() // - Some accessibility applications are declaring virtual monitors with a DPI of 0.0f, see #7902. We preserve this value for caller to handle. float ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) { -#if GLFW_HAS_X11_OR_WAYLAND +#if GLFW_HAS_WAYLAND if (ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window)) if (bd->IsWayland) return 1.0f; @@ -1129,7 +1190,7 @@ float ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) float ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) { -#if GLFW_HAS_X11_OR_WAYLAND +#if GLFW_HAS_WAYLAND if (ImGui_ImplGlfw_IsWayland()) // We can't access our bd->IsWayland cache for a monitor. return 1.0f; #endif @@ -1149,9 +1210,9 @@ static void ImGui_ImplGlfw_GetWindowSizeAndFramebufferScale(GLFWwindow* window, int display_w, display_h; glfwGetWindowSize(window, &w, &h); glfwGetFramebufferSize(window, &display_w, &display_h); - float fb_scale_x = (w > 0) ? (float)display_w / w : 1.0f; - float fb_scale_y = (h > 0) ? (float)display_h / h : 1.0f; -#if GLFW_HAS_X11_OR_WAYLAND + float fb_scale_x = (w > 0) ? (float)display_w / (float)w : 1.0f; + float fb_scale_y = (h > 0) ? (float)display_h / (float)h : 1.0f; +#if GLFW_HAS_WAYLAND ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); if (!bd->IsWayland) fb_scale_x = fb_scale_y = 1.0f; @@ -1204,8 +1265,7 @@ static EM_BOOL ImGui_ImplGlfw_OnCanvasSizeChange(int event_type, const Emscripte ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)user_data; double canvas_width, canvas_height; emscripten_get_element_css_size(bd->CanvasSelector, &canvas_width, &canvas_height); - double scale = emscripten_get_device_pixel_ratio(); - glfwSetWindowSize(bd->Window, (int)canvas_width * scale, (int)canvas_height * scale); + glfwSetWindowSize(bd->Window, (int)canvas_width, (int)canvas_height); return true; } @@ -1214,8 +1274,7 @@ static EM_BOOL ImGui_ImplEmscripten_FullscreenChangeCallback(int event_type, con ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)user_data; double canvas_width, canvas_height; emscripten_get_element_css_size(bd->CanvasSelector, &canvas_width, &canvas_height); - double scale = emscripten_get_device_pixel_ratio(); - glfwSetWindowSize(bd->Window, (int)canvas_width * scale, (int)canvas_height * scale); + glfwSetWindowSize(bd->Window, (int)canvas_width, (int)canvas_height); return true; } @@ -1318,20 +1377,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 @@ -1368,7 +1427,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); @@ -1413,7 +1472,7 @@ static void ImGui_ImplGlfw_DestroyWindow(ImGuiViewport* viewport) // Release any keys that were pressed in the window being destroyed and are still held down, // because we will not receive any release events after window is destroyed. - for (int i = 0; i < IM_ARRAYSIZE(bd->KeyOwnerWindows); i++) + for (int i = 0; i < IM_COUNTOF(bd->KeyOwnerWindows); i++) if (bd->KeyOwnerWindows[i] == vd->Window) ImGui_ImplGlfw_KeyCallback(vd->Window, i, 0, GLFW_RELEASE, 0); // Later params are only used for main viewport, on which this function is never called.