From 3563f1e270ea2c564a7860219e75eb18b2eb979c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 30 Sep 2025 18:39:34 +0200 Subject: [PATCH] Viewports: store ImGuiViewport* ParentViewport pointer as well. Backends: SDL3, Win32: use this pointer to reduce lookups. (#8948) --- backends/imgui_impl_sdl3.cpp | 17 ++++++++--------- backends/imgui_impl_win32.cpp | 11 +++++------ docs/CHANGELOG.txt | 1 + imgui.cpp | 11 +++++++++++ imgui.h | 3 ++- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index a581a7e3d..7b5b3a13a 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -1008,14 +1008,13 @@ struct ImGui_ImplSDL3_ViewportData ~ImGui_ImplSDL3_ViewportData() { IM_ASSERT(Window == nullptr && GLContext == nullptr); } }; -static SDL_Window* ImGui_ImplSDL3_GetSDLWindowFromViewportID(ImGuiID viewport_id) +static SDL_Window* ImGui_ImplSDL3_GetSDLWindowFromViewport(ImGuiViewport* viewport) { - if (viewport_id != 0) - if (ImGuiViewport* viewport = ImGui::FindViewportByID(viewport_id)) - { - SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle; - return SDL_GetWindowFromID(window_id); - } + if (viewport != nullptr) + { + SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle; + return SDL_GetWindowFromID(window_id); + } return nullptr; } @@ -1025,7 +1024,7 @@ static void ImGui_ImplSDL3_CreateWindow(ImGuiViewport* viewport) ImGui_ImplSDL3_ViewportData* vd = IM_NEW(ImGui_ImplSDL3_ViewportData)(); viewport->PlatformUserData = vd; - vd->ParentWindow = ImGui_ImplSDL3_GetSDLWindowFromViewportID(viewport->ParentViewportId); + vd->ParentWindow = ImGui_ImplSDL3_GetSDLWindowFromViewport(viewport->ParentViewport); ImGuiViewport* main_viewport = ImGui::GetMainViewport(); ImGui_ImplSDL3_ViewportData* main_viewport_data = (ImGui_ImplSDL3_ViewportData*)main_viewport->PlatformUserData; @@ -1114,7 +1113,7 @@ static void ImGui_ImplSDL3_UpdateWindow(ImGuiViewport* viewport) #ifndef __APPLE__ // On Mac, SDL3 Parenting appears to prevent viewport from appearing in another monitor // Update SDL3 parent if it changed _after_ creation. // This is for advanced apps that are manipulating ParentViewportID manually. - SDL_Window* new_parent = ImGui_ImplSDL3_GetSDLWindowFromViewportID(viewport->ParentViewportId); + SDL_Window* new_parent = ImGui_ImplSDL3_GetSDLWindowFromViewport(viewport->ParentViewport); if (new_parent != vd->ParentWindow) { vd->ParentWindow = new_parent; diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index bb7ef89d3..c2eb1b614 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -1123,11 +1123,10 @@ static void ImGui_ImplWin32_GetWin32StyleFromViewportFlags(ImGuiViewportFlags fl *out_ex_style |= WS_EX_TOPMOST; } -static HWND ImGui_ImplWin32_GetHwndFromViewportID(ImGuiID viewport_id) +static HWND ImGui_ImplWin32_GetHwndFromViewport(ImGuiViewport* viewport) { - if (viewport_id != 0) - if (ImGuiViewport* viewport = ImGui::FindViewportByID(viewport_id)) - return (HWND)viewport->PlatformHandle; + if (viewport != nullptr) + return (HWND)viewport->PlatformHandle; return nullptr; } @@ -1138,7 +1137,7 @@ static void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport) // Select style and parent window ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &vd->DwStyle, &vd->DwExStyle); - vd->HwndParent = ImGui_ImplWin32_GetHwndFromViewportID(viewport->ParentViewportId); + vd->HwndParent = ImGui_ImplWin32_GetHwndFromViewport(viewport->ParentViewport); // Create window RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) }; @@ -1201,7 +1200,7 @@ static void ImGui_ImplWin32_UpdateWindow(ImGuiViewport* viewport) // Update Win32 parent if it changed _after_ creation // Unlike style settings derived from configuration flags, this is more likely to change for advanced apps that are manipulating ParentViewportID manually. - HWND new_parent = ImGui_ImplWin32_GetHwndFromViewportID(viewport->ParentViewportId); + HWND new_parent = ImGui_ImplWin32_GetHwndFromViewport(viewport->ParentViewport); if (new_parent != vd->HwndParent) { // Win32 windows can either have a "Parent" (for WS_CHILD window) or an "Owner" (which among other thing keeps window above its owner). diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7c46aa333..0ecec67a4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -118,6 +118,7 @@ Docking+Viewports Branch: Note that for GLFW/SDL2/OSX backends, which do not support honoring ParentViewportID. setting io.ConfigViewportsNoDefaultParent=true will align imgui's expectation with what the backend does. +- Viewports: storing `ImGuiViewport* ParentViewport` pointer along with ParentViewportID. - Viewports: DestroyContext() does not call DestroyPlatformWindows() anymore at it assumed to be unnecessary as backensd should have done it and we check that backends have been shutdown since 1.90.4. Changed into asserts. (#7175, #8945) diff --git a/imgui.cpp b/imgui.cpp index 2cd8fcdea..bc13fc17e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -17023,11 +17023,22 @@ void ImGui::WindowSyncOwnedViewport(ImGuiWindow* window, ImGuiWindow* parent_win // Update parent viewport ID // (the !IsFallbackWindow test mimic the one done in WindowSelectViewport()) if (window->WindowClass.ParentViewportId != (ImGuiID)-1) + { + ImGuiID old_parent_viewport_id = window->Viewport->ParentViewportId; window->Viewport->ParentViewportId = window->WindowClass.ParentViewportId; + if (window->Viewport->ParentViewportId != old_parent_viewport_id) + window->Viewport->ParentViewport = FindViewportByID(window->Viewport->ParentViewportId); + } else if ((window_flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && parent_window_in_stack && (!parent_window_in_stack->IsFallbackWindow || parent_window_in_stack->WasActive)) + { + window->Viewport->ParentViewport = parent_window_in_stack->Viewport; window->Viewport->ParentViewportId = parent_window_in_stack->Viewport->ID; + } else + { + window->Viewport->ParentViewport = g.IO.ConfigViewportsNoDefaultParent ? NULL : GetMainViewport(); window->Viewport->ParentViewportId = g.IO.ConfigViewportsNoDefaultParent ? 0 : IMGUI_VIEWPORT_DEFAULT_ID; + } } // Called by user at the end of the main loop, after EndFrame() diff --git a/imgui.h b/imgui.h index a06efdd7b..57dd2773a 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.4 WIP" -#define IMGUI_VERSION_NUM 19233 +#define IMGUI_VERSION_NUM 19234 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 #define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch. @@ -4044,6 +4044,7 @@ struct ImGuiViewport ImVec2 WorkSize; // Work Area: Size of the viewport minus task bars, menu bars, status bars (<= Size) float DpiScale; // 1.0f = 96 DPI = No extra scale. ImGuiID ParentViewportId; // (Advanced) 0: no parent. Instruct the platform backend to setup a parent/child relationship between platform windows. + ImGuiViewport* ParentViewport; // (Advanced) == ImGui::FindViewportByID(ParentViewportId) ImDrawData* DrawData; // The ImDrawData corresponding to this viewport. Valid after Render() and until the next call to NewFrame(). // Platform/Backend Dependent Data