diff --git a/TODO.txt b/TODO.txt index 3a4e285f..918f3b58 100644 --- a/TODO.txt +++ b/TODO.txt @@ -262,6 +262,9 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - viewport: store per-viewport/monitor DPI in .ini file so an application reload or main window changing DPI on reload can be properly patched for. - viewport: vulkan renderer implementation. - viewport: need to clarify how to use GetMousePos() from a user point of view. + - platform: glfw: no support for ImGuiBackendFlags_HasMouseHoveredViewport. + - platform: sdl: no support for ImGuiBackendFlags_HasMouseHoveredViewport. maybe we could use SDL_GetMouseFocus() / SDL_WINDOW_MOUSE_FOCUS if imgui could fallback on its heuristic when NoInputs is set + - platform: sdl: no refresh of monitor/display (SDL doesn't seem to have an event for it). - inputs: we need an explicit flag about whether the imgui window is focused, to be able to distinguish focused key releases vs alt-tabbing all release behaviors. - inputs: rework IO system to be able to pass actual ordered/timestamped events. use an event queue? (~#335, #71) diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index 0d00b3aa..af984041 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -53,10 +53,12 @@ static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown; static double g_Time = 0.0f; static bool g_MouseJustPressed[5] = { false, false, false, false, false }; static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_Count_] = { 0 }; +static bool g_WantUpdateMonitors = true; // Forward Declarations static void ImGui_ImplGlfw_InitPlatformInterface(); static void ImGui_ImplGlfw_ShutdownPlatformInterface(); +static void ImGui_ImplGlfw_UpdateMonitors(); static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) { @@ -271,6 +273,8 @@ void ImGui_ImplGlfw_NewFrame() glfwGetFramebufferSize(g_Window, &display_w, &display_h); io.DisplaySize = ImVec2((float)w, (float)h); io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); + if (g_WantUpdateMonitors) + ImGui_ImplGlfw_UpdateMonitors(); // Setup time step double current_time = glfwGetTime(); @@ -562,7 +566,6 @@ static int ImGui_ImplGlfw_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_inst } #endif // GLFW_HAS_VULKAN -// FIXME-PLATFORM: Update monitor list when changed (using glfwSetMonitorCallback?) // FIXME-PLATFORM: GLFW doesn't export monitor work area (see https://github.com/glfw/glfw/pull/989) static void ImGui_ImplGlfw_UpdateMonitors() { @@ -586,6 +589,12 @@ static void ImGui_ImplGlfw_UpdateMonitors() #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() @@ -614,7 +623,9 @@ 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) ImGuiViewport* main_viewport = ImGui::GetMainViewport(); diff --git a/examples/imgui_impl_sdl2.cpp b/examples/imgui_impl_sdl2.cpp index e58f28cc..e33c2a18 100644 --- a/examples/imgui_impl_sdl2.cpp +++ b/examples/imgui_impl_sdl2.cpp @@ -418,8 +418,7 @@ static void ImGui_ImplSDL2_SetWindowFocus(ImGuiViewport* viewport) static bool ImGui_ImplSDL2_GetWindowFocus(ImGuiViewport* viewport) { ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData; - bool focus = (SDL_GetWindowFlags(data->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; - return focus; + return (SDL_GetWindowFlags(data->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; } static void ImGui_ImplSDL2_RenderWindow(ImGuiViewport* viewport, void*) @@ -452,7 +451,7 @@ static int ImGui_ImplSDL2_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_inst } #endif // SDL_HAS_VULKAN -// FIXME-PLATFORM: Update monitor list when changed? +// 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(); diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index f69067d0..76c5b76b 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -8,6 +8,7 @@ #include // CHANGELOG +// (minor and older changes stripped away, please see git history for details) // 2018-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag. // 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling). @@ -26,10 +27,12 @@ static HWND g_hWnd = 0; static INT64 g_Time = 0; static INT64 g_TicksPerSecond = 0; static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_Count_; +static bool g_WantUpdateMonitors = true; // Forward Declarations static void ImGui_ImplWin32_InitPlatformInterface(); static void ImGui_ImplWin32_ShutdownPlatformInterface(); +static void ImGui_ImplWin32_UpdateMonitors(); // Functions bool ImGui_ImplWin32_Init(void* hwnd) @@ -159,6 +162,8 @@ void ImGui_ImplWin32_NewFrame() RECT rect; ::GetClientRect(g_hWnd, &rect); io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); + if (g_WantUpdateMonitors) + ImGui_ImplWin32_UpdateMonitors(); // Setup time step INT64 current_time; @@ -251,7 +256,7 @@ IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wPa io.MouseWheelH += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; return 0; case WM_MOUSEMOVE: - io.MousePos.x = (signed short)(lParam); + io.MousePos.x = (signed short)(lParam); // Note: this is used for single-viewport support, but in reality the code in ImGui_ImplWin32_UpdateMousePos() overwrite this. io.MousePos.y = (signed short)(lParam >> 16); return 0; case WM_KEYDOWN: @@ -273,6 +278,9 @@ IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wPa if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) return 1; return 0; + case WM_DISPLAYCHANGE: + g_WantUpdateMonitors = true; + return 0; } return 0; } @@ -623,11 +631,11 @@ static BOOL CALLBACK ImGui_ImplWin32_UpdateMonitors_EnumFunc(HMONITOR monitor, H return TRUE; } -// FIXME-PLATFORM: Update monitor list when changed (WM_DISPLAYCHANGE?) 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() diff --git a/imgui.cpp b/imgui.cpp index 93b4a30b..1f624efa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3580,21 +3580,6 @@ void ImGui::UpdatePlatformWindows() if (!(g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)) return; - // Update our implicit z-order knowledge of platform windows, which is used when the back-end cannot provide io.MouseHoveredViewport. - if (g.PlatformIO.Platform_GetWindowFocus) - { - ImGuiViewportP* focused_viewport = NULL; - for (int i = 0; i < g.Viewports.Size && focused_viewport == NULL; i++) - if (g.PlatformIO.Platform_GetWindowFocus(g.Viewports[i])) - focused_viewport = g.Viewports[i]; - if (focused_viewport && g.PlatformLastFocusedViewport != focused_viewport->ID) - { - if (focused_viewport->LastFrontMostStampCount != g.WindowsFrontMostStampCount) - focused_viewport->LastFrontMostStampCount = ++g.WindowsFrontMostStampCount; - g.PlatformLastFocusedViewport = focused_viewport->ID; - } - } - // Create/resize/destroy platform windows to match each active viewport. // Skip the main viewport (index 0), which is always fully handled by the application! for (int i = 1; i < g.Viewports.Size; i++) @@ -3631,13 +3616,14 @@ void ImGui::UpdatePlatformWindows() } // Create window - bool is_new_window = (viewport->PlatformHandle == NULL && viewport->PlatformUserData == NULL && viewport->RendererUserData == NULL); - if (is_new_window && viewport->PlatformHandle == NULL && viewport->PlatformUserData == NULL) - g.PlatformIO.Platform_CreateWindow(viewport); - if (is_new_window && viewport->RendererUserData == NULL && g.PlatformIO.Renderer_CreateWindow != NULL) + bool is_new_window = (viewport->CreatedPlatformWindow == false); + if (is_new_window) { - g.PlatformIO.Renderer_CreateWindow(viewport); + g.PlatformIO.Platform_CreateWindow(viewport); + if (g.PlatformIO.Renderer_CreateWindow != NULL) + g.PlatformIO.Renderer_CreateWindow(viewport); viewport->RendererLastSize = viewport->Size; + viewport->CreatedPlatformWindow = true; } // Apply Position and Size (from ImGui to Platform/Renderer back-ends) @@ -3682,6 +3668,22 @@ void ImGui::UpdatePlatformWindows() // Clear request flags viewport->PlatformRequestClose = viewport->PlatformRequestMove = viewport->PlatformRequestResize = false; } + + // Update our implicit z-order knowledge of platform windows, which is used when the back-end cannot provide io.MouseHoveredViewport. + if (g.PlatformIO.Platform_GetWindowFocus != NULL) + { + ImGuiViewportP* focused_viewport = NULL; + for (int i = 0; i < g.Viewports.Size && focused_viewport == NULL; i++) + if (g.Viewports[i]->PlatformUserData != NULL || g.Viewports[i]->PlatformHandle != NULL || g.Viewports[i]->CreatedPlatformWindow) + if (g.PlatformIO.Platform_GetWindowFocus(g.Viewports[i])) + focused_viewport = g.Viewports[i]; + if (focused_viewport && g.PlatformLastFocusedViewport != focused_viewport->ID) + { + if (focused_viewport->LastFrontMostStampCount != g.WindowsFrontMostStampCount) + focused_viewport->LastFrontMostStampCount = ++g.WindowsFrontMostStampCount; + g.PlatformLastFocusedViewport = focused_viewport->ID; + } + } } // This is a default/basic function for performing the rendering/swap of multiple platform windows. diff --git a/imgui_internal.h b/imgui_internal.h index 603a31c7..5cc91ba9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -515,6 +515,7 @@ struct ImGuiViewportP : public ImGuiViewport int LastFrontMostStampCount; // Last stamp number from when a window hosted by this viewport was made front-most (by comparing this value between two viewport we have an implicit viewport z-order ImGuiID LastNameHash; ImVec2 LastPos; + bool CreatedPlatformWindow; float Alpha; // Window opacity (when dragging dockable windows/viewports we make them transparent) float LastAlpha; int PlatformMonitor; @@ -524,7 +525,7 @@ struct ImGuiViewportP : public ImGuiViewport ImDrawDataBuilder DrawDataBuilder; ImVec2 RendererLastSize; - ImGuiViewportP() { Idx = 1; LastFrameActive = LastFrameOverlayDrawList = LastFrontMostStampCount = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; PlatformMonitor = INT_MIN; Window = NULL; OverlayDrawList = NULL; RendererLastSize = ImVec2(-1.0f,-1.0f); } + ImGuiViewportP() { Idx = 1; LastFrameActive = LastFrameOverlayDrawList = LastFrontMostStampCount = -1; LastNameHash = 0; CreatedPlatformWindow = false; Alpha = LastAlpha = 1.0f; PlatformMonitor = INT_MIN; Window = NULL; OverlayDrawList = NULL; RendererLastSize = ImVec2(-1.0f,-1.0f); } ~ImGuiViewportP() { if (OverlayDrawList) IM_DELETE(OverlayDrawList); } ImRect GetRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } ImVec2 GetCenter() const{ return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); }