Windows, Viewport: fixed an issue where interrupting a viewport move with e.g. a ClearActiveID() call would leave the dragged viewport with the ImGuiViewportFlags_NoInputs flag.

Amend 6b7766817, 36055213c5, #5324.
Next would be good to amend the ImGuiViewportFlags_NoInputs clear to match the set logic.
This commit is contained in:
ocornut
2025-07-30 18:39:15 +09:00
parent 34debc733f
commit 80d78fad7c
3 changed files with 51 additions and 28 deletions

View File

@@ -62,6 +62,13 @@ Other Changes:
- Backends: Vulkan: Fixed texture update corruption introduced in 1.92.0,
affecting some drivers/setups. (#8801, #8755, #8840) [@Retro52, @Miolith]
Docking+Viewports Branch:
- Windows, Viewport: fixed an issue where interrupting a viewport move with
e.g. a ClearActiveID() call would leave the dragged viewport with the
normally temporary ImGuiViewportFlags_NoInputs flag, preventing further
interactions with the viewport. (#5324) (thanks @mdelaharpe)
-----------------------------------------------------------------------
VERSION 1.92.1 (Released 2025-07-09)

View File

@@ -4606,15 +4606,6 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
// Clear previous active id
if (g.ActiveId != 0)
{
// While most behaved code would make an effort to not steal active id during window move/drag operations,
// we at least need to be resilient to it. Canceling the move is rather aggressive and users of 'master' branch
// may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that.
if (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId)
{
IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() cancel MovingWindow\n");
g.MovingWindow = NULL;
}
// Store deactivate data
ImGuiDeactivatedItemData* deactivated_data = &g.DeactivatedItemData;
deactivated_data->ID = g.ActiveId;
@@ -4627,6 +4618,15 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
// One common scenario leading to this is: pressing Key ->NavMoveRequestApplyResult() -> ClearActiveID()
if (g.InputTextState.ID == g.ActiveId)
InputTextDeactivateHook(g.ActiveId);
// While most behaved code would make an effort to not steal active id during window move/drag operations,
// we at least need to be resilient to it. Canceling the move is rather aggressive and users of 'master' branch
// may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that.
if (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId)
{
IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() cancel MovingWindow\n");
StopMouseMovingWindow();
}
}
// Set active id
@@ -5207,6 +5207,34 @@ void ImGui::StartMouseMovingWindowOrNode(ImGuiWindow* window, ImGuiDockNode* nod
StartMouseMovingWindow(window);
}
// This is not 100% symetric with StartMouseMovingWindow().
// We do NOT clear ActiveID, because:
// - It would lead to rather confusing recursive code paths. Caller can call ClearActiveID() if desired.
// - Some code intentionally cancel moving but keep the ActiveID to lock inputs (e.g. code path taken when clicking a disabled item).
void ImGui::StopMouseMovingWindow()
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.MovingWindow;
// Ref commits 6b7766817, 36055213c for some partial history on checking if viewport != NULL.
if (window && window->Viewport)
{
// 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(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 = window->Viewport;
// Clear the NoInputs window flag set by the Viewport system in AddUpdateViewport()
window->Viewport->Flags &= ~ImGuiViewportFlags_NoInputs;
}
g.MovingWindow = NULL;
}
// Handle mouse moving window
// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing()
// FIXME: We don't have strong guarantee that g.MovingWindow stay synced with g.ActiveId == g.MovingWindow->MoveId.
@@ -5224,8 +5252,8 @@ void ImGui::UpdateMouseMovingWindowNewFrame()
ImGuiWindow* moving_window = g.MovingWindow->RootWindowDockTree;
// 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->Active);
if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos) && !window_disappared)
const bool window_disappeared = (!moving_window->WasActive && !moving_window->Active);
if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos) && !window_disappeared)
{
ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;
if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y)
@@ -5241,23 +5269,7 @@ void ImGui::UpdateMouseMovingWindowNewFrame()
}
else
{
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 (moving_window->Viewport && !IsDragDropPayloadBeingAccepted())
g.MouseViewport = moving_window->Viewport;
// Clear the NoInput window flag set by the Viewport system
if (moving_window->Viewport)
moving_window->Viewport->Flags &= ~ImGuiViewportFlags_NoInputs;
}
g.MovingWindow = NULL;
StopMouseMovingWindow();
ClearActiveID();
}
}
@@ -5299,6 +5311,9 @@ void ImGui::UpdateMouseMovingWindowEndFrame()
{
StartMouseMovingWindow(g.HoveredWindow); //-V595
// FIXME: In principal we might be able to call StopMouseMovingWindow() below.
// Please note how StartMouseMovingWindow() and StopMouseMovingWindow() and not entirely symetrical, at the later doesn't clear ActiveId.
// Cancel moving if clicked outside of title bar
if (g.IO.ConfigWindowsMoveFromTitleBarOnly)
if (!(root_window->Flags & ImGuiWindowFlags_NoTitleBar) || root_window->DockIsActive)

View File

@@ -3382,6 +3382,7 @@ namespace ImGui
IMGUI_API void FindHoveredWindowEx(const ImVec2& pos, bool find_first_and_in_any_viewport, ImGuiWindow** out_hovered_window, ImGuiWindow** out_hovered_window_under_moving_window);
IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window);
IMGUI_API void StartMouseMovingWindowOrNode(ImGuiWindow* window, ImGuiDockNode* node, bool undock);
IMGUI_API void StopMouseMovingWindow();
IMGUI_API void UpdateMouseMovingWindowNewFrame();
IMGUI_API void UpdateMouseMovingWindowEndFrame();