• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.1+)
5 
6 // Implemented features:
7 //  [X] Platform: Clipboard support.
8 //  [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
9 //  [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
10 //  [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
11 
12 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
13 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
14 // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
15 // Read online: https://github.com/ocornut/imgui/tree/master/docs
16 
17 // CHANGELOG
18 // (minor and older changes stripped away, please see git history for details)
19 //  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().
20 //  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().
21 //  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).
22 //  2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
23 //  2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
24 //  2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
25 //  2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
26 //  2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
27 //  2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
28 //  2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
29 //  2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
30 //  2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
31 //  2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
32 //  2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
33 //  2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
34 //  2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
35 //  2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
36 //  2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
37 //  2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
38 //  2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
39 //  2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
40 //  2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
41 //  2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
42 //  2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
43 
44 #include "imgui.h"
45 #include "imgui_impl_glfw.h"
46 
47 // GLFW
48 #include <GLFW/glfw3.h>
49 #ifdef _WIN32
50 #undef APIENTRY
51 #define GLFW_EXPOSE_NATIVE_WIN32
52 #include <GLFW/glfw3native.h>   // for glfwGetWin32Window
53 #endif
54 #define GLFW_HAS_WINDOW_TOPMOST       (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING
55 #define GLFW_HAS_WINDOW_HOVERED       (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED
56 #define GLFW_HAS_WINDOW_ALPHA         (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity
57 #define GLFW_HAS_PER_MONITOR_DPI      (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale
58 #define GLFW_HAS_VULKAN               (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface
59 #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?
60 #define GLFW_HAS_NEW_CURSORS          (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
61 #else
62 #define GLFW_HAS_NEW_CURSORS          (0)
63 #endif
64 
65 // GLFW data
66 enum GlfwClientApi
67 {
68     GlfwClientApi_Unknown,
69     GlfwClientApi_OpenGL,
70     GlfwClientApi_Vulkan
71 };
72 
73 struct ImGui_ImplGlfw_Data
74 {
75     GLFWwindow*             Window;
76     GlfwClientApi           ClientApi;
77     double                  Time;
78     GLFWwindow*             MouseWindow;
79     bool                    MouseJustPressed[ImGuiMouseButton_COUNT];
80     GLFWcursor*             MouseCursors[ImGuiMouseCursor_COUNT];
81     bool                    InstalledCallbacks;
82 
83     // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
84     GLFWwindowfocusfun      PrevUserCallbackWindowFocus;
85     GLFWcursorenterfun      PrevUserCallbackCursorEnter;
86     GLFWmousebuttonfun      PrevUserCallbackMousebutton;
87     GLFWscrollfun           PrevUserCallbackScroll;
88     GLFWkeyfun              PrevUserCallbackKey;
89     GLFWcharfun             PrevUserCallbackChar;
90     GLFWmonitorfun          PrevUserCallbackMonitor;
91 
ImGui_ImplGlfw_DataImGui_ImplGlfw_Data92     ImGui_ImplGlfw_Data()   { memset(this, 0, sizeof(*this)); }
93 };
94 
95 // Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
96 // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
97 // FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
98 // - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks
99 //   (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks.
100 // - 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.
101 // FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
ImGui_ImplGlfw_GetBackendData()102 static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData()
103 {
104     return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
105 }
106 
107 // Functions
ImGui_ImplGlfw_GetClipboardText(void * user_data)108 static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
109 {
110     return glfwGetClipboardString((GLFWwindow*)user_data);
111 }
112 
ImGui_ImplGlfw_SetClipboardText(void * user_data,const char * text)113 static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
114 {
115     glfwSetClipboardString((GLFWwindow*)user_data, text);
116 }
117 
ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow * window,int button,int action,int mods)118 void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
119 {
120     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
121     if (bd->PrevUserCallbackMousebutton != NULL && window == bd->Window)
122         bd->PrevUserCallbackMousebutton(window, button, action, mods);
123 
124     if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(bd->MouseJustPressed))
125         bd->MouseJustPressed[button] = true;
126 }
127 
ImGui_ImplGlfw_ScrollCallback(GLFWwindow * window,double xoffset,double yoffset)128 void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
129 {
130     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
131     if (bd->PrevUserCallbackScroll != NULL && window == bd->Window)
132         bd->PrevUserCallbackScroll(window, xoffset, yoffset);
133 
134     ImGuiIO& io = ImGui::GetIO();
135     io.MouseWheelH += (float)xoffset;
136     io.MouseWheel += (float)yoffset;
137 }
138 
ImGui_ImplGlfw_KeyCallback(GLFWwindow * window,int key,int scancode,int action,int mods)139 void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
140 {
141     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
142     if (bd->PrevUserCallbackKey != NULL && window == bd->Window)
143         bd->PrevUserCallbackKey(window, key, scancode, action, mods);
144 
145     ImGuiIO& io = ImGui::GetIO();
146     if (key >= 0 && key < IM_ARRAYSIZE(io.KeysDown))
147     {
148         if (action == GLFW_PRESS)
149             io.KeysDown[key] = true;
150         if (action == GLFW_RELEASE)
151             io.KeysDown[key] = false;
152     }
153 
154     // Modifiers are not reliable across systems
155     io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
156     io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
157     io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
158 #ifdef _WIN32
159     io.KeySuper = false;
160 #else
161     io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
162 #endif
163 }
164 
ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow * window,int focused)165 void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
166 {
167     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
168     if (bd->PrevUserCallbackWindowFocus != NULL && window == bd->Window)
169         bd->PrevUserCallbackWindowFocus(window, focused);
170 
171     ImGuiIO& io = ImGui::GetIO();
172     io.AddFocusEvent(focused != 0);
173 }
174 
ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow * window,int entered)175 void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
176 {
177     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
178     if (bd->PrevUserCallbackCursorEnter != NULL && window == bd->Window)
179         bd->PrevUserCallbackCursorEnter(window, entered);
180 
181     if (entered)
182         bd->MouseWindow = window;
183     if (!entered && bd->MouseWindow == window)
184         bd->MouseWindow = NULL;
185 }
186 
ImGui_ImplGlfw_CharCallback(GLFWwindow * window,unsigned int c)187 void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
188 {
189     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
190     if (bd->PrevUserCallbackChar != NULL && window == bd->Window)
191         bd->PrevUserCallbackChar(window, c);
192 
193     ImGuiIO& io = ImGui::GetIO();
194     io.AddInputCharacter(c);
195 }
196 
ImGui_ImplGlfw_MonitorCallback(GLFWmonitor *,int)197 void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
198 {
199 	// 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.
200 }
201 
ImGui_ImplGlfw_Init(GLFWwindow * window,bool install_callbacks,GlfwClientApi client_api)202 static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
203 {
204     ImGuiIO& io = ImGui::GetIO();
205     IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
206 
207     // Setup backend capabilities flags
208     ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)();
209     io.BackendPlatformUserData = (void*)bd;
210     io.BackendPlatformName = "imgui_impl_glfw";
211     io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;         // We can honor GetMouseCursor() values (optional)
212     io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;          // We can honor io.WantSetMousePos requests (optional, rarely used)
213 
214     bd->Window = window;
215     bd->Time = 0.0;
216 
217     // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
218     io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
219     io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
220     io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
221     io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
222     io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
223     io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
224     io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
225     io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
226     io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
227     io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
228     io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
229     io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
230     io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
231     io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
232     io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
233     io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
234     io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
235     io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
236     io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
237     io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
238     io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
239     io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
240 
241     io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
242     io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
243     io.ClipboardUserData = bd->Window;
244 #if defined(_WIN32)
245     io.ImeWindowHandle = (void*)glfwGetWin32Window(bd->Window);
246 #endif
247 
248     // Create mouse cursors
249     // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
250     // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
251     // Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
252     GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
253     bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
254     bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
255     bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
256     bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
257     bd->MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
258 #if GLFW_HAS_NEW_CURSORS
259     bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
260     bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
261     bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
262     bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
263 #else
264     bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
265     bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
266     bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
267     bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
268 #endif
269     glfwSetErrorCallback(prev_error_callback);
270 
271     // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
272     bd->PrevUserCallbackWindowFocus = NULL;
273     bd->PrevUserCallbackMousebutton = NULL;
274     bd->PrevUserCallbackScroll = NULL;
275     bd->PrevUserCallbackKey = NULL;
276     bd->PrevUserCallbackChar = NULL;
277     bd->PrevUserCallbackMonitor = NULL;
278     if (install_callbacks)
279     {
280         bd->InstalledCallbacks = true;
281         bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback);
282         bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback);
283         bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
284         bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
285         bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
286         bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
287         bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
288     }
289 
290     bd->ClientApi = client_api;
291     return true;
292 }
293 
ImGui_ImplGlfw_InitForOpenGL(GLFWwindow * window,bool install_callbacks)294 bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
295 {
296     return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
297 }
298 
ImGui_ImplGlfw_InitForVulkan(GLFWwindow * window,bool install_callbacks)299 bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
300 {
301     return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
302 }
303 
ImGui_ImplGlfw_InitForOther(GLFWwindow * window,bool install_callbacks)304 bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
305 {
306     return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
307 }
308 
ImGui_ImplGlfw_Shutdown()309 void ImGui_ImplGlfw_Shutdown()
310 {
311     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
312     IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
313     ImGuiIO& io = ImGui::GetIO();
314 
315     if (bd->InstalledCallbacks)
316     {
317         glfwSetWindowFocusCallback(bd->Window, bd->PrevUserCallbackWindowFocus);
318         glfwSetCursorEnterCallback(bd->Window, bd->PrevUserCallbackCursorEnter);
319         glfwSetMouseButtonCallback(bd->Window, bd->PrevUserCallbackMousebutton);
320         glfwSetScrollCallback(bd->Window, bd->PrevUserCallbackScroll);
321         glfwSetKeyCallback(bd->Window, bd->PrevUserCallbackKey);
322         glfwSetCharCallback(bd->Window, bd->PrevUserCallbackChar);
323         glfwSetMonitorCallback(bd->PrevUserCallbackMonitor);
324     }
325 
326     for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
327         glfwDestroyCursor(bd->MouseCursors[cursor_n]);
328 
329     io.BackendPlatformName = NULL;
330     io.BackendPlatformUserData = NULL;
331     IM_DELETE(bd);
332 }
333 
ImGui_ImplGlfw_UpdateMousePosAndButtons()334 static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
335 {
336     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
337     ImGuiIO& io = ImGui::GetIO();
338 
339     const ImVec2 mouse_pos_prev = io.MousePos;
340     io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
341 
342     // Update mouse buttons
343     // (if a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame)
344     for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
345     {
346         io.MouseDown[i] = bd->MouseJustPressed[i] || glfwGetMouseButton(bd->Window, i) != 0;
347         bd->MouseJustPressed[i] = false;
348     }
349 
350 #ifdef __EMSCRIPTEN__
351     const bool focused = true;
352 #else
353     const bool focused = glfwGetWindowAttrib(bd->Window, GLFW_FOCUSED) != 0;
354 #endif
355     GLFWwindow* mouse_window = (bd->MouseWindow == bd->Window || focused) ? bd->Window : NULL;
356 
357     // Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
358     if (io.WantSetMousePos && focused)
359         glfwSetCursorPos(bd->Window, (double)mouse_pos_prev.x, (double)mouse_pos_prev.y);
360 
361     // Set Dear ImGui mouse position from OS position
362     if (mouse_window != NULL)
363     {
364         double mouse_x, mouse_y;
365         glfwGetCursorPos(mouse_window, &mouse_x, &mouse_y);
366         io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
367     }
368 }
369 
ImGui_ImplGlfw_UpdateMouseCursor()370 static void ImGui_ImplGlfw_UpdateMouseCursor()
371 {
372     ImGuiIO& io = ImGui::GetIO();
373     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
374     if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
375         return;
376 
377     ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
378     if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
379     {
380         // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
381         glfwSetInputMode(bd->Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
382     }
383     else
384     {
385         // Show OS mouse cursor
386         // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
387         glfwSetCursor(bd->Window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
388         glfwSetInputMode(bd->Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
389     }
390 }
391 
ImGui_ImplGlfw_UpdateGamepads()392 static void ImGui_ImplGlfw_UpdateGamepads()
393 {
394     ImGuiIO& io = ImGui::GetIO();
395     memset(io.NavInputs, 0, sizeof(io.NavInputs));
396     if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
397         return;
398 
399     // Update gamepad inputs
400     #define MAP_BUTTON(NAV_NO, BUTTON_NO)       { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
401     #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
402     int axes_count = 0, buttons_count = 0;
403     const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
404     const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
405     MAP_BUTTON(ImGuiNavInput_Activate,   0);     // Cross / A
406     MAP_BUTTON(ImGuiNavInput_Cancel,     1);     // Circle / B
407     MAP_BUTTON(ImGuiNavInput_Menu,       2);     // Square / X
408     MAP_BUTTON(ImGuiNavInput_Input,      3);     // Triangle / Y
409     MAP_BUTTON(ImGuiNavInput_DpadLeft,   13);    // D-Pad Left
410     MAP_BUTTON(ImGuiNavInput_DpadRight,  11);    // D-Pad Right
411     MAP_BUTTON(ImGuiNavInput_DpadUp,     10);    // D-Pad Up
412     MAP_BUTTON(ImGuiNavInput_DpadDown,   12);    // D-Pad Down
413     MAP_BUTTON(ImGuiNavInput_FocusPrev,  4);     // L1 / LB
414     MAP_BUTTON(ImGuiNavInput_FocusNext,  5);     // R1 / RB
415     MAP_BUTTON(ImGuiNavInput_TweakSlow,  4);     // L1 / LB
416     MAP_BUTTON(ImGuiNavInput_TweakFast,  5);     // R1 / RB
417     MAP_ANALOG(ImGuiNavInput_LStickLeft, 0,  -0.3f,  -0.9f);
418     MAP_ANALOG(ImGuiNavInput_LStickRight,0,  +0.3f,  +0.9f);
419     MAP_ANALOG(ImGuiNavInput_LStickUp,   1,  +0.3f,  +0.9f);
420     MAP_ANALOG(ImGuiNavInput_LStickDown, 1,  -0.3f,  -0.9f);
421     #undef MAP_BUTTON
422     #undef MAP_ANALOG
423     if (axes_count > 0 && buttons_count > 0)
424         io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
425     else
426         io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
427 }
428 
ImGui_ImplGlfw_NewFrame()429 void ImGui_ImplGlfw_NewFrame()
430 {
431     ImGuiIO& io = ImGui::GetIO();
432     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
433     IM_ASSERT(bd != NULL && "Did you call ImGui_ImplGlfw_InitForXXX()?");
434 
435     // Setup display size (every frame to accommodate for window resizing)
436     int w, h;
437     int display_w, display_h;
438     glfwGetWindowSize(bd->Window, &w, &h);
439     glfwGetFramebufferSize(bd->Window, &display_w, &display_h);
440     io.DisplaySize = ImVec2((float)w, (float)h);
441     if (w > 0 && h > 0)
442         io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
443 
444     // Setup time step
445     double current_time = glfwGetTime();
446     io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
447     bd->Time = current_time;
448 
449     ImGui_ImplGlfw_UpdateMousePosAndButtons();
450     ImGui_ImplGlfw_UpdateMouseCursor();
451 
452     // Update game controllers (if enabled and available)
453     ImGui_ImplGlfw_UpdateGamepads();
454 }
455