upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/imgui/imgui_impl_glfw.cpp
diff options
context:
space:
mode:
authorbitflash-coin <bookofshamers@outlook.com>2026-08-04 06:34:32 -0700
committerbitflash-coin <bookofshamers@outlook.com>2026-08-04 06:34:32 -0700
commit5ce650382352c1503f40abf08129ada69402af55 (patch)
tree6a18198901f1e2c4933f1ac53c9365eec512bf63 /src/imgui/imgui_impl_glfw.cpp
parentf34113291da7e5e3dc7d2468d4f9c212c05c584b (diff)
public commit
Diffstat (limited to 'src/imgui/imgui_impl_glfw.cpp')
-rw-r--r--src/imgui/imgui_impl_glfw.cpp1109
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.
187struct ImGui_ImplGlfw_WindowToContext { GLFWwindow* Window; ImGuiContext* Context; };
188static ImVector<ImGui_ImplGlfw_WindowToContext> g_ContextMap;
189static void ImGui_ImplGlfw_ContextMap_Add(GLFWwindow* window, ImGuiContext* ctx) { g_ContextMap.push_back(ImGui_ImplGlfw_WindowToContext{ window, ctx }); }
190static 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; } }
191static ImGuiContext* ImGui_ImplGlfw_ContextMap_Get(GLFWwindow* window) { for (ImGui_ImplGlfw_WindowToContext& entry : g_ContextMap) if (entry.Window == window) return entry.Context; return nullptr; }
192
193enum GlfwClientApi
194{
195 GlfwClientApi_OpenGL,
196 GlfwClientApi_Vulkan,
197 GlfwClientApi_Unknown, // Anything else fits here.
198};
199
200// GLFW data
201struct 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.
244namespace ImGui { extern ImGuiIO& GetIO(ImGuiContext*); }
245static 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}
250static 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
258static 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)
277ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode);
278ImGuiKey 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
408static 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
416static bool ImGui_ImplGlfw_ShouldChainCallback(ImGui_ImplGlfw_Data* bd, GLFWwindow* window)
417{
418 return bd->CallbacksChainForAllWindows ? true : (window == bd->Window);
419}
420
421void 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
433void 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()?
449static 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
482void 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
501void 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
511void 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)
524void 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
544void 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
554void 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
560static 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.
581static 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}
590static 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
610void 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
627void 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.
656void 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
664void ImGui_ImplGlfw_EmscriptenOpenURL(const char* url) { if (url) emscripten::glfw3::OpenURL(url); }
665#else
666EM_JS(void, ImGui_ImplGlfw_EmscriptenOpenURL, (const char* url), { url = url ? UTF8ToString(url) : null; if (url) window.open(url, '_blank'); });
667#endif
668#endif
669
670static 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
779bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
780{
781 return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
782}
783
784bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
785{
786 return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
787}
788
789bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
790{
791 return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
792}
793
794void 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
828static 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
859static 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
900static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; }
901static 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)
955static float ImGui_ImplWin32_GetLegacyDpiScale() { const HDC dc = ::GetDC(nullptr); UINT xdpi = ::GetDeviceCaps(dc, LOGPIXELSX); ::ReleaseDC(nullptr, dc); return (float)xdpi / 96.0f; }
956static void glfwGetWindowContentScale(GLFWwindow*, float* x_scale, float* y_scale) { *x_scale = *y_scale = ImGui_ImplWin32_GetLegacyDpiScale(); }
957static 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.
965float 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
982float 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
998static 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
1017void 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
1042void 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
1052static 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
1061static 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.
1072void 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
1094void 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