From 7e2d172ae5c8b53184bbf2982ceb1fefbb99ceba Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 9 Feb 2020 17:31:18 +0100 Subject: [PATCH] Backends: GLFW, SDL: Platform monitors declared properly even if multi-viewport is not enabled. --- examples/imgui_impl_glfw.cpp | 91 ++++++++++++++++++----------------- examples/imgui_impl_glfw.h | 2 + examples/imgui_impl_sdl.cpp | 62 ++++++++++++------------ examples/imgui_impl_win32.cpp | 54 ++++++++++----------- imgui.cpp | 6 ++- 5 files changed, 112 insertions(+), 103 deletions(-) diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index 2d3431e9..bcbee436 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -83,11 +83,12 @@ static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL; static GLFWscrollfun g_PrevUserCallbackScroll = NULL; static GLFWkeyfun g_PrevUserCallbackKey = NULL; static GLFWcharfun g_PrevUserCallbackChar = NULL; +static GLFWmonitorfun g_PrevUserCallbackMonitor = NULL; // Forward Declarations +static void ImGui_ImplGlfw_UpdateMonitors(); static void ImGui_ImplGlfw_InitPlatformInterface(); static void ImGui_ImplGlfw_ShutdownPlatformInterface(); -static void ImGui_ImplGlfw_UpdateMonitors(); static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) { @@ -149,6 +150,11 @@ void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) io.AddInputCharacter(c); } +void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int) +{ + g_WantUpdateMonitors = true; +} + static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) { g_Window = window; @@ -220,6 +226,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw g_PrevUserCallbackScroll = NULL; g_PrevUserCallbackKey = NULL; g_PrevUserCallbackChar = NULL; + g_PrevUserCallbackMonitor = NULL; if (install_callbacks) { g_InstalledCallbacks = true; @@ -227,8 +234,13 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); + g_PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback); } + // Update monitors the first time (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784) + ImGui_ImplGlfw_UpdateMonitors(); + glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback); + // Our mouse update function expect PlatformHandle to be filled for the main viewport ImGuiViewport* main_viewport = ImGui::GetMainViewport(); main_viewport->PlatformHandle = (void*)g_Window; @@ -405,6 +417,40 @@ static void ImGui_ImplGlfw_UpdateGamepads() io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; } +static void ImGui_ImplGlfw_UpdateMonitors() +{ + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + int monitors_count = 0; + GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count); + platform_io.Monitors.resize(0); + for (int n = 0; n < monitors_count; n++) + { + ImGuiPlatformMonitor monitor; + int x, y; + glfwGetMonitorPos(glfw_monitors[n], &x, &y); + const GLFWvidmode* vid_mode = glfwGetVideoMode(glfw_monitors[n]); +#if GLFW_HAS_MONITOR_WORK_AREA + monitor.MainPos = ImVec2((float)x, (float)y); + monitor.MainSize = ImVec2((float)vid_mode->width, (float)vid_mode->height); + int w, h; + glfwGetMonitorWorkarea(glfw_monitors[n], &x, &y, &w, &h); + monitor.WorkPos = ImVec2((float)x, (float)y);; + monitor.WorkSize = ImVec2((float)w, (float)h); +#else + monitor.MainPos = monitor.WorkPos = ImVec2((float)x, (float)y); + monitor.MainSize = monitor.WorkSize = ImVec2((float)vid_mode->width, (float)vid_mode->height); +#endif +#if GLFW_HAS_PER_MONITOR_DPI + // 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. + float x_scale, y_scale; + glfwGetMonitorContentScale(glfw_monitors[n], &x_scale, &y_scale); + monitor.DpiScale = x_scale; +#endif + platform_io.Monitors.push_back(monitor); + } + g_WantUpdateMonitors = false; +} + void ImGui_ImplGlfw_NewFrame() { ImGuiIO& io = ImGui::GetIO(); @@ -746,45 +792,6 @@ static int ImGui_ImplGlfw_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_inst } #endif // GLFW_HAS_VULKAN -static void ImGui_ImplGlfw_UpdateMonitors() -{ - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - int monitors_count = 0; - GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count); - platform_io.Monitors.resize(0); - for (int n = 0; n < monitors_count; n++) - { - ImGuiPlatformMonitor monitor; - int x, y; - glfwGetMonitorPos(glfw_monitors[n], &x, &y); - const GLFWvidmode* vid_mode = glfwGetVideoMode(glfw_monitors[n]); -#if GLFW_HAS_MONITOR_WORK_AREA - monitor.MainPos = ImVec2((float)x, (float)y); - monitor.MainSize = ImVec2((float)vid_mode->width, (float)vid_mode->height); - int w, h; - glfwGetMonitorWorkarea(glfw_monitors[n], &x, &y, &w, &h); - monitor.WorkPos = ImVec2((float)x, (float)y);; - monitor.WorkSize = ImVec2((float)w, (float)h); -#else - monitor.MainPos = monitor.WorkPos = ImVec2((float)x, (float)y); - monitor.MainSize = monitor.WorkSize = ImVec2((float)vid_mode->width, (float)vid_mode->height); -#endif -#if GLFW_HAS_PER_MONITOR_DPI - // 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. - float x_scale, y_scale; - glfwGetMonitorContentScale(glfw_monitors[n], &x_scale, &y_scale); - monitor.DpiScale = x_scale; -#endif - platform_io.Monitors.push_back(monitor); - } - g_WantUpdateMonitors = false; -} - -static void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int) -{ - g_WantUpdateMonitors = true; -} - static void ImGui_ImplGlfw_InitPlatformInterface() { // Register platform interface (will be coupled with a renderer interface) @@ -812,10 +819,6 @@ static void ImGui_ImplGlfw_InitPlatformInterface() platform_io.Platform_SetImeInputPos = ImGui_ImplWin32_SetImeInputPos; #endif - // Note: monitor callback are broken GLFW 3.2 and earlier (see github.com/glfw/glfw/issues/784) - ImGui_ImplGlfw_UpdateMonitors(); - glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback); - // Register main window handle (which is owned by the main application, not by us) // 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. ImGuiViewport* main_viewport = ImGui::GetMainViewport(); diff --git a/examples/imgui_impl_glfw.h b/examples/imgui_impl_glfw.h index dcab351c..07a34568 100644 --- a/examples/imgui_impl_glfw.h +++ b/examples/imgui_impl_glfw.h @@ -20,6 +20,7 @@ #pragma once struct GLFWwindow; +struct GLFWmonitor; IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks); IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks); @@ -32,3 +33,4 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, i IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); +IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event); diff --git a/examples/imgui_impl_sdl.cpp b/examples/imgui_impl_sdl.cpp index 8d52a212..ab2ca5ac 100644 --- a/examples/imgui_impl_sdl.cpp +++ b/examples/imgui_impl_sdl.cpp @@ -77,6 +77,7 @@ static bool g_MouseCanUseGlobalState = true; static bool g_UseVulkan = false; // Forward Declarations +static void ImGui_ImplSDL2_UpdateMonitors(); static void ImGui_ImplSDL2_InitPlatformInterface(SDL_Window* window, void* sdl_gl_context); static void ImGui_ImplSDL2_ShutdownPlatformInterface(); @@ -222,6 +223,9 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, void* sdl_gl_context) main_viewport->PlatformHandleRaw = info.info.win.window; #endif + // Update monitors + ImGui_ImplSDL2_UpdateMonitors(); + // We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports. // We left the call to ImGui_ImplSDL2_InitPlatformInterface() outside of #ifdef to avoid unused-function warnings. if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) && (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports)) @@ -405,6 +409,34 @@ static void ImGui_ImplSDL2_UpdateGamepads() #undef MAP_ANALOG } +// FIXME-PLATFORM: SDL doesn't have an event to notify the application of display/monitor changes +static void ImGui_ImplSDL2_UpdateMonitors() +{ + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + platform_io.Monitors.resize(0); + int display_count = SDL_GetNumVideoDisplays(); + for (int n = 0; n < display_count; n++) + { + // 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. + ImGuiPlatformMonitor monitor; + SDL_Rect r; + SDL_GetDisplayBounds(n, &r); + monitor.MainPos = monitor.WorkPos = ImVec2((float)r.x, (float)r.y); + monitor.MainSize = monitor.WorkSize = ImVec2((float)r.w, (float)r.h); +#if SDL_HAS_USABLE_DISPLAY_BOUNDS + SDL_GetDisplayUsableBounds(n, &r); + monitor.WorkPos = ImVec2((float)r.x, (float)r.y); + monitor.WorkSize = ImVec2((float)r.w, (float)r.h); +#endif +#if SDL_HAS_PER_MONITOR_DPI + float dpi = 0.0f; + if (!SDL_GetDisplayDPI(n, &dpi, NULL, NULL)) + monitor.DpiScale = dpi / 96.0f; +#endif + platform_io.Monitors.push_back(monitor); + } +} + void ImGui_ImplSDL2_NewFrame(SDL_Window* window) { ImGuiIO& io = ImGui::GetIO(); @@ -632,34 +664,6 @@ static int ImGui_ImplSDL2_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_inst } #endif // SDL_HAS_VULKAN -// FIXME-PLATFORM: SDL doesn't have an event to notify the application of display/monitor changes -static void ImGui_ImplSDL2_UpdateMonitors() -{ - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - platform_io.Monitors.resize(0); - int display_count = SDL_GetNumVideoDisplays(); - for (int n = 0; n < display_count; n++) - { - // 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. - ImGuiPlatformMonitor monitor; - SDL_Rect r; - SDL_GetDisplayBounds(n, &r); - monitor.MainPos = monitor.WorkPos = ImVec2((float)r.x, (float)r.y); - monitor.MainSize = monitor.WorkSize = ImVec2((float)r.w, (float)r.h); -#if SDL_HAS_USABLE_DISPLAY_BOUNDS - SDL_GetDisplayUsableBounds(n, &r); - monitor.WorkPos = ImVec2((float)r.x, (float)r.y); - monitor.WorkSize = ImVec2((float)r.w, (float)r.h); -#endif -#if SDL_HAS_PER_MONITOR_DPI - float dpi = 0.0f; - if (!SDL_GetDisplayDPI(n, &dpi, NULL, NULL)) - monitor.DpiScale = dpi / 96.0f; -#endif - platform_io.Monitors.push_back(monitor); - } -} - static void ImGui_ImplSDL2_InitPlatformInterface(SDL_Window* window, void* sdl_gl_context) { // Register platform interface (will be coupled with a renderer interface) @@ -689,8 +693,6 @@ static void ImGui_ImplSDL2_InitPlatformInterface(SDL_Window* window, void* sdl_g SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); #endif - ImGui_ImplSDL2_UpdateMonitors(); - // Register main window handle (which is owned by the main application, not by us) // 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. ImGuiViewport* main_viewport = ImGui::GetMainViewport(); diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index cc190093..7a607799 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -263,6 +263,33 @@ static void ImGui_ImplWin32_UpdateGamepads() #endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD } +static BOOL CALLBACK ImGui_ImplWin32_UpdateMonitors_EnumFunc(HMONITOR monitor, HDC, LPRECT, LPARAM) +{ + MONITORINFO info = { 0 }; + info.cbSize = sizeof(MONITORINFO); + if (!::GetMonitorInfo(monitor, &info)) + return TRUE; + ImGuiPlatformMonitor imgui_monitor; + imgui_monitor.MainPos = ImVec2((float)info.rcMonitor.left, (float)info.rcMonitor.top); + imgui_monitor.MainSize = ImVec2((float)(info.rcMonitor.right - info.rcMonitor.left), (float)(info.rcMonitor.bottom - info.rcMonitor.top)); + imgui_monitor.WorkPos = ImVec2((float)info.rcWork.left, (float)info.rcWork.top); + imgui_monitor.WorkSize = ImVec2((float)(info.rcWork.right - info.rcWork.left), (float)(info.rcWork.bottom - info.rcWork.top)); + imgui_monitor.DpiScale = ImGui_ImplWin32_GetDpiScaleForMonitor(monitor); + ImGuiPlatformIO& io = ImGui::GetPlatformIO(); + if (info.dwFlags & MONITORINFOF_PRIMARY) + io.Monitors.push_front(imgui_monitor); + else + io.Monitors.push_back(imgui_monitor); + return TRUE; +} + +static void ImGui_ImplWin32_UpdateMonitors() +{ + ImGui::GetPlatformIO().Monitors.resize(0); + ::EnumDisplayMonitors(NULL, NULL, ImGui_ImplWin32_UpdateMonitors_EnumFunc, NULL); + g_WantUpdateMonitors = false; +} + void ImGui_ImplWin32_NewFrame() { ImGuiIO& io = ImGui::GetIO(); @@ -764,33 +791,6 @@ static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, return DefWindowProc(hWnd, msg, wParam, lParam); } -static BOOL CALLBACK ImGui_ImplWin32_UpdateMonitors_EnumFunc(HMONITOR monitor, HDC, LPRECT, LPARAM) -{ - MONITORINFO info = { 0 }; - info.cbSize = sizeof(MONITORINFO); - if (!::GetMonitorInfo(monitor, &info)) - return TRUE; - ImGuiPlatformMonitor imgui_monitor; - imgui_monitor.MainPos = ImVec2((float)info.rcMonitor.left, (float)info.rcMonitor.top); - imgui_monitor.MainSize = ImVec2((float)(info.rcMonitor.right - info.rcMonitor.left), (float)(info.rcMonitor.bottom - info.rcMonitor.top)); - imgui_monitor.WorkPos = ImVec2((float)info.rcWork.left, (float)info.rcWork.top); - imgui_monitor.WorkSize = ImVec2((float)(info.rcWork.right - info.rcWork.left), (float)(info.rcWork.bottom - info.rcWork.top)); - imgui_monitor.DpiScale = ImGui_ImplWin32_GetDpiScaleForMonitor(monitor); - ImGuiPlatformIO& io = ImGui::GetPlatformIO(); - if (info.dwFlags & MONITORINFOF_PRIMARY) - io.Monitors.push_front(imgui_monitor); - else - io.Monitors.push_back(imgui_monitor); - return TRUE; -} - -static void ImGui_ImplWin32_UpdateMonitors() -{ - ImGui::GetPlatformIO().Monitors.resize(0); - ::EnumDisplayMonitors(NULL, NULL, ImGui_ImplWin32_UpdateMonitors_EnumFunc, NULL); - g_WantUpdateMonitors = false; -} - static void ImGui_ImplWin32_InitPlatformInterface() { WNDCLASSEX wcex; diff --git a/imgui.cpp b/imgui.cpp index e0c882b5..2191d378 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15329,9 +15329,11 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing()); ImGui::ShowViewportThumbnails(); ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); - if (g.PlatformIO.Monitors.Size > 0 && ImGui::TreeNode("Monitors", "Monitors (%d)", g.PlatformIO.Monitors.Size)) + bool open = ImGui::TreeNode("Monitors", "Monitors (%d)", g.PlatformIO.Monitors.Size); + ImGui::SameLine(); + MetricsHelpMarker("Dear ImGui uses monitor data:\n- to query DPI settings on a per monitor basis\n- to position popup/tooltips so they don't straddle monitors."); + if (open) { - ImGui::TextWrapped("(When viewports are enabled, imgui needs uses monitor data to position popup/tooltips so they don't straddle monitors.)"); for (int i = 0; i < g.PlatformIO.Monitors.Size; i++) { const ImGuiPlatformMonitor& mon = g.PlatformIO.Monitors[i];