diff options
| author | bitflash-coin <bookofshamers@outlook.com> | 2026-08-04 06:34:32 -0700 |
|---|---|---|
| committer | bitflash-coin <bookofshamers@outlook.com> | 2026-08-04 06:34:32 -0700 |
| commit | 5ce650382352c1503f40abf08129ada69402af55 (patch) | |
| tree | 6a18198901f1e2c4933f1ac53c9365eec512bf63 /src/imgui/imgui_impl_glfw.cpp | |
| parent | f34113291da7e5e3dc7d2468d4f9c212c05c584b (diff) | |
public commit
Diffstat (limited to 'src/imgui/imgui_impl_glfw.cpp')
| -rw-r--r-- | src/imgui/imgui_impl_glfw.cpp | 1109 |
1 files changed, 1109 insertions, 0 deletions
diff --git a/src/imgui/imgui_impl_glfw.cpp b/src/imgui/imgui_impl_glfw.cpp new file mode 100644 index 0000000..678129a --- /dev/null +++ b/src/imgui/imgui_impl_glfw.cpp | |||
| @@ -0,0 +1,1109 @@ | |||
| 1 | // dear imgui: Platform Backend for GLFW | ||
| 2 | // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..) | ||
| 3 | // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) | ||
| 4 | // (Requires: GLFW 3.0+. Prefer GLFW 3.3+/3.4+ for full feature support.) | ||
| 5 | |||
| 6 | // Implemented features: | ||
| 7 | // [X] Platform: Clipboard support. | ||
| 8 | // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only). | ||
| 9 | // [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] | ||
| 10 | // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. | ||
| 11 | // [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'. | ||
| 12 | // [X] Multiple Dear ImGui contexts support. | ||
| 13 | // Missing features or Issues: | ||
| 14 | // [ ] 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. | ||
| 15 | // [ ] Platform: Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. | ||
| 16 | |||
| 17 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. | ||
| 18 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. | ||
| 19 | // Learn about Dear ImGui: | ||
| 20 | // - FAQ https://dearimgui.com/faq | ||
| 21 | // - Getting Started https://dearimgui.com/getting-started | ||
| 22 | // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). | ||
| 23 | // - Introduction, links and more at the top of imgui.cpp | ||
| 24 | |||
| 25 | // About Emscripten support: | ||
| 26 | // - Emscripten provides its own GLFW (3.2.1) implementation (syntax: "-sUSE_GLFW=3"), but Joystick is broken and several features are not supported (multiple windows, clipboard, timer, etc.) | ||
| 27 | // - A third-party Emscripten GLFW (3.4.0) implementation (syntax: "--use-port=contrib.glfw3") fixes the Joystick issue and implements all relevant features for the browser. | ||
| 28 | // See https://github.com/pongasoft/emscripten-glfw/blob/master/docs/Comparison.md for details. | ||
| 29 | |||
| 30 | // CHANGELOG | ||
| 31 | // (minor and older changes stripped away, please see git history for details) | ||
| 32 | // 2026-04-21: Added a Win32-specific implementation of ImGui_ImplGlfw_GetContentScaleXXXX functions for legacy GLFW 3.2. | ||
| 33 | // 2026-03-25: Mouse cursor is properly restored if changed by user app/code while using glfwSetInputMode(..., GLFW_CURSOR_DISABLED) or ImGuiConfigFlags_NoMouseCursorChange. Amend change from 2025-12-10. | ||
| 34 | // 2026-02-10: Try to set IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND automatically if corresponding headers are not accessible. (#9225) | ||
| 35 | // 2025-12-12: Added IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND to forcefully disable either. | ||
| 36 | // 2025-12-10: Avoid repeated glfwSetCursor()/glfwSetInputMode() calls when unnecessary. Lowers overhead for very high framerates (e.g. 10k+ FPS). | ||
| 37 | // 2025-11-06: Lower minimum requirement to GLFW 3.0. Though a recent version e.g GLFW 3.4 is highly recommended. | ||
| 38 | // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. | ||
| 39 | // 2025-09-15: Content Scales are always reported as 1.0 on Wayland. FramebufferScale are always reported as 1.0 on X11. (#8920, #8921) | ||
| 40 | // 2025-07-08: Made ImGui_ImplGlfw_GetContentScaleForWindow(), ImGui_ImplGlfw_GetContentScaleForMonitor() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) | ||
| 41 | // 2025-06-18: Added support for multiple Dear ImGui contexts. (#8676, #8239, #8069) | ||
| 42 | // 2025-06-11: Added ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) and ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) helper to facilitate making DPI-aware apps. | ||
| 43 | // 2025-03-10: Map GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 into ImGuiKey_Oem102. | ||
| 44 | // 2025-03-03: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled. | ||
| 45 | // 2024-08-22: Moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: | ||
| 46 | // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn | ||
| 47 | // - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn | ||
| 48 | // - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn | ||
| 49 | // 2024-07-31: Added ImGui_ImplGlfw_Sleep() helper function for usage by our examples app, since GLFW doesn't provide one. | ||
| 50 | // 2024-07-08: *BREAKING* Renamed ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback to ImGui_ImplGlfw_InstallEmscriptenCallbacks(), added GLFWWindow* parameter. | ||
| 51 | // 2024-07-08: Emscripten: Added support for GLFW3 contrib port (GLFW 3.4.0 features + bug fixes): to enable, replace -sUSE_GLFW=3 with --use-port=contrib.glfw3 (requires emscripten 3.1.59+) (https://github.com/pongasoft/emscripten-glfw) | ||
| 52 | // 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions. | ||
| 53 | // 2023-12-19: Emscripten: Added ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback() to register canvas selector and auto-resize GLFW window. | ||
| 54 | // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys. | ||
| 55 | // 2023-07-18: Inputs: Revert ignoring mouse data on GLFW_CURSOR_DISABLED as it can be used differently. User may set ImGuiConfigFLags_NoMouse if desired. (#5625, #6609) | ||
| 56 | // 2023-06-12: Accept glfwGetTime() not returning a monotonically increasing value. This seems to happens on some Windows setup when peripherals disconnect, and is likely to also happen on browser + Emscripten. (#6491) | ||
| 57 | // 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen/ImGuiMouseSource_Pen on Windows ONLY, using a custom WndProc hook. (#2702) | ||
| 58 | // 2023-03-16: Inputs: Fixed key modifiers handling on secondary viewports (docking branch). Broken on 2023/01/04. (#6248, #6034) | ||
| 59 | // 2023-03-14: Emscripten: Avoid using glfwGetError() and glfwGetGamepadState() which are not correctly implemented in Emscripten emulation. (#6240) | ||
| 60 | // 2023-02-03: Emscripten: Registering custom low-level mouse wheel handler to get more accurate scrolling impulses on Emscripten. (#4019, #6096) | ||
| 61 | // 2023-01-04: Inputs: Fixed mods state on Linux when using Alt-GR text input (e.g. German keyboard layout), could lead to broken text input. Revert a 2022/01/17 change were we resumed using mods provided by GLFW, turns out they were faulty. | ||
| 62 | // 2022-11-22: Perform a dummy glfwGetError() read to cancel missing names with glfwGetKeyName(). (#5908) | ||
| 63 | // 2022-10-18: Perform a dummy glfwGetError() read to cancel missing mouse cursors errors. Using GLFW_VERSION_COMBINED directly. (#5785) | ||
| 64 | // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. | ||
| 65 | // 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported). | ||
| 66 | // 2022-09-01: Inputs: Honor GLFW_CURSOR_DISABLED by not setting mouse position *EDIT* Reverted 2023-07-18. | ||
| 67 | // 2022-04-30: Inputs: Fixed ImGui_ImplGlfw_TranslateUntranslatedKey() for lower case letters on OSX. | ||
| 68 | // 2022-03-23: Inputs: Fixed a regression in 1.87 which resulted in keyboard modifiers events being reported incorrectly on Linux/X11. | ||
| 69 | // 2022-02-07: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing callbacks after initializing backend. | ||
| 70 | // 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion. | ||
| 71 | // 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[]. | ||
| 72 | // 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+). | ||
| 73 | // 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates. | ||
| 74 | // 2022-01-12: *BREAKING CHANGE*: Now using glfwSetCursorPosCallback(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetCursorPosCallback() and forward it to the backend via ImGui_ImplGlfw_CursorPosCallback(). | ||
| 75 | // 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. | ||
| 76 | // 2022-01-05: Inputs: Converting GLFW untranslated keycodes back to translated keycodes (in the ImGui_ImplGlfw_KeyCallback() function) in order to match the behavior of every other backend, and facilitate the use of GLFW with lettered-shortcuts API. | ||
| 77 | // 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback(). | ||
| 78 | // 2021-07-29: *BREAKING CHANGE*: Now using glfwSetCursorEnterCallback(). MousePos is correctly reported when the host platform window is hovered but not focused. If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() callback and forward it to the backend via ImGui_ImplGlfw_CursorEnterCallback(). | ||
| 79 | // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). | ||
| 80 | // 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors. | ||
| 81 | // 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor). | ||
| 82 | // 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown. | ||
| 83 | // 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter. | ||
| 84 | // 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter(). | ||
| 85 | // 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized. | ||
| 86 | // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. | ||
| 87 | // 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them. | ||
| 88 | // 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls. | ||
| 89 | // 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. | ||
| 90 | // 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples. | ||
| 91 | // 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag. | ||
| 92 | // 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()). | ||
| 93 | // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. | ||
| 94 | // 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. | ||
| 95 | // 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set. | ||
| 96 | // 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set). | ||
| 97 | // 2018-01-20: Inputs: Added Horizontal Mouse Wheel support. | ||
| 98 | // 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert. | ||
| 99 | // 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1). | ||
| 100 | // 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers. | ||
| 101 | |||
| 102 | #include "imgui.h" | ||
| 103 | #ifndef IMGUI_DISABLE | ||
| 104 | #include "imgui_impl_glfw.h" | ||
| 105 | |||
| 106 | // Clang warnings with -Weverything | ||
| 107 | #if defined(__clang__) | ||
| 108 | #pragma clang diagnostic push | ||
| 109 | #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast | ||
| 110 | #pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness | ||
| 111 | #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. | ||
| 112 | #pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is. | ||
| 113 | #endif | ||
| 114 | |||
| 115 | #if defined(__has_include) | ||
| 116 | #if !__has_include(<X11/Xlib.h>) || !__has_include(<X11/extensions/Xrandr.h>) | ||
| 117 | #define IMGUI_IMPL_GLFW_DISABLE_X11 | ||
| 118 | #endif | ||
| 119 | #if !__has_include(<wayland-client.h>) | ||
| 120 | #define IMGUI_IMPL_GLFW_DISABLE_WAYLAND | ||
| 121 | #endif | ||
| 122 | #endif | ||
| 123 | |||
| 124 | // GLFW | ||
| 125 | #if !defined(IMGUI_IMPL_GLFW_DISABLE_X11) && (defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)) | ||
| 126 | #define GLFW_HAS_X11 1 | ||
| 127 | #else | ||
| 128 | #define GLFW_HAS_X11 0 | ||
| 129 | #endif | ||
| 130 | #if !defined(IMGUI_IMPL_GLFW_DISABLE_WAYLAND) && (defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)) | ||
| 131 | #define GLFW_HAS_WAYLAND 1 | ||
| 132 | #else | ||
| 133 | #define GLFW_HAS_WAYLAND 0 | ||
| 134 | #endif | ||
| 135 | #include <GLFW/glfw3.h> | ||
| 136 | #ifdef _WIN32 | ||
| 137 | #undef APIENTRY | ||
| 138 | #ifndef GLFW_EXPOSE_NATIVE_WIN32 // for glfwGetWin32Window() | ||
| 139 | #define GLFW_EXPOSE_NATIVE_WIN32 | ||
| 140 | #endif | ||
| 141 | #include <GLFW/glfw3native.h> | ||
| 142 | #elif defined(__APPLE__) | ||
| 143 | #ifndef GLFW_EXPOSE_NATIVE_COCOA // for glfwGetCocoaWindow() | ||
| 144 | #define GLFW_EXPOSE_NATIVE_COCOA | ||
| 145 | #endif | ||
| 146 | #include <GLFW/glfw3native.h> | ||
| 147 | #elif GLFW_HAS_X11 | ||
| 148 | #ifndef GLFW_EXPOSE_NATIVE_X11 // for glfwGetX11Display(), glfwGetX11Window() on Freedesktop (Linux, BSD, etc.) | ||
| 149 | #define GLFW_EXPOSE_NATIVE_X11 | ||
| 150 | #endif | ||
| 151 | #include <GLFW/glfw3native.h> | ||
| 152 | #endif | ||
| 153 | #undef Status // X11 headers are leaking this. | ||
| 154 | #ifndef _WIN32 | ||
| 155 | #include <unistd.h> // for usleep() | ||
| 156 | #endif | ||
| 157 | #include <stdio.h> // for snprintf() | ||
| 158 | |||
| 159 | #ifdef __EMSCRIPTEN__ | ||
| 160 | #include <emscripten.h> | ||
| 161 | #include <emscripten/html5.h> | ||
| 162 | #ifdef EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 | ||
| 163 | #include <GLFW/emscripten_glfw3.h> | ||
| 164 | #else | ||
| 165 | #define EMSCRIPTEN_USE_EMBEDDED_GLFW3 | ||
| 166 | #endif | ||
| 167 | #endif | ||
| 168 | |||
| 169 | // We gather version tests as define in order to easily see which features are version-dependent. | ||
| 170 | #define GLFW_VERSION_COMBINED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION) | ||
| 171 | #define GLFW_HAS_CREATECURSOR (GLFW_VERSION_COMBINED >= 3100) // 3.1+ glfwCreateCursor() | ||
| 172 | #define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetMonitorContentScale | ||
| 173 | #ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released? | ||
| 174 | #define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR | ||
| 175 | #else | ||
| 176 | #define GLFW_HAS_NEW_CURSORS (0) | ||
| 177 | #endif | ||
| 178 | #define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetGamepadState() new api | ||
| 179 | #define GLFW_HAS_GETKEYNAME (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwGetKeyName() | ||
| 180 | #define GLFW_HAS_GETERROR (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetError() | ||
| 181 | #define GLFW_HAS_GETPLATFORM (GLFW_VERSION_COMBINED >= 3400) // 3.4+ glfwGetPlatform() | ||
| 182 | |||
| 183 | // Map GLFWWindow* to ImGuiContext*. | ||
| 184 | // - Would be simpler if we could use glfwSetWindowUserPointer()/glfwGetWindowUserPointer(), but this is a single and shared resource. | ||
| 185 | // - Would be simpler if we could use e.g. std::map<> as well. But we don't. | ||
| 186 | // - This is not particularly optimized as we expect size to be small and queries to be rare. | ||
| 187 | struct ImGui_ImplGlfw_WindowToContext { GLFWwindow* Window; ImGuiContext* Context; }; | ||
| 188 | static ImVector<ImGui_ImplGlfw_WindowToContext> g_ContextMap; | ||
| 189 | static void ImGui_ImplGlfw_ContextMap_Add(GLFWwindow* window, ImGuiContext* ctx) { g_ContextMap.push_back(ImGui_ImplGlfw_WindowToContext{ window, ctx }); } | ||
| 190 | 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; } } | ||
| 191 | static ImGuiContext* ImGui_ImplGlfw_ContextMap_Get(GLFWwindow* window) { for (ImGui_ImplGlfw_WindowToContext& entry : g_ContextMap) if (entry.Window == window) return entry.Context; return nullptr; } | ||
| 192 | |||
| 193 | enum GlfwClientApi | ||
| 194 | { | ||
| 195 | GlfwClientApi_OpenGL, | ||
| 196 | GlfwClientApi_Vulkan, | ||
| 197 | GlfwClientApi_Unknown, // Anything else fits here. | ||
| 198 | }; | ||
| 199 | |||
| 200 | // GLFW data | ||
| 201 | struct ImGui_ImplGlfw_Data | ||
| 202 | { | ||
| 203 | ImGuiContext* Context; | ||
| 204 | GLFWwindow* Window; | ||
| 205 | GlfwClientApi ClientApi; | ||
| 206 | double Time; | ||
| 207 | GLFWwindow* MouseWindow; | ||
| 208 | #if GLFW_HAS_CREATECURSOR | ||
| 209 | GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT]; | ||
| 210 | GLFWcursor* LastMouseCursor; | ||
| 211 | #endif | ||
| 212 | ImVec2 LastValidMousePos; | ||
| 213 | bool IsWayland; | ||
| 214 | bool InstalledCallbacks; | ||
| 215 | bool CallbacksChainForAllWindows; | ||
| 216 | char BackendPlatformName[40]; | ||
| 217 | #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 | ||
| 218 | const char* CanvasSelector; | ||
| 219 | #endif | ||
| 220 | |||
| 221 | // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. | ||
| 222 | GLFWwindowfocusfun PrevUserCallbackWindowFocus; | ||
| 223 | GLFWcursorposfun PrevUserCallbackCursorPos; | ||
| 224 | GLFWcursorenterfun PrevUserCallbackCursorEnter; | ||
| 225 | GLFWmousebuttonfun PrevUserCallbackMousebutton; | ||
| 226 | GLFWscrollfun PrevUserCallbackScroll; | ||
| 227 | GLFWkeyfun PrevUserCallbackKey; | ||
| 228 | GLFWcharfun PrevUserCallbackChar; | ||
| 229 | GLFWmonitorfun PrevUserCallbackMonitor; | ||
| 230 | #ifdef _WIN32 | ||
| 231 | WNDPROC PrevWndProc; | ||
| 232 | #endif | ||
| 233 | |||
| 234 | ImGui_ImplGlfw_Data() { memset((void*)this, 0, sizeof(*this)); } | ||
| 235 | }; | ||
| 236 | |||
| 237 | // Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts | ||
| 238 | // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. | ||
| 239 | // FIXME: multi-context support is not well tested and probably dysfunctional in this backend. | ||
| 240 | // - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks | ||
| 241 | // (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks. | ||
| 242 | // - Otherwise we may need to store a GLFWWindow* -> ImGuiContext* map and handle this in the backend, adding a little bit of extra complexity to it. | ||
| 243 | // FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context. | ||
| 244 | namespace ImGui { extern ImGuiIO& GetIO(ImGuiContext*); } | ||
| 245 | static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData() | ||
| 246 | { | ||
| 247 | // Get data for current context | ||
| 248 | return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; | ||
| 249 | } | ||
| 250 | static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData(GLFWwindow* window) | ||
| 251 | { | ||
| 252 | // Get data for a given GLFW window, regardless of current context (since GLFW events are sent together) | ||
| 253 | ImGuiContext* ctx = ImGui_ImplGlfw_ContextMap_Get(window); | ||
| 254 | return (ImGui_ImplGlfw_Data*)ImGui::GetIO(ctx).BackendPlatformUserData; | ||
| 255 | } | ||
| 256 | |||
| 257 | // Functions | ||
| 258 | static bool ImGui_ImplGlfw_IsWayland() | ||
| 259 | { | ||
| 260 | #if !GLFW_HAS_WAYLAND | ||
| 261 | return false; | ||
| 262 | #elif GLFW_HAS_GETPLATFORM | ||
| 263 | return glfwGetPlatform() == GLFW_PLATFORM_WAYLAND; | ||
| 264 | #else | ||
| 265 | const char* version = glfwGetVersionString(); | ||
| 266 | if (strstr(version, "Wayland") == nullptr) // e.g. Ubuntu 22.04 ships with GLFW 3.3.6 compiled without Wayland | ||
| 267 | return false; | ||
| 268 | #ifdef GLFW_EXPOSE_NATIVE_X11 | ||
| 269 | if (glfwGetX11Display() != nullptr) | ||
| 270 | return false; | ||
| 271 | #endif | ||
| 272 | return true; | ||
| 273 | #endif | ||
| 274 | } | ||
| 275 | |||
| 276 | // Not static to allow third-party code to use that if they want to (but undocumented) | ||
| 277 | ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode); | ||
| 278 | ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode) | ||
| 279 | { | ||
| 280 | IM_UNUSED(scancode); | ||
| 281 | switch (keycode) | ||
| 282 | { | ||
| 283 | case GLFW_KEY_TAB: return ImGuiKey_Tab; | ||
| 284 | case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow; | ||
| 285 | case GLFW_KEY_RIGHT: return ImGuiKey_RightArrow; | ||
| 286 | case GLFW_KEY_UP: return ImGuiKey_UpArrow; | ||
| 287 | case GLFW_KEY_DOWN: return ImGuiKey_DownArrow; | ||
| 288 | case GLFW_KEY_PAGE_UP: return ImGuiKey_PageUp; | ||
| 289 | case GLFW_KEY_PAGE_DOWN: return ImGuiKey_PageDown; | ||
| 290 | case GLFW_KEY_HOME: return ImGuiKey_Home; | ||
| 291 | case GLFW_KEY_END: return ImGuiKey_End; | ||
| 292 | case GLFW_KEY_INSERT: return ImGuiKey_Insert; | ||
| 293 | case GLFW_KEY_DELETE: return ImGuiKey_Delete; | ||
| 294 | case GLFW_KEY_BACKSPACE: return ImGuiKey_Backspace; | ||
| 295 | case GLFW_KEY_SPACE: return ImGuiKey_Space; | ||
| 296 | case GLFW_KEY_ENTER: return ImGuiKey_Enter; | ||
| 297 | case GLFW_KEY_ESCAPE: return ImGuiKey_Escape; | ||
| 298 | case GLFW_KEY_APOSTROPHE: return ImGuiKey_Apostrophe; | ||
| 299 | case GLFW_KEY_COMMA: return ImGuiKey_Comma; | ||
| 300 | case GLFW_KEY_MINUS: return ImGuiKey_Minus; | ||
| 301 | case GLFW_KEY_PERIOD: return ImGuiKey_Period; | ||
| 302 | case GLFW_KEY_SLASH: return ImGuiKey_Slash; | ||
| 303 | case GLFW_KEY_SEMICOLON: return ImGuiKey_Semicolon; | ||
| 304 | case GLFW_KEY_EQUAL: return ImGuiKey_Equal; | ||
| 305 | case GLFW_KEY_LEFT_BRACKET: return ImGuiKey_LeftBracket; | ||
| 306 | case GLFW_KEY_BACKSLASH: return ImGuiKey_Backslash; | ||
| 307 | case GLFW_KEY_WORLD_1: return ImGuiKey_Oem102; | ||
| 308 | case GLFW_KEY_WORLD_2: return ImGuiKey_Oem102; | ||
| 309 | case GLFW_KEY_RIGHT_BRACKET: return ImGuiKey_RightBracket; | ||
| 310 | case GLFW_KEY_GRAVE_ACCENT: return ImGuiKey_GraveAccent; | ||
| 311 | case GLFW_KEY_CAPS_LOCK: return ImGuiKey_CapsLock; | ||
| 312 | case GLFW_KEY_SCROLL_LOCK: return ImGuiKey_ScrollLock; | ||
| 313 | case GLFW_KEY_NUM_LOCK: return ImGuiKey_NumLock; | ||
| 314 | case GLFW_KEY_PRINT_SCREEN: return ImGuiKey_PrintScreen; | ||
| 315 | case GLFW_KEY_PAUSE: return ImGuiKey_Pause; | ||
| 316 | case GLFW_KEY_KP_0: return ImGuiKey_Keypad0; | ||
| 317 | case GLFW_KEY_KP_1: return ImGuiKey_Keypad1; | ||
| 318 | case GLFW_KEY_KP_2: return ImGuiKey_Keypad2; | ||
| 319 | case GLFW_KEY_KP_3: return ImGuiKey_Keypad3; | ||
| 320 | case GLFW_KEY_KP_4: return ImGuiKey_Keypad4; | ||
| 321 | case GLFW_KEY_KP_5: return ImGuiKey_Keypad5; | ||
| 322 | case GLFW_KEY_KP_6: return ImGuiKey_Keypad6; | ||
| 323 | case GLFW_KEY_KP_7: return ImGuiKey_Keypad7; | ||
| 324 | case GLFW_KEY_KP_8: return ImGuiKey_Keypad8; | ||
| 325 | case GLFW_KEY_KP_9: return ImGuiKey_Keypad9; | ||
| 326 | case GLFW_KEY_KP_DECIMAL: return ImGuiKey_KeypadDecimal; | ||
| 327 | case GLFW_KEY_KP_DIVIDE: return ImGuiKey_KeypadDivide; | ||
| 328 | case GLFW_KEY_KP_MULTIPLY: return ImGuiKey_KeypadMultiply; | ||
| 329 | case GLFW_KEY_KP_SUBTRACT: return ImGuiKey_KeypadSubtract; | ||
| 330 | case GLFW_KEY_KP_ADD: return ImGuiKey_KeypadAdd; | ||
| 331 | case GLFW_KEY_KP_ENTER: return ImGuiKey_KeypadEnter; | ||
| 332 | case GLFW_KEY_KP_EQUAL: return ImGuiKey_KeypadEqual; | ||
| 333 | case GLFW_KEY_LEFT_SHIFT: return ImGuiKey_LeftShift; | ||
| 334 | case GLFW_KEY_LEFT_CONTROL: return ImGuiKey_LeftCtrl; | ||
| 335 | case GLFW_KEY_LEFT_ALT: return ImGuiKey_LeftAlt; | ||
| 336 | case GLFW_KEY_LEFT_SUPER: return ImGuiKey_LeftSuper; | ||
| 337 | case GLFW_KEY_RIGHT_SHIFT: return ImGuiKey_RightShift; | ||
| 338 | case GLFW_KEY_RIGHT_CONTROL: return ImGuiKey_RightCtrl; | ||
| 339 | case GLFW_KEY_RIGHT_ALT: return ImGuiKey_RightAlt; | ||
| 340 | case GLFW_KEY_RIGHT_SUPER: return ImGuiKey_RightSuper; | ||
| 341 | case GLFW_KEY_MENU: return ImGuiKey_Menu; | ||
| 342 | case GLFW_KEY_0: return ImGuiKey_0; | ||
| 343 | case GLFW_KEY_1: return ImGuiKey_1; | ||
| 344 | case GLFW_KEY_2: return ImGuiKey_2; | ||
| 345 | case GLFW_KEY_3: return ImGuiKey_3; | ||
| 346 | case GLFW_KEY_4: return ImGuiKey_4; | ||
| 347 | case GLFW_KEY_5: return ImGuiKey_5; | ||
| 348 | case GLFW_KEY_6: return ImGuiKey_6; | ||
| 349 | case GLFW_KEY_7: return ImGuiKey_7; | ||
| 350 | case GLFW_KEY_8: return ImGuiKey_8; | ||
| 351 | case GLFW_KEY_9: return ImGuiKey_9; | ||
| 352 | case GLFW_KEY_A: return ImGuiKey_A; | ||
| 353 | case GLFW_KEY_B: return ImGuiKey_B; | ||
| 354 | case GLFW_KEY_C: return ImGuiKey_C; | ||
| 355 | case GLFW_KEY_D: return ImGuiKey_D; | ||
| 356 | case GLFW_KEY_E: return ImGuiKey_E; | ||
| 357 | case GLFW_KEY_F: return ImGuiKey_F; | ||
| 358 | case GLFW_KEY_G: return ImGuiKey_G; | ||
| 359 | case GLFW_KEY_H: return ImGuiKey_H; | ||
| 360 | case GLFW_KEY_I: return ImGuiKey_I; | ||
| 361 | case GLFW_KEY_J: return ImGuiKey_J; | ||
| 362 | case GLFW_KEY_K: return ImGuiKey_K; | ||
| 363 | case GLFW_KEY_L: return ImGuiKey_L; | ||
| 364 | case GLFW_KEY_M: return ImGuiKey_M; | ||
| 365 | case GLFW_KEY_N: return ImGuiKey_N; | ||
| 366 | case GLFW_KEY_O: return ImGuiKey_O; | ||
| 367 | case GLFW_KEY_P: return ImGuiKey_P; | ||
| 368 | case GLFW_KEY_Q: return ImGuiKey_Q; | ||
| 369 | case GLFW_KEY_R: return ImGuiKey_R; | ||
| 370 | case GLFW_KEY_S: return ImGuiKey_S; | ||
| 371 | case GLFW_KEY_T: return ImGuiKey_T; | ||
| 372 | case GLFW_KEY_U: return ImGuiKey_U; | ||
| 373 | case GLFW_KEY_V: return ImGuiKey_V; | ||
| 374 | case GLFW_KEY_W: return ImGuiKey_W; | ||
| 375 | case GLFW_KEY_X: return ImGuiKey_X; | ||
| 376 | case GLFW_KEY_Y: return ImGuiKey_Y; | ||
| 377 | case GLFW_KEY_Z: return ImGuiKey_Z; | ||
| 378 | case GLFW_KEY_F1: return ImGuiKey_F1; | ||
| 379 | case GLFW_KEY_F2: return ImGuiKey_F2; | ||
| 380 | case GLFW_KEY_F3: return ImGuiKey_F3; | ||
| 381 | case GLFW_KEY_F4: return ImGuiKey_F4; | ||
| 382 | case GLFW_KEY_F5: return ImGuiKey_F5; | ||
| 383 | case GLFW_KEY_F6: return ImGuiKey_F6; | ||
| 384 | case GLFW_KEY_F7: return ImGuiKey_F7; | ||
| 385 | case GLFW_KEY_F8: return ImGuiKey_F8; | ||
| 386 | case GLFW_KEY_F9: return ImGuiKey_F9; | ||
| 387 | case GLFW_KEY_F10: return ImGuiKey_F10; | ||
| 388 | case GLFW_KEY_F11: return ImGuiKey_F11; | ||
| 389 | case GLFW_KEY_F12: return ImGuiKey_F12; | ||
| 390 | case GLFW_KEY_F13: return ImGuiKey_F13; | ||
| 391 | case GLFW_KEY_F14: return ImGuiKey_F14; | ||
| 392 | case GLFW_KEY_F15: return ImGuiKey_F15; | ||
| 393 | case GLFW_KEY_F16: return ImGuiKey_F16; | ||
| 394 | case GLFW_KEY_F17: return ImGuiKey_F17; | ||
| 395 | case GLFW_KEY_F18: return ImGuiKey_F18; | ||
| 396 | case GLFW_KEY_F19: return ImGuiKey_F19; | ||
| 397 | case GLFW_KEY_F20: return ImGuiKey_F20; | ||
| 398 | case GLFW_KEY_F21: return ImGuiKey_F21; | ||
| 399 | case GLFW_KEY_F22: return ImGuiKey_F22; | ||
| 400 | case GLFW_KEY_F23: return ImGuiKey_F23; | ||
| 401 | case GLFW_KEY_F24: return ImGuiKey_F24; | ||
| 402 | default: return ImGuiKey_None; | ||
| 403 | } | ||
| 404 | } | ||
| 405 | |||
| 406 | // X11 does not include current pressed/released modifier key in 'mods' flags submitted by GLFW | ||
| 407 | // See https://github.com/ocornut/imgui/issues/6034 and https://github.com/glfw/glfw/issues/1630 | ||
| 408 | static void ImGui_ImplGlfw_UpdateKeyModifiers(ImGuiIO& io, GLFWwindow* window) | ||
| 409 | { | ||
| 410 | io.AddKeyEvent(ImGuiMod_Ctrl, (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS)); | ||
| 411 | io.AddKeyEvent(ImGuiMod_Shift, (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS)); | ||
| 412 | io.AddKeyEvent(ImGuiMod_Alt, (glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS)); | ||
| 413 | io.AddKeyEvent(ImGuiMod_Super, (glfwGetKey(window, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS)); | ||
| 414 | } | ||
| 415 | |||
| 416 | static bool ImGui_ImplGlfw_ShouldChainCallback(ImGui_ImplGlfw_Data* bd, GLFWwindow* window) | ||
| 417 | { | ||
| 418 | return bd->CallbacksChainForAllWindows ? true : (window == bd->Window); | ||
| 419 | } | ||
| 420 | |||
| 421 | void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) | ||
| 422 | { | ||
| 423 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); | ||
| 424 | if (bd->PrevUserCallbackMousebutton != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) | ||
| 425 | bd->PrevUserCallbackMousebutton(window, button, action, mods); | ||
| 426 | |||
| 427 | ImGuiIO& io = ImGui::GetIO(bd->Context); | ||
| 428 | ImGui_ImplGlfw_UpdateKeyModifiers(io, window); | ||
| 429 | if (button >= 0 && button < ImGuiMouseButton_COUNT) | ||
| 430 | io.AddMouseButtonEvent(button, action == GLFW_PRESS); | ||
| 431 | } | ||
| 432 | |||
| 433 | void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) | ||
| 434 | { | ||
| 435 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); | ||
| 436 | if (bd->PrevUserCallbackScroll != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) | ||
| 437 | bd->PrevUserCallbackScroll(window, xoffset, yoffset); | ||
| 438 | |||
| 439 | #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 | ||
| 440 | // Ignore GLFW events: will be processed in ImGui_ImplEmscripten_WheelCallback(). | ||
| 441 | return; | ||
| 442 | #endif | ||
| 443 | |||
| 444 | ImGuiIO& io = ImGui::GetIO(bd->Context); | ||
| 445 | io.AddMouseWheelEvent((float)xoffset, (float)yoffset); | ||
| 446 | } | ||
| 447 | |||
| 448 | // FIXME: should this be baked into ImGui_ImplGlfw_KeyToImGuiKey()? then what about the values passed to io.SetKeyEventNativeData()? | ||
| 449 | static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode) | ||
| 450 | { | ||
| 451 | #if GLFW_HAS_GETKEYNAME && !defined(EMSCRIPTEN_USE_EMBEDDED_GLFW3) | ||
| 452 | // GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult. | ||
| 453 | // (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently) | ||
| 454 | // See https://github.com/glfw/glfw/issues/1502 for details. | ||
| 455 | // Adding a workaround to undo this (so our keys are translated->untranslated->translated, likely a lossy process). | ||
| 456 | // This won't cover edge cases but this is at least going to cover common cases. | ||
| 457 | if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_EQUAL) | ||
| 458 | return key; | ||
| 459 | GLFWerrorfun prev_error_callback = glfwSetErrorCallback(nullptr); | ||
| 460 | const char* key_name = glfwGetKeyName(key, scancode); | ||
| 461 | glfwSetErrorCallback(prev_error_callback); | ||
| 462 | #if GLFW_HAS_GETERROR && !defined(EMSCRIPTEN_USE_EMBEDDED_GLFW3) // Eat errors (see #5908) | ||
| 463 | (void)glfwGetError(nullptr); | ||
| 464 | #endif | ||
| 465 | if (key_name && key_name[0] != 0 && key_name[1] == 0) | ||
| 466 | { | ||
| 467 | const char char_names[] = "`-=[]\\,;\'./"; | ||
| 468 | 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 }; | ||
| 469 | IM_ASSERT(IM_COUNTOF(char_names) == IM_COUNTOF(char_keys)); | ||
| 470 | if (key_name[0] >= '0' && key_name[0] <= '9') { key = GLFW_KEY_0 + (key_name[0] - '0'); } | ||
| 471 | else if (key_name[0] >= 'A' && key_name[0] <= 'Z') { key = GLFW_KEY_A + (key_name[0] - 'A'); } | ||
| 472 | else if (key_name[0] >= 'a' && key_name[0] <= 'z') { key = GLFW_KEY_A + (key_name[0] - 'a'); } | ||
| 473 | else if (const char* p = strchr(char_names, key_name[0])) { key = char_keys[p - char_names]; } | ||
| 474 | } | ||
| 475 | // if (action == GLFW_PRESS) printf("key %d scancode %d name '%s'\n", key, scancode, key_name); | ||
| 476 | #else | ||
| 477 | IM_UNUSED(scancode); | ||
| 478 | #endif | ||
| 479 | return key; | ||
| 480 | } | ||
| 481 | |||
| 482 | void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods) | ||
| 483 | { | ||
| 484 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); | ||
| 485 | if (bd->PrevUserCallbackKey != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) | ||
| 486 | bd->PrevUserCallbackKey(window, keycode, scancode, action, mods); | ||
| 487 | |||
| 488 | if (action != GLFW_PRESS && action != GLFW_RELEASE) | ||
| 489 | return; | ||
| 490 | |||
| 491 | ImGuiIO& io = ImGui::GetIO(bd->Context); | ||
| 492 | ImGui_ImplGlfw_UpdateKeyModifiers(io, window); | ||
| 493 | |||
| 494 | keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode); | ||
| 495 | |||
| 496 | ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode, scancode); | ||
| 497 | io.AddKeyEvent(imgui_key, (action == GLFW_PRESS)); | ||
| 498 | io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code) | ||
| 499 | } | ||
| 500 | |||
| 501 | void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused) | ||
| 502 | { | ||
| 503 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); | ||
| 504 | if (bd->PrevUserCallbackWindowFocus != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) | ||
| 505 | bd->PrevUserCallbackWindowFocus(window, focused); | ||
| 506 | |||
| 507 | ImGuiIO& io = ImGui::GetIO(bd->Context); | ||
| 508 | io.AddFocusEvent(focused != 0); | ||
| 509 | } | ||
| 510 | |||
| 511 | void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y) | ||
| 512 | { | ||
| 513 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); | ||
| 514 | if (bd->PrevUserCallbackCursorPos != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) | ||
| 515 | bd->PrevUserCallbackCursorPos(window, x, y); | ||
| 516 | |||
| 517 | ImGuiIO& io = ImGui::GetIO(bd->Context); | ||
| 518 | io.AddMousePosEvent((float)x, (float)y); | ||
| 519 | bd->LastValidMousePos = ImVec2((float)x, (float)y); | ||
| 520 | } | ||
| 521 | |||
| 522 | // Workaround: X11 seems to send spurious Leave/Enter events which would make us lose our position, | ||
| 523 | // so we back it up and restore on Leave/Enter (see https://github.com/ocornut/imgui/issues/4984) | ||
| 524 | void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered) | ||
| 525 | { | ||
| 526 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); | ||
| 527 | if (bd->PrevUserCallbackCursorEnter != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) | ||
| 528 | bd->PrevUserCallbackCursorEnter(window, entered); | ||
| 529 | |||
| 530 | ImGuiIO& io = ImGui::GetIO(bd->Context); | ||
| 531 | if (entered) | ||
| 532 | { | ||
| 533 | bd->MouseWindow = window; | ||
| 534 | io.AddMousePosEvent(bd->LastValidMousePos.x, bd->LastValidMousePos.y); | ||
| 535 | } | ||
| 536 | else if (!entered && bd->MouseWindow == window) | ||
| 537 | { | ||
| 538 | bd->LastValidMousePos = io.MousePos; | ||
| 539 | bd->MouseWindow = nullptr; | ||
| 540 | io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); | ||
| 541 | } | ||
| 542 | } | ||
| 543 | |||
| 544 | void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) | ||
| 545 | { | ||
| 546 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); | ||
| 547 | if (bd->PrevUserCallbackChar != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) | ||
| 548 | bd->PrevUserCallbackChar(window, c); | ||
| 549 | |||
| 550 | ImGuiIO& io = ImGui::GetIO(bd->Context); | ||
| 551 | io.AddInputCharacter(c); | ||
| 552 | } | ||
| 553 | |||
| 554 | void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int) | ||
| 555 | { | ||
| 556 | // Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too. | ||
| 557 | } | ||
| 558 | |||
| 559 | #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 | ||
| 560 | static EM_BOOL ImGui_ImplEmscripten_WheelCallback(int, const EmscriptenWheelEvent* ev, void* user_data) | ||
| 561 | { | ||
| 562 | // Mimic Emscripten_HandleWheel() in SDL. | ||
| 563 | // Corresponding equivalent in GLFW JS emulation layer has incorrect quantizing preventing small values. See #6096 | ||
| 564 | ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)user_data; | ||
| 565 | float multiplier = 0.0f; | ||
| 566 | if (ev->deltaMode == DOM_DELTA_PIXEL) { multiplier = 1.0f / 100.0f; } // 100 pixels make up a step. | ||
| 567 | else if (ev->deltaMode == DOM_DELTA_LINE) { multiplier = 1.0f / 3.0f; } // 3 lines make up a step. | ||
| 568 | else if (ev->deltaMode == DOM_DELTA_PAGE) { multiplier = 80.0f; } // A page makes up 80 steps. | ||
| 569 | float wheel_x = ev->deltaX * -multiplier; | ||
| 570 | float wheel_y = ev->deltaY * -multiplier; | ||
| 571 | ImGuiIO& io = ImGui::GetIO(bd->Context); | ||
| 572 | io.AddMouseWheelEvent(wheel_x, wheel_y); | ||
| 573 | //IMGUI_DEBUG_LOG("[Emsc] mode %d dx: %.2f, dy: %.2f, dz: %.2f --> feed %.2f %.2f\n", (int)ev->deltaMode, ev->deltaX, ev->deltaY, ev->deltaZ, wheel_x, wheel_y); | ||
| 574 | return EM_TRUE; | ||
| 575 | } | ||
| 576 | #endif | ||
| 577 | |||
| 578 | #ifdef _WIN32 | ||
| 579 | // GLFW doesn't allow to distinguish Mouse vs TouchScreen vs Pen. | ||
| 580 | // Add support for Win32 (based on imgui_impl_win32), because we rely on _TouchScreen info to trickle inputs differently. | ||
| 581 | static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo() | ||
| 582 | { | ||
| 583 | LPARAM extra_info = ::GetMessageExtraInfo(); | ||
| 584 | if ((extra_info & 0xFFFFFF80) == 0xFF515700) | ||
| 585 | return ImGuiMouseSource_Pen; | ||
| 586 | if ((extra_info & 0xFFFFFF80) == 0xFF515780) | ||
| 587 | return ImGuiMouseSource_TouchScreen; | ||
| 588 | return ImGuiMouseSource_Mouse; | ||
| 589 | } | ||
| 590 | static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) | ||
| 591 | { | ||
| 592 | ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)::GetPropA(hWnd, "IMGUI_BACKEND_DATA"); | ||
| 593 | ImGuiIO& io = ImGui::GetIO(bd->Context); | ||
| 594 | |||
| 595 | switch (msg) | ||
| 596 | { | ||
| 597 | case WM_MOUSEMOVE: case WM_NCMOUSEMOVE: | ||
| 598 | case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_LBUTTONUP: | ||
| 599 | case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_RBUTTONUP: | ||
| 600 | case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_MBUTTONUP: | ||
| 601 | case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: case WM_XBUTTONUP: | ||
| 602 | io.AddMouseSourceEvent(GetMouseSourceFromMessageExtraInfo()); | ||
| 603 | break; | ||
| 604 | default: break; | ||
| 605 | } | ||
| 606 | return ::CallWindowProcW(bd->PrevWndProc, hWnd, msg, wParam, lParam); | ||
| 607 | } | ||
| 608 | #endif | ||
| 609 | |||
| 610 | void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window) | ||
| 611 | { | ||
| 612 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); | ||
| 613 | IM_ASSERT(bd->InstalledCallbacks == false && "Callbacks already installed!"); | ||
| 614 | IM_ASSERT(bd->Window == window); | ||
| 615 | |||
| 616 | bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback); | ||
| 617 | bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback); | ||
| 618 | bd->PrevUserCallbackCursorPos = glfwSetCursorPosCallback(window, ImGui_ImplGlfw_CursorPosCallback); | ||
| 619 | bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); | ||
| 620 | bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); | ||
| 621 | bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); | ||
| 622 | bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); | ||
| 623 | bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback); | ||
| 624 | bd->InstalledCallbacks = true; | ||
| 625 | } | ||
| 626 | |||
| 627 | void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window) | ||
| 628 | { | ||
| 629 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); | ||
| 630 | IM_ASSERT(bd->InstalledCallbacks == true && "Callbacks not installed!"); | ||
| 631 | IM_ASSERT(bd->Window == window); | ||
| 632 | |||
| 633 | glfwSetWindowFocusCallback(window, bd->PrevUserCallbackWindowFocus); | ||
| 634 | glfwSetCursorEnterCallback(window, bd->PrevUserCallbackCursorEnter); | ||
| 635 | glfwSetCursorPosCallback(window, bd->PrevUserCallbackCursorPos); | ||
| 636 | glfwSetMouseButtonCallback(window, bd->PrevUserCallbackMousebutton); | ||
| 637 | glfwSetScrollCallback(window, bd->PrevUserCallbackScroll); | ||
| 638 | glfwSetKeyCallback(window, bd->PrevUserCallbackKey); | ||
| 639 | glfwSetCharCallback(window, bd->PrevUserCallbackChar); | ||
| 640 | glfwSetMonitorCallback(bd->PrevUserCallbackMonitor); | ||
| 641 | bd->InstalledCallbacks = false; | ||
| 642 | bd->PrevUserCallbackWindowFocus = nullptr; | ||
| 643 | bd->PrevUserCallbackCursorEnter = nullptr; | ||
| 644 | bd->PrevUserCallbackCursorPos = nullptr; | ||
| 645 | bd->PrevUserCallbackMousebutton = nullptr; | ||
| 646 | bd->PrevUserCallbackScroll = nullptr; | ||
| 647 | bd->PrevUserCallbackKey = nullptr; | ||
| 648 | bd->PrevUserCallbackChar = nullptr; | ||
| 649 | bd->PrevUserCallbackMonitor = nullptr; | ||
| 650 | } | ||
| 651 | |||
| 652 | // Set to 'true' to enable chaining installed callbacks for all windows (including secondary viewports created by backends or by user). | ||
| 653 | // This is 'false' by default meaning we only chain callbacks for the main viewport. | ||
| 654 | // We cannot set this to 'true' by default because user callbacks code may be not testing the 'window' parameter of their callback. | ||
| 655 | // If you set this to 'true' your user callback code will need to make sure you are testing the 'window' parameter. | ||
| 656 | void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows) | ||
| 657 | { | ||
| 658 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | ||
| 659 | bd->CallbacksChainForAllWindows = chain_for_all_windows; | ||
| 660 | } | ||
| 661 | |||
| 662 | #ifdef __EMSCRIPTEN__ | ||
| 663 | #if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 34020240817 | ||
| 664 | void ImGui_ImplGlfw_EmscriptenOpenURL(const char* url) { if (url) emscripten::glfw3::OpenURL(url); } | ||
| 665 | #else | ||
| 666 | EM_JS(void, ImGui_ImplGlfw_EmscriptenOpenURL, (const char* url), { url = url ? UTF8ToString(url) : null; if (url) window.open(url, '_blank'); }); | ||
| 667 | #endif | ||
| 668 | #endif | ||
| 669 | |||
| 670 | static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) | ||
| 671 | { | ||
| 672 | ImGuiIO& io = ImGui::GetIO(); | ||
| 673 | IMGUI_CHECKVERSION(); | ||
| 674 | IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); | ||
| 675 | //printf("GLFW_VERSION: %d.%d.%d (%d)", GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION, GLFW_VERSION_COMBINED); | ||
| 676 | |||
| 677 | // Setup backend capabilities flags | ||
| 678 | ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)(); | ||
| 679 | bd->Context = ImGui::GetCurrentContext(); | ||
| 680 | bd->Window = window; | ||
| 681 | bd->Time = 0.0; | ||
| 682 | bd->IsWayland = ImGui_ImplGlfw_IsWayland(); | ||
| 683 | ImGui_ImplGlfw_ContextMap_Add(window, bd->Context); | ||
| 684 | |||
| 685 | snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_glfw (%d)%s", GLFW_VERSION_COMBINED, bd->IsWayland ? " (Wayland)" : ""); | ||
| 686 | io.BackendPlatformUserData = (void*)bd; | ||
| 687 | io.BackendPlatformName = bd->BackendPlatformName; | ||
| 688 | #if GLFW_HAS_CREATECURSOR | ||
| 689 | io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) | ||
| 690 | #endif | ||
| 691 | io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) | ||
| 692 | |||
| 693 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | ||
| 694 | #if GLFW_VERSION_COMBINED < 3300 | ||
| 695 | platform_io.Platform_SetClipboardTextFn = [](ImGuiContext*, const char* text) { glfwSetClipboardString(ImGui_ImplGlfw_GetBackendData()->Window, text); }; | ||
| 696 | platform_io.Platform_GetClipboardTextFn = [](ImGuiContext*) { return glfwGetClipboardString(ImGui_ImplGlfw_GetBackendData()->Window); }; | ||
| 697 | #else | ||
| 698 | platform_io.Platform_SetClipboardTextFn = [](ImGuiContext*, const char* text) { glfwSetClipboardString(nullptr, text); }; | ||
| 699 | platform_io.Platform_GetClipboardTextFn = [](ImGuiContext*) { return glfwGetClipboardString(nullptr); }; | ||
| 700 | #endif | ||
| 701 | |||
| 702 | #ifdef __EMSCRIPTEN__ | ||
| 703 | platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplGlfw_EmscriptenOpenURL(url); return true; }; | ||
| 704 | #endif | ||
| 705 | |||
| 706 | // Create mouse cursors | ||
| 707 | // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist, | ||
| 708 | // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting. | ||
| 709 | // Missing cursors will return nullptr and our _UpdateMouseCursor() function will use the Arrow cursor instead.) | ||
| 710 | #if GLFW_HAS_CREATECURSOR | ||
| 711 | GLFWerrorfun prev_error_callback = glfwSetErrorCallback(nullptr); | ||
| 712 | bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); | ||
| 713 | bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); | ||
| 714 | bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR); | ||
| 715 | bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); | ||
| 716 | bd->MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR); | ||
| 717 | #if GLFW_HAS_NEW_CURSORS | ||
| 718 | bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR); | ||
| 719 | bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR); | ||
| 720 | bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR); | ||
| 721 | bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR); | ||
| 722 | #else | ||
| 723 | bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); | ||
| 724 | bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); | ||
| 725 | bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); | ||
| 726 | bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); | ||
| 727 | #endif | ||
| 728 | glfwSetErrorCallback(prev_error_callback); | ||
| 729 | #endif | ||
| 730 | #if GLFW_HAS_GETERROR && !defined(__EMSCRIPTEN__) // Eat errors (see #5908) | ||
| 731 | (void)glfwGetError(nullptr); | ||
| 732 | #endif | ||
| 733 | |||
| 734 | // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. | ||
| 735 | if (install_callbacks) | ||
| 736 | ImGui_ImplGlfw_InstallCallbacks(window); | ||
| 737 | |||
| 738 | // Set platform dependent data in viewport | ||
| 739 | ImGuiViewport* main_viewport = ImGui::GetMainViewport(); | ||
| 740 | main_viewport->PlatformHandle = (void*)bd->Window; | ||
| 741 | #ifdef _WIN32 | ||
| 742 | main_viewport->PlatformHandleRaw = glfwGetWin32Window(bd->Window); | ||
| 743 | #elif defined(__APPLE__) | ||
| 744 | main_viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(bd->Window); | ||
| 745 | #else | ||
| 746 | IM_UNUSED(main_viewport); | ||
| 747 | #endif | ||
| 748 | |||
| 749 | // Windows: register a WndProc hook so we can intercept some messages. | ||
| 750 | #ifdef _WIN32 | ||
| 751 | HWND hwnd = (HWND)main_viewport->PlatformHandleRaw; | ||
| 752 | ::SetPropA(hwnd, "IMGUI_BACKEND_DATA", bd); | ||
| 753 | bd->PrevWndProc = (WNDPROC)::GetWindowLongPtrW(hwnd, GWLP_WNDPROC); | ||
| 754 | IM_ASSERT(bd->PrevWndProc != nullptr); | ||
| 755 | ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc); | ||
| 756 | #endif | ||
| 757 | |||
| 758 | // Emscripten: the same application can run on various platforms, so we detect the Apple platform at runtime | ||
| 759 | // to override io.ConfigMacOSXBehaviors from its default (which is always false in Emscripten). | ||
| 760 | #ifdef __EMSCRIPTEN__ | ||
| 761 | #if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 34020240817 | ||
| 762 | if (emscripten::glfw3::IsRuntimePlatformApple()) | ||
| 763 | { | ||
| 764 | io.ConfigMacOSXBehaviors = true; | ||
| 765 | |||
| 766 | // Due to how the browser (poorly) handles the Meta Key, this line essentially disables repeats when used. | ||
| 767 | // This means that Meta + V only registers a single key-press, even if the keys are held. | ||
| 768 | // This is a compromise for dealing with this issue in ImGui since ImGui implements key repeat itself. | ||
| 769 | // See https://github.com/pongasoft/emscripten-glfw/blob/v3.4.0.20240817/docs/Usage.md#the-problem-of-the-super-key | ||
| 770 | emscripten::glfw3::SetSuperPlusKeyTimeouts(10, 10); | ||
| 771 | } | ||
| 772 | #endif | ||
| 773 | #endif | ||
| 774 | |||
| 775 | bd->ClientApi = client_api; | ||
| 776 | return true; | ||
| 777 | } | ||
| 778 | |||
| 779 | bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks) | ||
| 780 | { | ||
| 781 | return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL); | ||
| 782 | } | ||
| 783 | |||
| 784 | bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks) | ||
| 785 | { | ||
| 786 | return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan); | ||
| 787 | } | ||
| 788 | |||
| 789 | bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks) | ||
| 790 | { | ||
| 791 | return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown); | ||
| 792 | } | ||
| 793 | |||
| 794 | void ImGui_ImplGlfw_Shutdown() | ||
| 795 | { | ||
| 796 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | ||
| 797 | IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); | ||
| 798 | |||
| 799 | ImGuiIO& io = ImGui::GetIO(); | ||
| 800 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | ||
| 801 | |||
| 802 | if (bd->InstalledCallbacks) | ||
| 803 | ImGui_ImplGlfw_RestoreCallbacks(bd->Window); | ||
| 804 | #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 | ||
| 805 | if (bd->CanvasSelector) | ||
| 806 | emscripten_set_wheel_callback(bd->CanvasSelector, nullptr, false, nullptr); | ||
| 807 | #endif | ||
| 808 | #if GLFW_HAS_CREATECURSOR | ||
| 809 | for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) | ||
| 810 | glfwDestroyCursor(bd->MouseCursors[cursor_n]); | ||
| 811 | #endif | ||
| 812 | // Windows: restore our WndProc hook | ||
| 813 | #ifdef _WIN32 | ||
| 814 | ImGuiViewport* main_viewport = ImGui::GetMainViewport(); | ||
| 815 | ::SetPropA((HWND)main_viewport->PlatformHandleRaw, "IMGUI_BACKEND_DATA", nullptr); | ||
| 816 | ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)bd->PrevWndProc); | ||
| 817 | bd->PrevWndProc = nullptr; | ||
| 818 | #endif | ||
| 819 | |||
| 820 | io.BackendPlatformName = nullptr; | ||
| 821 | io.BackendPlatformUserData = nullptr; | ||
| 822 | io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad); | ||
| 823 | platform_io.ClearPlatformHandlers(); | ||
| 824 | ImGui_ImplGlfw_ContextMap_Remove(bd->Window); | ||
| 825 | IM_DELETE(bd); | ||
| 826 | } | ||
| 827 | |||
| 828 | static void ImGui_ImplGlfw_UpdateMouseData() | ||
| 829 | { | ||
| 830 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | ||
| 831 | ImGuiIO& io = ImGui::GetIO(); | ||
| 832 | |||
| 833 | // (those braces are here to reduce diff with multi-viewports support in 'docking' branch) | ||
| 834 | { | ||
| 835 | GLFWwindow* window = bd->Window; | ||
| 836 | #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 | ||
| 837 | const bool is_window_focused = true; | ||
| 838 | #else | ||
| 839 | const bool is_window_focused = glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0; | ||
| 840 | #endif | ||
| 841 | if (is_window_focused) | ||
| 842 | { | ||
| 843 | // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user) | ||
| 844 | if (io.WantSetMousePos) | ||
| 845 | glfwSetCursorPos(window, (double)io.MousePos.x, (double)io.MousePos.y); | ||
| 846 | |||
| 847 | // (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured) | ||
| 848 | if (bd->MouseWindow == nullptr) | ||
| 849 | { | ||
| 850 | double mouse_x, mouse_y; | ||
| 851 | glfwGetCursorPos(window, &mouse_x, &mouse_y); | ||
| 852 | bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y); | ||
| 853 | io.AddMousePosEvent((float)mouse_x, (float)mouse_y); | ||
| 854 | } | ||
| 855 | } | ||
| 856 | } | ||
| 857 | } | ||
| 858 | |||
| 859 | static void ImGui_ImplGlfw_UpdateMouseCursor() | ||
| 860 | { | ||
| 861 | ImGuiIO& io = ImGui::GetIO(); | ||
| 862 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | ||
| 863 | if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) | ||
| 864 | { | ||
| 865 | bd->LastMouseCursor = nullptr; // Invalidate so that if user changes underlying cursor we will update it next time we can. | ||
| 866 | return; | ||
| 867 | } | ||
| 868 | |||
| 869 | ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); | ||
| 870 | // (those braces are here to reduce diff with multi-viewports support in 'docking' branch) | ||
| 871 | { | ||
| 872 | GLFWwindow* window = bd->Window; | ||
| 873 | if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) | ||
| 874 | { | ||
| 875 | if (bd->LastMouseCursor != nullptr) | ||
| 876 | { | ||
| 877 | // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor | ||
| 878 | glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); | ||
| 879 | bd->LastMouseCursor = nullptr; | ||
| 880 | } | ||
| 881 | } | ||
| 882 | else | ||
| 883 | { | ||
| 884 | // Show OS mouse cursor | ||
| 885 | // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here. | ||
| 886 | #if GLFW_HAS_CREATECURSOR | ||
| 887 | GLFWcursor* cursor = bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]; | ||
| 888 | if (bd->LastMouseCursor != cursor) | ||
| 889 | { | ||
| 890 | glfwSetCursor(window, cursor); | ||
| 891 | bd->LastMouseCursor = cursor; | ||
| 892 | } | ||
| 893 | #endif | ||
| 894 | glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); | ||
| 895 | } | ||
| 896 | } | ||
| 897 | } | ||
| 898 | |||
| 899 | // Update gamepad inputs | ||
| 900 | static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; } | ||
| 901 | static void ImGui_ImplGlfw_UpdateGamepads() | ||
| 902 | { | ||
| 903 | ImGuiIO& io = ImGui::GetIO(); | ||
| 904 | if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs, but see #8075 | ||
| 905 | return; | ||
| 906 | |||
| 907 | io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; | ||
| 908 | #if GLFW_HAS_GAMEPAD_API && !defined(EMSCRIPTEN_USE_EMBEDDED_GLFW3) | ||
| 909 | GLFWgamepadstate gamepad; | ||
| 910 | if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &gamepad)) | ||
| 911 | return; | ||
| 912 | #define MAP_BUTTON(KEY_NO, BUTTON_NO, _UNUSED) do { io.AddKeyEvent(KEY_NO, gamepad.buttons[BUTTON_NO] != 0); } while (0) | ||
| 913 | #define MAP_ANALOG(KEY_NO, AXIS_NO, _UNUSED, V0, V1) do { float v = gamepad.axes[AXIS_NO]; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0) | ||
| 914 | #else | ||
| 915 | int axes_count = 0, buttons_count = 0; | ||
| 916 | const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count); | ||
| 917 | const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count); | ||
| 918 | if (axes_count == 0 || buttons_count == 0) | ||
| 919 | return; | ||
| 920 | #define MAP_BUTTON(KEY_NO, _UNUSED, BUTTON_NO) do { io.AddKeyEvent(KEY_NO, (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS)); } while (0) | ||
| 921 | #define MAP_ANALOG(KEY_NO, _UNUSED, AXIS_NO, V0, V1) do { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0) | ||
| 922 | #endif | ||
| 923 | io.BackendFlags |= ImGuiBackendFlags_HasGamepad; | ||
| 924 | MAP_BUTTON(ImGuiKey_GamepadStart, GLFW_GAMEPAD_BUTTON_START, 7); | ||
| 925 | MAP_BUTTON(ImGuiKey_GamepadBack, GLFW_GAMEPAD_BUTTON_BACK, 6); | ||
| 926 | MAP_BUTTON(ImGuiKey_GamepadFaceLeft, GLFW_GAMEPAD_BUTTON_X, 2); // Xbox X, PS Square | ||
| 927 | MAP_BUTTON(ImGuiKey_GamepadFaceRight, GLFW_GAMEPAD_BUTTON_B, 1); // Xbox B, PS Circle | ||
| 928 | MAP_BUTTON(ImGuiKey_GamepadFaceUp, GLFW_GAMEPAD_BUTTON_Y, 3); // Xbox Y, PS Triangle | ||
| 929 | MAP_BUTTON(ImGuiKey_GamepadFaceDown, GLFW_GAMEPAD_BUTTON_A, 0); // Xbox A, PS Cross | ||
| 930 | MAP_BUTTON(ImGuiKey_GamepadDpadLeft, GLFW_GAMEPAD_BUTTON_DPAD_LEFT, 13); | ||
| 931 | MAP_BUTTON(ImGuiKey_GamepadDpadRight, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, 11); | ||
| 932 | MAP_BUTTON(ImGuiKey_GamepadDpadUp, GLFW_GAMEPAD_BUTTON_DPAD_UP, 10); | ||
| 933 | MAP_BUTTON(ImGuiKey_GamepadDpadDown, GLFW_GAMEPAD_BUTTON_DPAD_DOWN, 12); | ||
| 934 | MAP_BUTTON(ImGuiKey_GamepadL1, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, 4); | ||
| 935 | MAP_BUTTON(ImGuiKey_GamepadR1, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, 5); | ||
| 936 | MAP_ANALOG(ImGuiKey_GamepadL2, GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, 4, -0.75f, +1.0f); | ||
| 937 | MAP_ANALOG(ImGuiKey_GamepadR2, GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, 5, -0.75f, +1.0f); | ||
| 938 | MAP_BUTTON(ImGuiKey_GamepadL3, GLFW_GAMEPAD_BUTTON_LEFT_THUMB, 8); | ||
| 939 | MAP_BUTTON(ImGuiKey_GamepadR3, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, 9); | ||
| 940 | MAP_ANALOG(ImGuiKey_GamepadLStickLeft, GLFW_GAMEPAD_AXIS_LEFT_X, 0, -0.25f, -1.0f); | ||
| 941 | MAP_ANALOG(ImGuiKey_GamepadLStickRight, GLFW_GAMEPAD_AXIS_LEFT_X, 0, +0.25f, +1.0f); | ||
| 942 | MAP_ANALOG(ImGuiKey_GamepadLStickUp, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, -0.25f, -1.0f); | ||
| 943 | MAP_ANALOG(ImGuiKey_GamepadLStickDown, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, +0.25f, +1.0f); | ||
| 944 | MAP_ANALOG(ImGuiKey_GamepadRStickLeft, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, -0.25f, -1.0f); | ||
| 945 | MAP_ANALOG(ImGuiKey_GamepadRStickRight, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, +0.25f, +1.0f); | ||
| 946 | MAP_ANALOG(ImGuiKey_GamepadRStickUp, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, -0.25f, -1.0f); | ||
| 947 | MAP_ANALOG(ImGuiKey_GamepadRStickDown, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, +0.25f, +1.0f); | ||
| 948 | #undef MAP_BUTTON | ||
| 949 | #undef MAP_ANALOG | ||
| 950 | } | ||
| 951 | |||
| 952 | // For GFLW 3.2 + Windows: include a simplified non-monitor aware version of ImGui_ImplWin32_GetDpiScaleForMonitor(). | ||
| 953 | // This is merely a band-aid to make using GLFW 3.2 a little bit nicer, but prefer to use GLFW 3.3+ or the full correct functions from the Win32 backend. | ||
| 954 | #if !GLFW_HAS_PER_MONITOR_DPI && defined(_WIN32) && !defined(NOGDI) | ||
| 955 | static float ImGui_ImplWin32_GetLegacyDpiScale() { const HDC dc = ::GetDC(nullptr); UINT xdpi = ::GetDeviceCaps(dc, LOGPIXELSX); ::ReleaseDC(nullptr, dc); return (float)xdpi / 96.0f; } | ||
| 956 | static void glfwGetWindowContentScale(GLFWwindow*, float* x_scale, float* y_scale) { *x_scale = *y_scale = ImGui_ImplWin32_GetLegacyDpiScale(); } | ||
| 957 | static void glfwGetMonitorContentScale(GLFWmonitor*, float* x_scale, float* y_scale) { *x_scale = *y_scale = ImGui_ImplWin32_GetLegacyDpiScale(); } | ||
| 958 | #undef GLFW_HAS_PER_MONITOR_DPI | ||
| 959 | #define GLFW_HAS_PER_MONITOR_DPI 1 | ||
| 960 | #endif | ||
| 961 | |||
| 962 | // - On Windows the process needs to be marked DPI-aware!! SDL2 doesn't do it by default. You can call ::SetProcessDPIAware() or call ImGui_ImplWin32_EnableDpiAwareness() from Win32 backend. | ||
| 963 | // - Apple platforms use FramebufferScale so we always return 1.0f. | ||
| 964 | // - Some accessibility applications are declaring virtual monitors with a DPI of 0.0f, see #7902. We preserve this value for caller to handle. | ||
| 965 | float ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) | ||
| 966 | { | ||
| 967 | #if GLFW_HAS_WAYLAND | ||
| 968 | if (ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window)) | ||
| 969 | if (bd->IsWayland) | ||
| 970 | return 1.0f; | ||
| 971 | #endif | ||
| 972 | #if GLFW_HAS_PER_MONITOR_DPI && !(defined(__APPLE__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__)) | ||
| 973 | float x_scale, y_scale; | ||
| 974 | glfwGetWindowContentScale(window, &x_scale, &y_scale); | ||
| 975 | return x_scale; | ||
| 976 | #else | ||
| 977 | IM_UNUSED(window); | ||
| 978 | return 1.0f; | ||
| 979 | #endif | ||
| 980 | } | ||
| 981 | |||
| 982 | float ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) | ||
| 983 | { | ||
| 984 | #if GLFW_HAS_WAYLAND | ||
| 985 | if (ImGui_ImplGlfw_IsWayland()) // We can't access our bd->IsWayland cache for a monitor. | ||
| 986 | return 1.0f; | ||
| 987 | #endif | ||
| 988 | #if GLFW_HAS_PER_MONITOR_DPI && !(defined(__APPLE__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__)) | ||
| 989 | float x_scale, y_scale; | ||
| 990 | glfwGetMonitorContentScale(monitor, &x_scale, &y_scale); | ||
| 991 | return x_scale; | ||
| 992 | #else | ||
| 993 | IM_UNUSED(monitor); | ||
| 994 | return 1.0f; | ||
| 995 | #endif | ||
| 996 | } | ||
| 997 | |||
| 998 | static void ImGui_ImplGlfw_GetWindowSizeAndFramebufferScale(GLFWwindow* window, ImVec2* out_size, ImVec2* out_framebuffer_scale) | ||
| 999 | { | ||
| 1000 | int w, h; | ||
| 1001 | int display_w, display_h; | ||
| 1002 | glfwGetWindowSize(window, &w, &h); | ||
| 1003 | glfwGetFramebufferSize(window, &display_w, &display_h); | ||
| 1004 | float fb_scale_x = (w > 0) ? (float)display_w / (float)w : 1.0f; | ||
| 1005 | float fb_scale_y = (h > 0) ? (float)display_h / (float)h : 1.0f; | ||
| 1006 | #if GLFW_HAS_WAYLAND | ||
| 1007 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); | ||
| 1008 | if (!bd->IsWayland) | ||
| 1009 | fb_scale_x = fb_scale_y = 1.0f; | ||
| 1010 | #endif | ||
| 1011 | if (out_size != nullptr) | ||
| 1012 | *out_size = ImVec2((float)w, (float)h); | ||
| 1013 | if (out_framebuffer_scale != nullptr) | ||
| 1014 | *out_framebuffer_scale = ImVec2(fb_scale_x, fb_scale_y); | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | void ImGui_ImplGlfw_NewFrame() | ||
| 1018 | { | ||
| 1019 | ImGuiIO& io = ImGui::GetIO(); | ||
| 1020 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | ||
| 1021 | IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplGlfw_InitForXXX()?"); | ||
| 1022 | |||
| 1023 | // Setup main viewport size (every frame to accommodate for window resizing) | ||
| 1024 | ImGui_ImplGlfw_GetWindowSizeAndFramebufferScale(bd->Window, &io.DisplaySize, &io.DisplayFramebufferScale); | ||
| 1025 | |||
| 1026 | // Setup time step | ||
| 1027 | // (Accept glfwGetTime() not returning a monotonically increasing value. Seems to happens on disconnecting peripherals and probably on VMs and Emscripten, see #6491, #6189, #6114, #3644) | ||
| 1028 | double current_time = glfwGetTime(); | ||
| 1029 | if (current_time <= bd->Time) | ||
| 1030 | current_time = bd->Time + 0.00001; | ||
| 1031 | io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f); | ||
| 1032 | bd->Time = current_time; | ||
| 1033 | |||
| 1034 | ImGui_ImplGlfw_UpdateMouseData(); | ||
| 1035 | ImGui_ImplGlfw_UpdateMouseCursor(); | ||
| 1036 | |||
| 1037 | // Update game controllers (if enabled and available) | ||
| 1038 | ImGui_ImplGlfw_UpdateGamepads(); | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | // GLFW doesn't provide a portable sleep function | ||
| 1042 | void ImGui_ImplGlfw_Sleep(int milliseconds) | ||
| 1043 | { | ||
| 1044 | #ifdef _WIN32 | ||
| 1045 | ::Sleep(milliseconds); | ||
| 1046 | #else | ||
| 1047 | usleep(milliseconds * 1000); | ||
| 1048 | #endif | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 | ||
| 1052 | static EM_BOOL ImGui_ImplGlfw_OnCanvasSizeChange(int event_type, const EmscriptenUiEvent* event, void* user_data) | ||
| 1053 | { | ||
| 1054 | ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)user_data; | ||
| 1055 | double canvas_width, canvas_height; | ||
| 1056 | emscripten_get_element_css_size(bd->CanvasSelector, &canvas_width, &canvas_height); | ||
| 1057 | glfwSetWindowSize(bd->Window, (int)canvas_width, (int)canvas_height); | ||
| 1058 | return true; | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | static EM_BOOL ImGui_ImplEmscripten_FullscreenChangeCallback(int event_type, const EmscriptenFullscreenChangeEvent* event, void* user_data) | ||
| 1062 | { | ||
| 1063 | ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)user_data; | ||
| 1064 | double canvas_width, canvas_height; | ||
| 1065 | emscripten_get_element_css_size(bd->CanvasSelector, &canvas_width, &canvas_height); | ||
| 1066 | glfwSetWindowSize(bd->Window, (int)canvas_width, (int)canvas_height); | ||
| 1067 | return true; | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | // 'canvas_selector' is a CSS selector. The event listener is applied to the first element that matches the query. | ||
| 1071 | // STRING MUST PERSIST FOR THE APPLICATION DURATION. PLEASE USE A STRING LITERAL OR ENSURE POINTER WILL STAY VALID. | ||
| 1072 | void ImGui_ImplGlfw_InstallEmscriptenCallbacks(GLFWwindow*, const char* canvas_selector) | ||
| 1073 | { | ||
| 1074 | IM_ASSERT(canvas_selector != nullptr); | ||
| 1075 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | ||
| 1076 | IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplGlfw_InitForXXX()?"); | ||
| 1077 | |||
| 1078 | bd->CanvasSelector = canvas_selector; | ||
| 1079 | emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, bd, false, ImGui_ImplGlfw_OnCanvasSizeChange); | ||
| 1080 | emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, bd, false, ImGui_ImplEmscripten_FullscreenChangeCallback); | ||
| 1081 | |||
| 1082 | // Change the size of the GLFW window according to the size of the canvas | ||
| 1083 | ImGui_ImplGlfw_OnCanvasSizeChange(EMSCRIPTEN_EVENT_RESIZE, {}, bd); | ||
| 1084 | |||
| 1085 | // Register Emscripten Wheel callback to workaround issue in Emscripten GLFW Emulation (#6096) | ||
| 1086 | // We intentionally do not check 'if (install_callbacks)' here, as some users may set it to false and call GLFW callback themselves. | ||
| 1087 | // FIXME: May break chaining in case user registered their own Emscripten callback? | ||
| 1088 | emscripten_set_wheel_callback(bd->CanvasSelector, bd, false, ImGui_ImplEmscripten_WheelCallback); | ||
| 1089 | } | ||
| 1090 | #elif defined(EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3) | ||
| 1091 | // When using --use-port=contrib.glfw3 for the GLFW implementation, you can override the behavior of this call | ||
| 1092 | // by invoking emscripten_glfw_make_canvas_resizable afterward. | ||
| 1093 | // See https://github.com/pongasoft/emscripten-glfw/blob/master/docs/Usage.md#how-to-make-the-canvas-resizable-by-the-user for an explanation | ||
| 1094 | void ImGui_ImplGlfw_InstallEmscriptenCallbacks(GLFWwindow* window, const char* canvas_selector) | ||
| 1095 | { | ||
| 1096 | GLFWwindow* w = (GLFWwindow*)(EM_ASM_INT({ return Module.glfwGetWindow(UTF8ToString($0)); }, canvas_selector)); | ||
| 1097 | IM_ASSERT(window == w); // Sanity check | ||
| 1098 | IM_UNUSED(w); | ||
| 1099 | emscripten_glfw_make_canvas_resizable(window, "window", nullptr); | ||
| 1100 | } | ||
| 1101 | #endif // #ifdef EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 | ||
| 1102 | |||
| 1103 | //----------------------------------------------------------------------------- | ||
| 1104 | |||
| 1105 | #if defined(__clang__) | ||
| 1106 | #pragma clang diagnostic pop | ||
| 1107 | #endif | ||
| 1108 | |||
| 1109 | #endif // #ifndef IMGUI_DISABLE | ||