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.
This commit is contained in:
ocornut 2021-09-09 21:05:40 +02:00
parent 9a49c1ddbd
commit 6b77668171
2 changed files with 21 additions and 12 deletions

View File

@ -148,7 +148,9 @@ Docking+Viewports Branch:
- Docking: fixed settings load issue when mouse wheeling. (#4310) - Docking: fixed settings load issue when mouse wheeling. (#4310)
- Docking + Drag and Drop: Fixed using BeginDragDropSource() or BeginDragDropTarget() inside a Begin() - Docking + Drag and Drop: Fixed using BeginDragDropSource() or BeginDragDropTarget() inside a Begin()
that returned false because the window is docked. (#4515) 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. got reassigned to a new node (created mid-frame) which already has a HostWindow.

View File

@ -3690,7 +3690,10 @@ void ImGui::UpdateMouseMovingWindowNewFrame()
KeepAliveID(g.ActiveId); KeepAliveID(g.ActiveId);
IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindowDockTree); IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindowDockTree);
ImGuiWindow* moving_window = 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; ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;
if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y) if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y)
@ -3707,17 +3710,20 @@ void ImGui::UpdateMouseMovingWindowNewFrame()
} }
else else
{ {
// Try to merge the window back into the main viewport. if (!window_disappared)
// This works because MouseViewport should be != MovingWindow->Viewport on release (as per code in UpdateViewports) {
if (g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable) // Try to merge the window back into the main viewport.
UpdateTryMergeWindowIntoHostViewport(moving_window, g.MouseViewport); // 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. // 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()) if (!IsDragDropPayloadBeingAccepted())
g.MouseViewport = moving_window->Viewport; g.MouseViewport = moving_window->Viewport;
// Clear the NoInput window flag set by the Viewport system // 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. moving_window->Viewport->Flags &= ~ImGuiViewportFlags_NoInputs; // FIXME-VIEWPORT: Test engine managed to crash here because Viewport was NULL.
}
g.MovingWindow = NULL; g.MovingWindow = NULL;
ClearActiveID(); ClearActiveID();
@ -11855,7 +11861,8 @@ static void ImGui::UpdateViewportsNewFrame()
// Update mouse reference viewport // 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) // (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; g.MouseViewport = g.MovingWindow->Viewport;
else else
g.MouseViewport = g.MouseLastHoveredViewport; g.MouseViewport = g.MouseLastHoveredViewport;