imgui_impl_glfw.cpp 42 KB

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