From 22d6f001103e826a0efbbc5cc28c171a289c1b83 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 13 Apr 2018 00:01:55 +0200 Subject: [PATCH] Viewport: Fixed DPI changing viewport from interfering with moving another window (disabling code) + metrics crash fix on closed viewport window + Windows 10 call to SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) for DPI, with no noticeable improvements. (#1542, #1676) --- examples/imgui_impl_win32.cpp | 23 ++++++++++++++++++----- imgui.cpp | 15 +++++++++------ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index 610a2e23..efe5b461 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -286,9 +286,7 @@ IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wPa // So we dynamically select and load those functions to avoid dependencies. This is the scheme successfully // used by GLFW (from which we borrowed some of the code here) and other applications aiming to be portable. //--------------------------------------------------------------------------------------------------------- -// FIXME-DPI: For now we just call SetProcessDpiAwareness(PROCESS_PER_MONITOR_AWARE) without requiring SDK 8.1 or 10. -// We may allow/aim calling the most-recent-available version, e.g. Windows 10 Creators Update has SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); -// At this point ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it ourselves. +// At this point ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically. //--------------------------------------------------------------------------------------------------------- static BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp) @@ -307,11 +305,26 @@ static BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp) typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS; typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE; #endif -typedef HRESULT(WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib+dll, Windows 8.1 -typedef HRESULT(WINAPI * PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib+dll, Windows 8.1 +#ifndef _DPI_AWARENESS_CONTEXTS_ +DECLARE_HANDLE(DPI_AWARENESS_CONTEXT); +#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (DPI_AWARENESS_CONTEXT)-3 +#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4 +#endif +typedef HRESULT(WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib+dll, Windows 8.1 +typedef HRESULT(WINAPI * PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib+dll, Windows 8.1 +typedef DPI_AWARENESS_CONTEXT(WINAPI * PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib+dll, Windows 10 v1607 (Creators Update) void ImGui_ImplWin32_EnableDpiAwareness() { + // if (IsWindows10OrGreater()) // FIXME-DPI: This needs a manifest to succeed. Instead we try to grab the function pointer. + { + static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process + if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext")) + { + SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + return; + } + } if (IsWindows8Point1OrGreater()) { static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process diff --git a/imgui.cpp b/imgui.cpp index cbe28876..aded38a8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -14035,8 +14035,11 @@ void ImGui::ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale) { ImGuiContext& g = *GImGui; - if (g.MovingWindow != NULL) - g.ActiveIdClickOffset = ImFloor(g.ActiveIdClickOffset * scale); + // FIXME-DPI: This is meant to have the window rescale around the mouse. It currently creates feedback loop when a window is straddling a DPI transition border. + // NB: since our sizes do not perfectly linearly scale, deferring the ClickOffset scale until we know the actual window scale ratio may get us slightly more precise mouse positioning. + //if (g.MovingWindow != NULL && g.MovingWindow->Viewport == viewport) + // g.ActiveIdClickOffset = ImFloor(g.ActiveIdClickOffset * scale); + /* if (g.IO.MousePosViewport == viewport->ID) { @@ -14106,8 +14109,8 @@ void ImGui::ShowMetricsWindow(bool* p_open) return; } - ImDrawList* overlay_draw_list = GetOverlayDrawList(viewport); // Render additional visuals into the top-most draw list - if (window && ImGui::IsItemHovered()) + ImDrawList* overlay_draw_list = viewport ? GetOverlayDrawList(viewport) : NULL; // Render additional visuals into the top-most draw list + if (window && overlay_draw_list && ImGui::IsItemHovered()) overlay_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); if (!node_open) return; @@ -14124,7 +14127,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) } ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %4d %s vtx, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); - if (show_clip_rects && ImGui::IsItemHovered()) + if (show_clip_rects && overlay_draw_list && ImGui::IsItemHovered()) { ImRect clip_rect = pcmd->ClipRect; ImRect vtxs_rect; @@ -14151,7 +14154,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) buf_p += ImFormatString(buf_p, (int)(buf_end - buf_p), "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); } ImGui::Selectable(buf, false); - if (ImGui::IsItemHovered()) + if (overlay_draw_list && ImGui::IsItemHovered()) { ImDrawListFlags backup_flags = overlay_draw_list->Flags; overlay_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines at is more readable for very large and thin triangles.