From 6b77668171240d52ffe85e1c6aa3ee24fe22aaf2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 9 Sep 2021 21:05:40 +0200 Subject: [PATCH] Viewports: Fixed a crash while a window owning its viewport disappear while being dragged. t would manifest when e.g. reconfiguring dock nodes while dragging. --- docs/CHANGELOG.txt | 4 +++- imgui.cpp | 29 ++++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ce1080790423..3cd090e68464 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -148,7 +148,9 @@ Docking+Viewports Branch: - Docking: fixed settings load issue when mouse wheeling. (#4310) - Docking + Drag and Drop: Fixed using BeginDragDropSource() or BeginDragDropTarget() inside a Begin() that returned false because the window is docked. (#4515) -- Viewports: Viewports: fixed unnecessary creation of temporary viewports when multiple docked windows +- Viewports: Fixed a crash while a window owning its viewport disappear while being dragged. + It would manifest when e.g. reconfiguring dock nodes while dragging. +- Viewports: Fixed unnecessary creation of temporary viewports when multiple docked windows got reassigned to a new node (created mid-frame) which already has a HostWindow. diff --git a/imgui.cpp b/imgui.cpp index d3f0391e233d..edbc0a15e59d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3690,7 +3690,10 @@ void ImGui::UpdateMouseMovingWindowNewFrame() KeepAliveID(g.ActiveId); IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindowDockTree); ImGuiWindow* moving_window = g.MovingWindow->RootWindowDockTree; - if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos)) + + // When a window stop being submitted while being dragged, it may will its viewport until next Begin() + const bool window_disappared = (!moving_window->WasActive || moving_window->Viewport == NULL); + if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos) && !window_disappared) { ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset; if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y) @@ -3707,17 +3710,20 @@ void ImGui::UpdateMouseMovingWindowNewFrame() } else { - // Try to merge the window back into the main viewport. - // This works because MouseViewport should be != MovingWindow->Viewport on release (as per code in UpdateViewports) - if (g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable) - UpdateTryMergeWindowIntoHostViewport(moving_window, g.MouseViewport); + if (!window_disappared) + { + // Try to merge the window back into the main viewport. + // This works because MouseViewport should be != MovingWindow->Viewport on release (as per code in UpdateViewports) + if (g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable) + UpdateTryMergeWindowIntoHostViewport(moving_window, g.MouseViewport); - // Restore the mouse viewport so that we don't hover the viewport _under_ the moved window during the frame we released the mouse button. - if (!IsDragDropPayloadBeingAccepted()) - g.MouseViewport = moving_window->Viewport; + // Restore the mouse viewport so that we don't hover the viewport _under_ the moved window during the frame we released the mouse button. + if (!IsDragDropPayloadBeingAccepted()) + g.MouseViewport = moving_window->Viewport; - // Clear the NoInput window flag set by the Viewport system - moving_window->Viewport->Flags &= ~ImGuiViewportFlags_NoInputs; // FIXME-VIEWPORT: Test engine managed to crash here because Viewport was NULL. + // Clear the NoInput window flag set by the Viewport system + moving_window->Viewport->Flags &= ~ImGuiViewportFlags_NoInputs; // FIXME-VIEWPORT: Test engine managed to crash here because Viewport was NULL. + } g.MovingWindow = NULL; ClearActiveID(); @@ -11855,7 +11861,8 @@ static void ImGui::UpdateViewportsNewFrame() // Update mouse reference viewport // (when moving a window we aim at its viewport, but this will be overwritten below if we go in drag and drop mode) - if (g.MovingWindow) + // (MovingViewport->Viewport will be NULL in the rare situation where the window disappared while moving, set UpdateMouseMovingWindowNewFrame() for details) + if (g.MovingWindow && g.MovingWindow->Viewport) g.MouseViewport = g.MovingWindow->Viewport; else g.MouseViewport = g.MouseLastHoveredViewport;