diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index b07f33f9..b826188b 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -521,25 +521,28 @@ static int ImGui_ImplGlfw_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_inst #endif // GLFW_HAS_VULKAN // FIXME-PLATFORM: Update when changed (using glfwSetMonitorCallback?) +// FIXME-PLATFORM: GLFW doesn't export work area (see https://github.com/glfw/glfw/pull/989) static void ImGui_ImplGlfw_UpdateMonitors() { ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); int monitors_count = 0; GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count); - platform_io.Monitors.resize(monitors_count, ImGuiPlatformMonitor()); + 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]); - platform_io.Monitors[n].Pos = ImVec2((float)x, (float)y); - platform_io.Monitors[n].Size = ImVec2((float)vid_mode->width, (float)vid_mode->height); + monitor.FullMin = monitor.WorkMin = ImVec2((float)x, (float)y); + monitor.FullMax = monitor.WorkMax = ImVec2((float)(x + vid_mode->width), (float)(y + vid_mode->height)); #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); - platform_io.Monitors[n].DpiScale = x_scale; + monitor.DpiScale = x_scale; #endif + platform_io.Monitors.push_back(monitor); } } diff --git a/examples/imgui_impl_sdl2.cpp b/examples/imgui_impl_sdl2.cpp index b7d801a8..9a67f0e1 100644 --- a/examples/imgui_impl_sdl2.cpp +++ b/examples/imgui_impl_sdl2.cpp @@ -30,13 +30,15 @@ #include "imgui_impl_sdl2.h" // SDL +// (the multi-viewports feature requires SDL features suppoted from SDL 2.0.5+) #include #include -#define SDL_HAS_CAPTURE_MOUSE SDL_VERSION_ATLEAST(2,0,4) -#define SDL_HAS_WINDOW_OPACITY SDL_VERSION_ATLEAST(2,0,5) -#define SDL_HAS_ALWAYS_ON_TOP SDL_VERSION_ATLEAST(2,0,5) -#define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4) -#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) +#define SDL_HAS_CAPTURE_MOUSE SDL_VERSION_ATLEAST(2,0,4) +#define SDL_HAS_WINDOW_OPACITY SDL_VERSION_ATLEAST(2,0,5) +#define SDL_HAS_ALWAYS_ON_TOP SDL_VERSION_ATLEAST(2,0,5) +#define SDL_HAS_USABLE_DISPLAY_BOUNDS SDL_VERSION_ATLEAST(2,0,5) +#define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4) +#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) #if !SDL_HAS_VULKAN static const Uint32 SDL_WINDOW_VULKAN = 0x10000000; #endif @@ -446,20 +448,27 @@ static int ImGui_ImplSDL2_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_inst static void ImGui_ImplSDL2_UpdateMonitors() { ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + platform_io.Monitors.resize(0); int display_count = SDL_GetNumVideoDisplays(); - platform_io.Monitors.resize(display_count, ImGuiPlatformMonitor()); 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); - platform_io.Monitors[n].Pos = ImVec2((float)r.x, (float)r.y); - platform_io.Monitors[n].Size = ImVec2((float)r.w, (float)r.h); + monitor.FullMin = monitor.WorkMin = ImVec2((float)(r.x), (float)(r.y)); + monitor.FullMax = monitor.WorkMax = ImVec2((float)(r.x + r.w), (float)(r.y + r.h)); +#if SDL_HAS_USABLE_DISPLAY_BOUNDS + SDL_GetDisplayUsableBounds(n, &r); + monitor.WorkMin = ImVec2((float)(r.x), (float)(r.y)); + monitor.WorkMax = ImVec2((float)(r.x + r.w), (float)(r.y + r.h)); +#endif #if SDL_HAS_PER_MONITOR_DPI float dpi = 0.0f; - SDL_GetDisplayDPI(n, &dpi, NULL, NULL); - platform_io.Monitors[n].DpiScale = dpi / 96.0f; + if (SDL_GetDisplayDPI(n, &dpi, NULL, NULL)) + monitor.DpiScale = dpi / 96.0f; #endif + platform_io.Monitors.push_back(monitor); } } diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index 47560a4e..c68dcc8b 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -550,11 +550,17 @@ 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 rect, 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.Pos = ImVec2((float)rect->left, (float)rect->top); - imgui_monitor.Size = ImVec2((float)(rect->right - rect->left), (float)(rect->bottom - rect->top)); + imgui_monitor.FullMin = ImVec2((float)info.rcMonitor.left, (float)info.rcMonitor.top); + imgui_monitor.FullMax = ImVec2((float)info.rcMonitor.right, (float)info.rcMonitor.bottom); + imgui_monitor.WorkMin = ImVec2((float)info.rcWork.left, (float)info.rcWork.top); + imgui_monitor.WorkMax = ImVec2((float)info.rcWork.right, (float)info.rcWork.bottom); imgui_monitor.DpiScale = ImGui_ImplWin32_GetDpiScaleForMonitor(monitor); ImGui::GetPlatformIO().Monitors.push_back(imgui_monitor); return TRUE; diff --git a/imgui.cpp b/imgui.cpp index 59fdd2b0..b9b0a752 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3802,6 +3802,13 @@ void ImGui::NewFrame() // Disable feature, our back-ends do not support it g.IO.ConfigFlags &= ~ImGuiConfigFlags_ViewportsEnable; } + for (int monitor_n = 0; monitor_n < g.PlatformIO.Monitors.Size; monitor_n++) + { + ImGuiPlatformMonitor& mon = g.PlatformIO.Monitors[monitor_n]; + IM_ASSERT(mon.FullMin.x < mon.FullMax.x && mon.FullMin.y < mon.FullMax.y && "Monitor bounds not setup properly."); + IM_ASSERT(mon.WorkMin.x < mon.WorkMax.x && mon.WorkMin.y < mon.WorkMax.y && "Monitor bounds not setup properly. If you don't have work area information, just copy Min/Max into them."); + IM_ASSERT(mon.DpiScale != 0.0f); + } } // Load settings on first frame @@ -5847,8 +5854,8 @@ static ImRect FindAllowedExtentRectForWindow(ImGuiWindow* window) { // Extent with be in the frame of reference of the given viewport (so Min is likely to be negative here) const ImGuiPlatformMonitor& monitor = g.PlatformIO.Monitors[window->ViewportAllowPlatformMonitorExtend]; - r_screen.Min = monitor.Pos; - r_screen.Max = monitor.Pos + monitor.Size; + r_screen.Min = monitor.WorkMin; + r_screen.Max = monitor.WorkMax; } else { @@ -6028,7 +6035,7 @@ static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents) const int monitor_idx = window->ViewportAllowPlatformMonitorExtend; ImVec2 avail_size = window->Viewport->Size; if (window->ViewportOwned) - avail_size = (monitor_idx >= 0 && monitor_idx < g.PlatformIO.Monitors.Size) ? g.PlatformIO.Monitors[monitor_idx].Size : ImVec2(FLT_MAX, FLT_MAX); + avail_size = (monitor_idx >= 0 && monitor_idx < g.PlatformIO.Monitors.Size) ? (g.PlatformIO.Monitors[monitor_idx].WorkMax - g.PlatformIO.Monitors[monitor_idx].WorkMin) : ImVec2(FLT_MAX, FLT_MAX); ImVec2 size_auto_fit = ImClamp(size_contents, style.WindowMinSize, ImMax(style.WindowMinSize, avail_size - g.Style.DisplaySafeAreaPadding * 2.0f)); // When the window cannot fit all contents (either because of constraints, either because screen is too small), @@ -6099,8 +6106,7 @@ static int FindPlatformMonitorForPos(ImVec2 platform_pos) for (int monitor_n = 0; monitor_n < g.PlatformIO.Monitors.Size; monitor_n++) { const ImGuiPlatformMonitor* monitor = &g.PlatformIO.Monitors[monitor_n]; - ImRect monitor_rect(monitor->Pos, monitor->Pos + monitor->Size); - if (monitor_rect.Contains(platform_pos)) + if (ImRect(monitor->FullMin, monitor->FullMax).Contains(platform_pos)) return monitor_n; } return -1; @@ -14252,7 +14258,10 @@ void ImGui::ShowMetricsWindow(bool* p_open) for (int i = 0; i < g.PlatformIO.Monitors.Size; i++) { const ImGuiPlatformMonitor& mon = g.PlatformIO.Monitors[i]; - ImGui::BulletText("Monitor #%d: DPI %.0f%%, Min (%.0f,%.0f), Max (%.0f,%.0f), Size (%.0f,%.0f)", i, mon.DpiScale * 100.0f, mon.Pos.x, mon.Pos.y, mon.Pos.x + mon.Size.x, mon.Pos.y + mon.Size.y, mon.Size.x, mon.Size.y); + ImGui::BulletText("Monitor #%d: DPI %.0f%%\n FullMin (%.0f,%.0f), FullMax (%.0f,%.0f), FullSize (%.0f,%.0f)\n WorkMin (%.0f,%.0f), WorkMax (%.0f,%.0f), WorkSize (%.0f,%.0f)", + i, mon.DpiScale * 100.0f, + mon.FullMin.x, mon.FullMin.y, mon.FullMax.x, mon.FullMax.y, mon.FullMax.x - mon.FullMin.x, mon.FullMax.y - mon.FullMin.y, + mon.WorkMin.x, mon.WorkMin.y, mon.WorkMax.x, mon.WorkMax.y, mon.WorkMax.x - mon.WorkMin.x, mon.WorkMax.y - mon.WorkMin.y); } ImGui::TreePop(); } diff --git a/imgui.h b/imgui.h index f207425c..8c6e5b54 100644 --- a/imgui.h +++ b/imgui.h @@ -1876,10 +1876,10 @@ struct ImFont // Dear ImGui only uses this to clamp the position of popups and tooltips so they don't straddle multiple monitors struct ImGuiPlatformMonitor { - ImVec2 Pos; - ImVec2 Size; + ImVec2 FullMin, FullMax; // Coordinates of the area displayed on this monitor (Min = upper left, Max = bottom right) + ImVec2 WorkMin, WorkMax; // (Optional) Coordinates without task bars / side bars / menu bars. imgui uses this to avoid positioning popups/tooltips inside this region. float DpiScale; - ImGuiPlatformMonitor() { Pos = ImVec2(0,0); Size = ImVec2(0,0); DpiScale = 1.0f; } + ImGuiPlatformMonitor() { FullMin = FullMax = WorkMin = WorkMax = ImVec2(0,0); DpiScale = 1.0f; } }; // (Optional) Setup required only if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) is enabled