imgui_impl_glfw.cpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  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+. Prefer GLFW 3.3+ for full feature support.)
  5. // Implemented features:
  6. // [X] Platform: Clipboard support.
  7. // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
  8. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
  9. // [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
  10. // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
  11. // Issues:
  12. // [ ] Platform: Multi-viewport support: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
  13. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
  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. // CHANGELOG
  17. // (minor and older changes stripped away, please see git history for details)
  18. // 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
  19. // 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
  20. // 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
  21. // 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
  22. // 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
  23. // 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
  24. // 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
  25. // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
  26. // 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
  27. // 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
  28. // 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
  29. // 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
  30. // 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
  31. // 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
  32. // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
  33. // 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
  34. // 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
  35. // 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
  36. // 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
  37. // 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
  38. // 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
  39. // 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
  40. #include "imgui.h"
  41. #include "imgui_impl_glfw.h"
  42. // GLFW
  43. #include <GLFW/glfw3.h>
  44. #ifdef _WIN32
  45. #undef APIENTRY
  46. #define GLFW_EXPOSE_NATIVE_WIN32
  47. #include <GLFW/glfw3native.h> // for glfwGetWin32Window
  48. #endif
  49. #define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING
  50. #define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED
  51. #define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity
  52. #define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale
  53. #define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface
  54. #define GLFW_HAS_FOCUS_WINDOW (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwFocusWindow
  55. #define GLFW_HAS_FOCUS_ON_SHOW (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_FOCUS_ON_SHOW
  56. #define GLFW_HAS_MONITOR_WORK_AREA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorWorkarea
  57. #define GLFW_HAS_OSX_WINDOW_POS_FIX (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION * 10 >= 3310) // 3.3.1+ Fixed: Resizing window repositions it on MacOS #1553
  58. #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?
  59. #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
  60. #else
  61. #define GLFW_HAS_NEW_CURSORS (0)
  62. #endif
  63. #ifdef GLFW_MOUSE_PASSTHROUGH // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2020-07-17 (passthrough)
  64. #define GLFW_HAS_MOUSE_PASSTHROUGH (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_MOUSE_PASSTHROUGH
  65. #else
  66. #define GLFW_HAS_MOUSE_PASSTHROUGH (0)
  67. #endif
  68. // Data
  69. enum GlfwClientApi
  70. {
  71. GlfwClientApi_Unknown,
  72. GlfwClientApi_OpenGL,
  73. GlfwClientApi_Vulkan
  74. };
  75. static GLFWwindow* g_Window = NULL; // Main window
  76. static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
  77. static double g_Time = 0.0;
  78. static bool g_MouseJustPressed[ImGuiMouseButton_COUNT] = {};
  79. static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
  80. static bool g_InstalledCallbacks = false;
  81. static bool g_WantUpdateMonitors = true;
  82. // Chain GLFW callbacks for main viewport: our callbacks will call the user's previously installed callbacks, if any.
  83. static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL;
  84. static GLFWscrollfun g_PrevUserCallbackScroll = NULL;
  85. static GLFWkeyfun g_PrevUserCallbackKey = NULL;
  86. static GLFWcharfun g_PrevUserCallbackChar = NULL;
  87. static GLFWmonitorfun g_PrevUserCallbackMonitor = NULL;
  88. // Forward Declarations
  89. static void ImGui_ImplGlfw_UpdateMonitors();
  90. static void ImGui_ImplGlfw_InitPlatformInterface();
  91. static void ImGui_ImplGlfw_ShutdownPlatformInterface();
  92. static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
  93. {
  94. return glfwGetClipboardString((GLFWwindow*)user_data);
  95. }
  96. static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
  97. {
  98. glfwSetClipboardString((GLFWwindow*)user_data, text);
  99. }
  100. void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
  101. {
  102. if (g_PrevUserCallbackMousebutton != NULL && window == g_Window)
  103. g_PrevUserCallbackMousebutton(window, button, action, mods);
  104. if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
  105. g_MouseJustPressed[button] = true;
  106. }
  107. void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
  108. {
  109. if (g_PrevUserCallbackScroll != NULL && window == g_Window)
  110. g_PrevUserCallbackScroll(window, xoffset, yoffset);
  111. ImGuiIO& io = ImGui::GetIO();
  112. io.MouseWheelH += (float)xoffset;
  113. io.MouseWheel += (float)yoffset;
  114. }
  115. void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
  116. {
  117. if (g_PrevUserCallbackKey != NULL && window == g_Window)
  118. g_PrevUserCallbackKey(window, key, scancode, action, mods);
  119. ImGuiIO& io = ImGui::GetIO();
  120. if (action == GLFW_PRESS)
  121. io.KeysDown[key] = true;
  122. if (action == GLFW_RELEASE)
  123. io.KeysDown[key] = false;
  124. // Modifiers are not reliable across systems
  125. io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
  126. io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
  127. io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
  128. #ifdef _WIN32
  129. io.KeySuper = false;
  130. #else
  131. io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
  132. #endif
  133. }
  134. void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
  135. {
  136. if (g_PrevUserCallbackChar != NULL && window == g_Window)
  137. g_PrevUserCallbackChar(window, c);
  138. ImGuiIO& io = ImGui::GetIO();
  139. io.AddInputCharacter(c);
  140. }
  141. void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
  142. {
  143. g_WantUpdateMonitors = true;
  144. }
  145. static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
  146. {
  147. g_Window = window;
  148. g_Time = 0.0;
  149. // Setup backend capabilities flags
  150. ImGuiIO& io = ImGui::GetIO();
  151. io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
  152. io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
  153. io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
  154. #if GLFW_HAS_MOUSE_PASSTHROUGH || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32))
  155. io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy)
  156. #endif
  157. io.BackendPlatformName = "imgui_impl_glfw";
  158. // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
  159. io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
  160. io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
  161. io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
  162. io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
  163. io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
  164. io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
  165. io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
  166. io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
  167. io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
  168. io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
  169. io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
  170. io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
  171. io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
  172. io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
  173. io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
  174. io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
  175. io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
  176. io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
  177. io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
  178. io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
  179. io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
  180. io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
  181. io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
  182. io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
  183. io.ClipboardUserData = g_Window;
  184. // Create mouse cursors
  185. // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
  186. // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
  187. // Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
  188. GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
  189. g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
  190. g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
  191. g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
  192. g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
  193. g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
  194. #if GLFW_HAS_NEW_CURSORS
  195. g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
  196. g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
  197. g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
  198. g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
  199. #else
  200. g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
  201. g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
  202. g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
  203. g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
  204. #endif
  205. glfwSetErrorCallback(prev_error_callback);
  206. // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
  207. g_PrevUserCallbackMousebutton = NULL;
  208. g_PrevUserCallbackScroll = NULL;
  209. g_PrevUserCallbackKey = NULL;
  210. g_PrevUserCallbackChar = NULL;
  211. g_PrevUserCallbackMonitor = NULL;
  212. if (install_callbacks)
  213. {
  214. g_InstalledCallbacks = true;
  215. g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
  216. g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
  217. g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
  218. g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
  219. g_PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
  220. }
  221. // Update monitors the first time (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784)
  222. ImGui_ImplGlfw_UpdateMonitors();
  223. glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
  224. // Our mouse update function expect PlatformHandle to be filled for the main viewport
  225. ImGuiViewport* main_viewport = ImGui::GetMainViewport();
  226. main_viewport->PlatformHandle = (void*)g_Window;
  227. #ifdef _WIN32
  228. main_viewport->PlatformHandleRaw = glfwGetWin32Window(g_Window);
  229. #endif
  230. if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
  231. ImGui_ImplGlfw_InitPlatformInterface();
  232. g_ClientApi = client_api;
  233. return true;
  234. }
  235. bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
  236. {
  237. return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
  238. }
  239. bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
  240. {
  241. return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
  242. }
  243. bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
  244. {
  245. return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
  246. }
  247. void ImGui_ImplGlfw_Shutdown()
  248. {
  249. ImGui_ImplGlfw_ShutdownPlatformInterface();
  250. if (g_InstalledCallbacks)
  251. {
  252. glfwSetMouseButtonCallback(g_Window, g_PrevUserCallbackMousebutton);
  253. glfwSetScrollCallback(g_Window, g_PrevUserCallbackScroll);
  254. glfwSetKeyCallback(g_Window, g_PrevUserCallbackKey);
  255. glfwSetCharCallback(g_Window, g_PrevUserCallbackChar);
  256. g_InstalledCallbacks = false;
  257. }
  258. for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
  259. {
  260. glfwDestroyCursor(g_MouseCursors[cursor_n]);
  261. g_MouseCursors[cursor_n] = NULL;
  262. }
  263. g_ClientApi = GlfwClientApi_Unknown;
  264. }
  265. static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
  266. {
  267. // Update buttons
  268. ImGuiIO& io = ImGui::GetIO();
  269. for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
  270. {
  271. // 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.
  272. io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0;
  273. g_MouseJustPressed[i] = false;
  274. }
  275. // Update mouse position
  276. const ImVec2 mouse_pos_backup = io.MousePos;
  277. io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
  278. io.MouseHoveredViewport = 0;
  279. ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
  280. for (int n = 0; n < platform_io.Viewports.Size; n++)
  281. {
  282. ImGuiViewport* viewport = platform_io.Viewports[n];
  283. GLFWwindow* window = (GLFWwindow*)viewport->PlatformHandle;
  284. IM_ASSERT(window != NULL);
  285. #ifdef __EMSCRIPTEN__
  286. const bool focused = true;
  287. IM_ASSERT(platform_io.Viewports.Size == 1);
  288. #else
  289. const bool focused = glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0;
  290. #endif
  291. if (focused)
  292. {
  293. if (io.WantSetMousePos)
  294. {
  295. glfwSetCursorPos(window, (double)(mouse_pos_backup.x - viewport->Pos.x), (double)(mouse_pos_backup.y - viewport->Pos.y));
  296. }
  297. else
  298. {
  299. double mouse_x, mouse_y;
  300. glfwGetCursorPos(window, &mouse_x, &mouse_y);
  301. if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
  302. {
  303. // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
  304. int window_x, window_y;
  305. glfwGetWindowPos(window, &window_x, &window_y);
  306. io.MousePos = ImVec2((float)mouse_x + window_x, (float)mouse_y + window_y);
  307. }
  308. else
  309. {
  310. // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
  311. io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
  312. }
  313. }
  314. for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
  315. io.MouseDown[i] |= glfwGetMouseButton(window, i) != 0;
  316. }
  317. // (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering.
  318. // Important: this information is not easy to provide and many high-level windowing library won't be able to provide it correctly, because
  319. // - This is _ignoring_ viewports with the ImGuiViewportFlags_NoInputs flag (pass-through windows).
  320. // - This is _regardless_ of whether another viewport is focused or being dragged from.
  321. // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, imgui will ignore this field and infer the information by relying on the
  322. // rectangles and last focused time of every viewports it knows about. It will be unaware of other windows that may be sitting between or over your windows.
  323. // [GLFW] FIXME: This is currently only correct on Win32. See what we do below with the WM_NCHITTEST, missing an equivalent for other systems.
  324. // See https://github.com/glfw/glfw/issues/1236 if you want to help in making this a GLFW feature.
  325. #if GLFW_HAS_MOUSE_PASSTHROUGH || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32))
  326. const bool window_no_input = (viewport->Flags & ImGuiViewportFlags_NoInputs) != 0;
  327. #if GLFW_HAS_MOUSE_PASSTHROUGH
  328. glfwSetWindowAttrib(window, GLFW_MOUSE_PASSTHROUGH, window_no_input);
  329. #endif
  330. if (glfwGetWindowAttrib(window, GLFW_HOVERED) && !window_no_input)
  331. io.MouseHoveredViewport = viewport->ID;
  332. #endif
  333. }
  334. }
  335. static void ImGui_ImplGlfw_UpdateMouseCursor()
  336. {
  337. ImGuiIO& io = ImGui::GetIO();
  338. if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
  339. return;
  340. ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
  341. ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
  342. for (int n = 0; n < platform_io.Viewports.Size; n++)
  343. {
  344. GLFWwindow* window = (GLFWwindow*)platform_io.Viewports[n]->PlatformHandle;
  345. if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
  346. {
  347. // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
  348. glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
  349. }
  350. else
  351. {
  352. // Show OS mouse cursor
  353. // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
  354. glfwSetCursor(window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
  355. glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
  356. }
  357. }
  358. }
  359. static void ImGui_ImplGlfw_UpdateGamepads()
  360. {
  361. ImGuiIO& io = ImGui::GetIO();
  362. memset(io.NavInputs, 0, sizeof(io.NavInputs));
  363. if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
  364. return;
  365. // Update gamepad inputs
  366. #define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
  367. #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; }
  368. int axes_count = 0, buttons_count = 0;
  369. const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
  370. const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
  371. MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
  372. MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
  373. MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
  374. MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
  375. MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
  376. MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
  377. MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
  378. MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
  379. MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
  380. MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
  381. MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
  382. MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
  383. MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
  384. MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
  385. MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
  386. MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
  387. #undef MAP_BUTTON
  388. #undef MAP_ANALOG
  389. if (axes_count > 0 && buttons_count > 0)
  390. io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
  391. else
  392. io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
  393. }
  394. static void ImGui_ImplGlfw_UpdateMonitors()
  395. {
  396. ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
  397. int monitors_count = 0;
  398. GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count);
  399. platform_io.Monitors.resize(0);
  400. for (int n = 0; n < monitors_count; n++)
  401. {
  402. ImGuiPlatformMonitor monitor;
  403. int x, y;
  404. glfwGetMonitorPos(glfw_monitors[n], &x, &y);
  405. const GLFWvidmode* vid_mode = glfwGetVideoMode(glfw_monitors[n]);
  406. monitor.MainPos = monitor.WorkPos = ImVec2((float)x, (float)y);
  407. monitor.MainSize = monitor.WorkSize = ImVec2((float)vid_mode->width, (float)vid_mode->height);
  408. #if GLFW_HAS_MONITOR_WORK_AREA
  409. int w, h;
  410. glfwGetMonitorWorkarea(glfw_monitors[n], &x, &y, &w, &h);
  411. if (w > 0 && h > 0) // Workaround a small GLFW issue reporting zero on monitor changes: https://github.com/glfw/glfw/pull/1761
  412. {
  413. monitor.WorkPos = ImVec2((float)x, (float)y);
  414. monitor.WorkSize = ImVec2((float)w, (float)h);
  415. }
  416. #endif
  417. #if GLFW_HAS_PER_MONITOR_DPI
  418. // Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime.
  419. float x_scale, y_scale;
  420. glfwGetMonitorContentScale(glfw_monitors[n], &x_scale, &y_scale);
  421. monitor.DpiScale = x_scale;
  422. #endif
  423. platform_io.Monitors.push_back(monitor);
  424. }
  425. g_WantUpdateMonitors = false;
  426. }
  427. void ImGui_ImplGlfw_NewFrame()
  428. {
  429. ImGuiIO& io = ImGui::GetIO();
  430. IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
  431. // Setup display size (every frame to accommodate for window resizing)
  432. int w, h;
  433. int display_w, display_h;
  434. glfwGetWindowSize(g_Window, &w, &h);
  435. glfwGetFramebufferSize(g_Window, &display_w, &display_h);
  436. io.DisplaySize = ImVec2((float)w, (float)h);
  437. if (w > 0 && h > 0)
  438. io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
  439. if (g_WantUpdateMonitors)
  440. ImGui_ImplGlfw_UpdateMonitors();
  441. // Setup time step
  442. double current_time = glfwGetTime();
  443. io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
  444. g_Time = current_time;
  445. ImGui_ImplGlfw_UpdateMousePosAndButtons();
  446. ImGui_ImplGlfw_UpdateMouseCursor();
  447. // Update game controllers (if enabled and available)
  448. ImGui_ImplGlfw_UpdateGamepads();
  449. }
  450. //--------------------------------------------------------------------------------------------------------
  451. // MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
  452. // This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
  453. // If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
  454. //--------------------------------------------------------------------------------------------------------
  455. // Helper structure we store in the void* RenderUserData field of each ImGuiViewport to easily retrieve our backend data.
  456. struct ImGuiViewportDataGlfw
  457. {
  458. GLFWwindow* Window;
  459. bool WindowOwned;
  460. int IgnoreWindowPosEventFrame;
  461. int IgnoreWindowSizeEventFrame;
  462. ImGuiViewportDataGlfw() { Window = NULL; WindowOwned = false; IgnoreWindowSizeEventFrame = IgnoreWindowPosEventFrame = -1; }
  463. ~ImGuiViewportDataGlfw() { IM_ASSERT(Window == NULL); }
  464. };
  465. static void ImGui_ImplGlfw_WindowCloseCallback(GLFWwindow* window)
  466. {
  467. if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
  468. viewport->PlatformRequestClose = true;
  469. }
  470. // GLFW may dispatch window pos/size events after calling glfwSetWindowPos()/glfwSetWindowSize().
  471. // However: depending on the platform the callback may be invoked at different time:
  472. // - on Windows it appears to be called within the glfwSetWindowPos()/glfwSetWindowSize() call
  473. // - on Linux it is queued and invoked during glfwPollEvents()
  474. // Because the event doesn't always fire on glfwSetWindowXXX() we use a frame counter tag to only
  475. // ignore recent glfwSetWindowXXX() calls.
  476. static void ImGui_ImplGlfw_WindowPosCallback(GLFWwindow* window, int, int)
  477. {
  478. if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
  479. {
  480. if (ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData)
  481. {
  482. bool ignore_event = (ImGui::GetFrameCount() <= data->IgnoreWindowPosEventFrame + 1);
  483. //data->IgnoreWindowPosEventFrame = -1;
  484. if (ignore_event)
  485. return;
  486. }
  487. viewport->PlatformRequestMove = true;
  488. }
  489. }
  490. static void ImGui_ImplGlfw_WindowSizeCallback(GLFWwindow* window, int, int)
  491. {
  492. if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
  493. {
  494. if (ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData)
  495. {
  496. bool ignore_event = (ImGui::GetFrameCount() <= data->IgnoreWindowSizeEventFrame + 1);
  497. //data->IgnoreWindowSizeEventFrame = -1;
  498. if (ignore_event)
  499. return;
  500. }
  501. viewport->PlatformRequestResize = true;
  502. }
  503. }
  504. static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport)
  505. {
  506. ImGuiViewportDataGlfw* data = IM_NEW(ImGuiViewportDataGlfw)();
  507. viewport->PlatformUserData = data;
  508. // GLFW 3.2 unfortunately always set focus on glfwCreateWindow() if GLFW_VISIBLE is set, regardless of GLFW_FOCUSED
  509. // With GLFW 3.3, the hint GLFW_FOCUS_ON_SHOW fixes this problem
  510. glfwWindowHint(GLFW_VISIBLE, false);
  511. glfwWindowHint(GLFW_FOCUSED, false);
  512. #if GLFW_HAS_FOCUS_ON_SHOW
  513. glfwWindowHint(GLFW_FOCUS_ON_SHOW, false);
  514. #endif
  515. glfwWindowHint(GLFW_DECORATED, (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? false : true);
  516. #if GLFW_HAS_WINDOW_TOPMOST
  517. glfwWindowHint(GLFW_FLOATING, (viewport->Flags & ImGuiViewportFlags_TopMost) ? true : false);
  518. #endif
  519. GLFWwindow* share_window = (g_ClientApi == GlfwClientApi_OpenGL) ? g_Window : NULL;
  520. data->Window = glfwCreateWindow((int)viewport->Size.x, (int)viewport->Size.y, "No Title Yet", NULL, share_window);
  521. data->WindowOwned = true;
  522. viewport->PlatformHandle = (void*)data->Window;
  523. #ifdef _WIN32
  524. viewport->PlatformHandleRaw = glfwGetWin32Window(data->Window);
  525. #endif
  526. glfwSetWindowPos(data->Window, (int)viewport->Pos.x, (int)viewport->Pos.y);
  527. // Install GLFW callbacks for secondary viewports
  528. glfwSetMouseButtonCallback(data->Window, ImGui_ImplGlfw_MouseButtonCallback);
  529. glfwSetScrollCallback(data->Window, ImGui_ImplGlfw_ScrollCallback);
  530. glfwSetKeyCallback(data->Window, ImGui_ImplGlfw_KeyCallback);
  531. glfwSetCharCallback(data->Window, ImGui_ImplGlfw_CharCallback);
  532. glfwSetWindowCloseCallback(data->Window, ImGui_ImplGlfw_WindowCloseCallback);
  533. glfwSetWindowPosCallback(data->Window, ImGui_ImplGlfw_WindowPosCallback);
  534. glfwSetWindowSizeCallback(data->Window, ImGui_ImplGlfw_WindowSizeCallback);
  535. if (g_ClientApi == GlfwClientApi_OpenGL)
  536. {
  537. glfwMakeContextCurrent(data->Window);
  538. glfwSwapInterval(0);
  539. }
  540. }
  541. static void ImGui_ImplGlfw_DestroyWindow(ImGuiViewport* viewport)
  542. {
  543. if (ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData)
  544. {
  545. if (data->WindowOwned)
  546. {
  547. #if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)
  548. HWND hwnd = (HWND)viewport->PlatformHandleRaw;
  549. ::RemovePropA(hwnd, "IMGUI_VIEWPORT");
  550. #endif
  551. glfwDestroyWindow(data->Window);
  552. }
  553. data->Window = NULL;
  554. IM_DELETE(data);
  555. }
  556. viewport->PlatformUserData = viewport->PlatformHandle = NULL;
  557. }
  558. // We have submitted https://github.com/glfw/glfw/pull/1568 to allow GLFW to support "transparent inputs".
  559. // In the meanwhile we implement custom per-platform workarounds here (FIXME-VIEWPORT: Implement same work-around for Linux/OSX!)
  560. #if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)
  561. static WNDPROC g_GlfwWndProc = NULL;
  562. static LRESULT CALLBACK WndProcNoInputs(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  563. {
  564. if (msg == WM_NCHITTEST)
  565. {
  566. // Let mouse pass-through the window. This will allow the backend to set io.MouseHoveredViewport properly (which is OPTIONAL).
  567. // The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
  568. // If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
  569. // your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
  570. ImGuiViewport* viewport = (ImGuiViewport*)::GetPropA(hWnd, "IMGUI_VIEWPORT");
  571. if (viewport->Flags & ImGuiViewportFlags_NoInputs)
  572. return HTTRANSPARENT;
  573. }
  574. return ::CallWindowProc(g_GlfwWndProc, hWnd, msg, wParam, lParam);
  575. }
  576. #endif
  577. static void ImGui_ImplGlfw_ShowWindow(ImGuiViewport* viewport)
  578. {
  579. ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData;
  580. #if defined(_WIN32)
  581. // GLFW hack: Hide icon from task bar
  582. HWND hwnd = (HWND)viewport->PlatformHandleRaw;
  583. if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon)
  584. {
  585. LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
  586. ex_style &= ~WS_EX_APPWINDOW;
  587. ex_style |= WS_EX_TOOLWINDOW;
  588. ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
  589. }
  590. // GLFW hack: install hook for WM_NCHITTEST message handler
  591. #if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)
  592. ::SetPropA(hwnd, "IMGUI_VIEWPORT", viewport);
  593. if (g_GlfwWndProc == NULL)
  594. g_GlfwWndProc = (WNDPROC)::GetWindowLongPtr(hwnd, GWLP_WNDPROC);
  595. ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)WndProcNoInputs);
  596. #endif
  597. #if !GLFW_HAS_FOCUS_ON_SHOW
  598. // GLFW hack: GLFW 3.2 has a bug where glfwShowWindow() also activates/focus the window.
  599. // The fix was pushed to GLFW repository on 2018/01/09 and should be included in GLFW 3.3 via a GLFW_FOCUS_ON_SHOW window attribute.
  600. // See https://github.com/glfw/glfw/issues/1189
  601. // FIXME-VIEWPORT: Implement same work-around for Linux/OSX in the meanwhile.
  602. if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
  603. {
  604. ::ShowWindow(hwnd, SW_SHOWNA);
  605. return;
  606. }
  607. #endif
  608. #endif
  609. glfwShowWindow(data->Window);
  610. }
  611. static ImVec2 ImGui_ImplGlfw_GetWindowPos(ImGuiViewport* viewport)
  612. {
  613. ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData;
  614. int x = 0, y = 0;
  615. glfwGetWindowPos(data->Window, &x, &y);
  616. return ImVec2((float)x, (float)y);
  617. }
  618. static void ImGui_ImplGlfw_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
  619. {
  620. ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData;
  621. data->IgnoreWindowPosEventFrame = ImGui::GetFrameCount();
  622. glfwSetWindowPos(data->Window, (int)pos.x, (int)pos.y);
  623. }
  624. static ImVec2 ImGui_ImplGlfw_GetWindowSize(ImGuiViewport* viewport)
  625. {
  626. ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData;
  627. int w = 0, h = 0;
  628. glfwGetWindowSize(data->Window, &w, &h);
  629. return ImVec2((float)w, (float)h);
  630. }
  631. static void ImGui_ImplGlfw_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
  632. {
  633. ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData;
  634. #if __APPLE__ && !GLFW_HAS_OSX_WINDOW_POS_FIX
  635. // Native OS windows are positioned from the bottom-left corner on macOS, whereas on other platforms they are
  636. // positioned from the upper-left corner. GLFW makes an effort to convert macOS style coordinates, however it
  637. // doesn't handle it when changing size. We are manually moving the window in order for changes of size to be based
  638. // on the upper-left corner.
  639. int x, y, width, height;
  640. glfwGetWindowPos(data->Window, &x, &y);
  641. glfwGetWindowSize(data->Window, &width, &height);
  642. glfwSetWindowPos(data->Window, x, y - height + size.y);
  643. #endif
  644. data->IgnoreWindowSizeEventFrame = ImGui::GetFrameCount();
  645. glfwSetWindowSize(data->Window, (int)size.x, (int)size.y);
  646. }
  647. static void ImGui_ImplGlfw_SetWindowTitle(ImGuiViewport* viewport, const char* title)
  648. {
  649. ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData;
  650. glfwSetWindowTitle(data->Window, title);
  651. }
  652. static void ImGui_ImplGlfw_SetWindowFocus(ImGuiViewport* viewport)
  653. {
  654. #if GLFW_HAS_FOCUS_WINDOW
  655. ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData;
  656. glfwFocusWindow(data->Window);
  657. #else
  658. // FIXME: What are the effect of not having this function? At the moment imgui doesn't actually call SetWindowFocus - we set that up ahead, will answer that question later.
  659. (void)viewport;
  660. #endif
  661. }
  662. static bool ImGui_ImplGlfw_GetWindowFocus(ImGuiViewport* viewport)
  663. {
  664. ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData;
  665. return glfwGetWindowAttrib(data->Window, GLFW_FOCUSED) != 0;
  666. }
  667. static bool ImGui_ImplGlfw_GetWindowMinimized(ImGuiViewport* viewport)
  668. {
  669. ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData;
  670. return glfwGetWindowAttrib(data->Window, GLFW_ICONIFIED) != 0;
  671. }
  672. #if GLFW_HAS_WINDOW_ALPHA
  673. static void ImGui_ImplGlfw_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
  674. {
  675. ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData;
  676. glfwSetWindowOpacity(data->Window, alpha);
  677. }
  678. #endif
  679. static void ImGui_ImplGlfw_RenderWindow(ImGuiViewport* viewport, void*)
  680. {
  681. ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData;
  682. if (g_ClientApi == GlfwClientApi_OpenGL)
  683. glfwMakeContextCurrent(data->Window);
  684. }
  685. static void ImGui_ImplGlfw_SwapBuffers(ImGuiViewport* viewport, void*)
  686. {
  687. ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData;
  688. if (g_ClientApi == GlfwClientApi_OpenGL)
  689. {
  690. glfwMakeContextCurrent(data->Window);
  691. glfwSwapBuffers(data->Window);
  692. }
  693. }
  694. //--------------------------------------------------------------------------------------------------------
  695. // IME (Input Method Editor) basic support for e.g. Asian language users
  696. //--------------------------------------------------------------------------------------------------------
  697. // We provide a Win32 implementation because this is such a common issue for IME users
  698. #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
  699. #define HAS_WIN32_IME 1
  700. #include <imm.h>
  701. #ifdef _MSC_VER
  702. #pragma comment(lib, "imm32")
  703. #endif
  704. static void ImGui_ImplWin32_SetImeInputPos(ImGuiViewport* viewport, ImVec2 pos)
  705. {
  706. COMPOSITIONFORM cf = { CFS_FORCE_POSITION, { (LONG)(pos.x - viewport->Pos.x), (LONG)(pos.y - viewport->Pos.y) }, { 0, 0, 0, 0 } };
  707. if (HWND hwnd = (HWND)viewport->PlatformHandleRaw)
  708. if (HIMC himc = ::ImmGetContext(hwnd))
  709. {
  710. ::ImmSetCompositionWindow(himc, &cf);
  711. ::ImmReleaseContext(hwnd, himc);
  712. }
  713. }
  714. #else
  715. #define HAS_WIN32_IME 0
  716. #endif
  717. //--------------------------------------------------------------------------------------------------------
  718. // Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface)
  719. //--------------------------------------------------------------------------------------------------------
  720. // Avoid including <vulkan.h> so we can build without it
  721. #if GLFW_HAS_VULKAN
  722. #ifndef VULKAN_H_
  723. #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
  724. #if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
  725. #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
  726. #else
  727. #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
  728. #endif
  729. VK_DEFINE_HANDLE(VkInstance)
  730. VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR)
  731. struct VkAllocationCallbacks;
  732. enum VkResult { VK_RESULT_MAX_ENUM = 0x7FFFFFFF };
  733. #endif // VULKAN_H_
  734. extern "C" { extern GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); }
  735. static int ImGui_ImplGlfw_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface)
  736. {
  737. ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData;
  738. IM_ASSERT(g_ClientApi == GlfwClientApi_Vulkan);
  739. VkResult err = glfwCreateWindowSurface((VkInstance)vk_instance, data->Window, (const VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface);
  740. return (int)err;
  741. }
  742. #endif // GLFW_HAS_VULKAN
  743. static void ImGui_ImplGlfw_InitPlatformInterface()
  744. {
  745. // Register platform interface (will be coupled with a renderer interface)
  746. ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
  747. platform_io.Platform_CreateWindow = ImGui_ImplGlfw_CreateWindow;
  748. platform_io.Platform_DestroyWindow = ImGui_ImplGlfw_DestroyWindow;
  749. platform_io.Platform_ShowWindow = ImGui_ImplGlfw_ShowWindow;
  750. platform_io.Platform_SetWindowPos = ImGui_ImplGlfw_SetWindowPos;
  751. platform_io.Platform_GetWindowPos = ImGui_ImplGlfw_GetWindowPos;
  752. platform_io.Platform_SetWindowSize = ImGui_ImplGlfw_SetWindowSize;
  753. platform_io.Platform_GetWindowSize = ImGui_ImplGlfw_GetWindowSize;
  754. platform_io.Platform_SetWindowFocus = ImGui_ImplGlfw_SetWindowFocus;
  755. platform_io.Platform_GetWindowFocus = ImGui_ImplGlfw_GetWindowFocus;
  756. platform_io.Platform_GetWindowMinimized = ImGui_ImplGlfw_GetWindowMinimized;
  757. platform_io.Platform_SetWindowTitle = ImGui_ImplGlfw_SetWindowTitle;
  758. platform_io.Platform_RenderWindow = ImGui_ImplGlfw_RenderWindow;
  759. platform_io.Platform_SwapBuffers = ImGui_ImplGlfw_SwapBuffers;
  760. #if GLFW_HAS_WINDOW_ALPHA
  761. platform_io.Platform_SetWindowAlpha = ImGui_ImplGlfw_SetWindowAlpha;
  762. #endif
  763. #if GLFW_HAS_VULKAN
  764. platform_io.Platform_CreateVkSurface = ImGui_ImplGlfw_CreateVkSurface;
  765. #endif
  766. #if HAS_WIN32_IME
  767. platform_io.Platform_SetImeInputPos = ImGui_ImplWin32_SetImeInputPos;
  768. #endif
  769. // Register main window handle (which is owned by the main application, not by us)
  770. // This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
  771. ImGuiViewport* main_viewport = ImGui::GetMainViewport();
  772. ImGuiViewportDataGlfw* data = IM_NEW(ImGuiViewportDataGlfw)();
  773. data->Window = g_Window;
  774. data->WindowOwned = false;
  775. main_viewport->PlatformUserData = data;
  776. main_viewport->PlatformHandle = (void*)g_Window;
  777. }
  778. static void ImGui_ImplGlfw_ShutdownPlatformInterface()
  779. {
  780. }