Fixed an assert in background dimming code, which could trigger after using gamepad/keyboard to move a window to another viewport. (#9053)

Due to missing ->Active check the dimming could render behind a window which was not submitted during the frame, appending to left-over ImDrawList data and in some situations tripping on the assert in RenderDimmedBackgroundBehindWindow().
The assumption that the PushClipRect won't match previous command is arguably a bit fragile, but this is what the assert is for.
This commit is contained in:
ocornut
2025-12-05 13:51:52 +01:00
parent 42e91c3155
commit 8e67fe13a5
2 changed files with 11 additions and 6 deletions

View File

@@ -85,6 +85,8 @@ Other Changes:
Docking+Viewports Branch:
- Fixed an assert in background dimming code, which could trigger after using
gamepad/keyboard to move a window to another viewport. (#9053) [@lut0pia, @ocornut]
- Backends:
- Win32: viewports created by backend forcefully direct messages to
DefWindowProcW() in order to support Unicode text input. (#9099, #3653, #5961) [@ulhc]

View File

@@ -6025,15 +6025,16 @@ static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32
// Draw behind window by moving the draw command at the FRONT of the draw list
{
// Draw list have been trimmed already, hence the explicit recreation of a draw command if missing.
// FIXME: This is creating complication, might be simpler if we could inject a drawlist in drawdata at a given position and not attempt to manipulate ImDrawCmd order.
// FIXME: This is a little bit complicated, solely to avoid creating/injecting an extra drawlist in drawdata.
ImDrawList* draw_list = window->RootWindowDockTree->DrawList;
draw_list->ChannelsMerge();
if (draw_list->CmdBuffer.Size == 0)
draw_list->AddDrawCmd();
draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to stricty ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that)
draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col);
ImDrawCmd cmd = draw_list->CmdBuffer.back();
IM_ASSERT(cmd.ElemCount == 6);
IM_ASSERT(cmd.ElemCount == 0);
draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col);
cmd = draw_list->CmdBuffer.back();
draw_list->CmdBuffer.pop_back();
draw_list->CmdBuffer.push_front(cmd);
draw_list->AddDrawCmd(); // We need to create a command as CmdBuffer.back().IdxOffset won't be correct if we append to same command.
@@ -6095,10 +6096,12 @@ static void ImGui::RenderDimmedBackgrounds()
{
// Draw dimming behind Ctrl+Tab target window and behind Ctrl+Tab UI window
RenderDimmedBackgroundBehindWindow(g.NavWindowingTargetAnim, GetColorU32(ImGuiCol_NavWindowingDimBg, g.DimBgRatio));
if (g.NavWindowingListWindow != NULL && g.NavWindowingListWindow->Viewport && g.NavWindowingListWindow->Viewport != g.NavWindowingTargetAnim->Viewport)
RenderDimmedBackgroundBehindWindow(g.NavWindowingListWindow, GetColorU32(ImGuiCol_NavWindowingDimBg, g.DimBgRatio));
viewports_already_dimmed[0] = g.NavWindowingTargetAnim->Viewport;
viewports_already_dimmed[1] = g.NavWindowingListWindow ? g.NavWindowingListWindow->Viewport : NULL;
if (g.NavWindowingListWindow != NULL && g.NavWindowingListWindow->Active && g.NavWindowingListWindow->Viewport && g.NavWindowingListWindow->Viewport != g.NavWindowingTargetAnim->Viewport)
{
RenderDimmedBackgroundBehindWindow(g.NavWindowingListWindow, GetColorU32(ImGuiCol_NavWindowingDimBg, g.DimBgRatio));
viewports_already_dimmed[1] = g.NavWindowingListWindow->Viewport;
}
// Draw border around Ctrl+Tab target window
ImGuiWindow* window = g.NavWindowingTargetAnim;