From a9ca61a7ce82b83a89c1a00c2cd7e53b0ae26926 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 2 Feb 2026 16:00:33 +0100 Subject: [PATCH 01/11] Fonts: fixed an issue where using PushFont() from the implicit/fallback "Debug" window when its recorded state is collapsed would incorrectly early out. (#9210, #8865) Amend 0e769c5, ca31693, d8da97f, 1bf41a0. --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 30 +++++++++++++++++------------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 80bd16b19..7e3e4ae40 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -78,6 +78,9 @@ Breaking Changes: has already been rendered. (#9162) [@ocornut, @cyfewlp] - Removed ImFontConfig::PixelSnapV added in 1.92 which turns out is unnecessary (and misdocumented). Post-rescale GlyphOffset is always rounded. + - Fixed an issue where using PushFont() from the implicit/fallback "Debug" window when + its recorded state is collapsed would incorrectly early out. This would break e.g. using + direct draw-list calls such as GetForegroundDrawList() with current font. (#9210, #8865) - Popups: changed compile-time 'ImGuiPopupFlags popup_flags = 1' default value to be '= 0' for BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid(), OpenPopupOnItemClick(). The default value has same meaning before and after. (#9157, #9146) diff --git a/imgui.cpp b/imgui.cpp index e8f54efd5..82f38ee8b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4566,13 +4566,13 @@ static void SetCurrentWindow(ImGuiWindow* window) g.CurrentDpiScale = 1.0f; // FIXME-DPI: WIP this is modified in docking if (window) { - bool backup_skip_items = window->SkipItems; - window->SkipItems = false; if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) { ImGuiViewport* viewport = window->Viewport; g.FontRasterizerDensity = (viewport->FramebufferScale.x != 0.0f) ? viewport->FramebufferScale.x : g.IO.DisplayFramebufferScale.x; // == SetFontRasterizerDensity() } + const bool backup_skip_items = window->SkipItems; + window->SkipItems = false; ImGui::UpdateCurrentFontSize(0.0f); window->SkipItems = backup_skip_items; ImGui::NavUpdateCurrentWindowIsScrollPushableX(); @@ -9000,16 +9000,6 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) g.Style.FontSizeBase = g.FontSizeBase; - // Early out to avoid hidden window keeping bakes referenced and out of GC reach. - // However this would leave a pretty subtle and damning error surface area if g.FontBaked was mismatching. - // FIXME: perhaps g.FontSize should be updated? - if (window != NULL && window->SkipItems) - { - ImGuiTable* table = g.CurrentTable; - if (table == NULL || (table->CurrentColumn != -1 && table->Columns[table->CurrentColumn].IsSkipItems == false)) // See 8465#issuecomment-2951509561 and #8865. Ideally the SkipItems=true in tables would be amended with extra data. - return; - } - // Restoring is pretty much only used by PopFont() float final_size = (restore_font_size_after_scaling > 0.0f) ? restore_font_size_after_scaling : 0.0f; if (final_size == 0.0f) @@ -9039,10 +9029,24 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) final_size = ImClamp(final_size, 1.0f, IMGUI_FONT_SIZE_MAX); if (g.Font != NULL && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures)) g.Font->CurrentRasterizerDensity = g.FontRasterizerDensity; + g.FontSize = final_size; + g.DrawListSharedData.FontSize = g.FontSize; + + // Early out to avoid hidden window keeping bakes referenced and out of GC reach. + // - However this leave a pretty subtle and damning error surface area if g.FontBaked was mismatching. + // Probably needs to be reevaluated into e.g. setting g.FontBaked = nullptr to mark it as dirty. + // - Note that 'PushFont(); Begin(); End(); PopFont()' from within any collapsed window is not compromised, because Begin() calls SetCurrentWindow()->...->UpdateCurrentSize() + if (window != NULL && window->SkipItems) + { + ImGuiTable* table = g.CurrentTable; + const bool allow_early_out = table == NULL || (table->CurrentColumn != -1 && table->Columns[table->CurrentColumn].IsSkipItems == false); // See 8465#issuecomment-2951509561 and #8865. Ideally the SkipItems=true in tables would be amended with extra data. + if (allow_early_out) + return; + } + g.FontBaked = (g.Font != NULL && window != NULL) ? g.Font->GetFontBaked(final_size) : NULL; g.FontBakedScale = (g.Font != NULL && window != NULL) ? (g.FontSize / g.FontBaked->Size) : 0.0f; - g.DrawListSharedData.FontSize = g.FontSize; g.DrawListSharedData.FontScale = g.FontBakedScale; } From 4b8e41cffb82b64777b6c682bedf33089517da04 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 30 Jan 2026 18:41:40 +0100 Subject: [PATCH 02/11] TabBar: expose NextScrollToTabId to internal API. --- imgui_internal.h | 3 ++- imgui_widgets.cpp | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/imgui_internal.h b/imgui_internal.h index b0da43d18..e9e644f64 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2792,7 +2792,7 @@ struct ImGuiTabItem ImGuiTabItemFlags Flags; int LastFrameVisible; int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance - float Offset; // Position relative to beginning of tab + float Offset; // Position relative to beginning of tab bar float Width; // Width currently displayed float ContentWidth; // Width of label + padding, stored during BeginTabItem() call (misnamed as "Content" would normally imply width of label only) float RequestedWidth; // Width optionally requested by caller, -1.0f is unused @@ -2813,6 +2813,7 @@ struct IMGUI_API ImGuiTabBar ImGuiID ID; // Zero for tab-bars used by docking ImGuiID SelectedTabId; // Selected tab/window ImGuiID NextSelectedTabId; // Next selected tab/window. Will also trigger a scrolling animation + ImGuiID NextScrollToTabId; ImGuiID VisibleTabId; // Can occasionally be != SelectedTabId (e.g. when previewing contents for Ctrl+Tab preview) int CurrFrameVisible; int PrevFrameVisible; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 0fabf7965..54ff81bd6 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -9801,6 +9801,11 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) // Setup next selected tab ImGuiID scroll_to_tab_id = 0; + if (tab_bar->NextScrollToTabId) + { + scroll_to_tab_id = tab_bar->NextScrollToTabId; + tab_bar->NextScrollToTabId = 0; + } if (tab_bar->NextSelectedTabId) { tab_bar->SelectedTabId = tab_bar->NextSelectedTabId; From 76860017d51f25f943a1e607ab795b3615acefb5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 2 Feb 2026 17:24:32 +0100 Subject: [PATCH 03/11] Clipper, Nav: fixed an UBSan warning when using in a ListClipper region . (#9160) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 3 ++- imgui_internal.h | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7e3e4ae40..253a4b020 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -179,6 +179,7 @@ Other Changes: used io.DisplayFramebufferScale (very old code), effectively making those actions faster on macOS/iOS retina screens. (changed this to use a style scale factor that's not fully formalized yet) + - Fixed an UBSan warning when using in a ListClipper region . (#9160) - Scrollbar: fixed a codepath leading to a divide-by-zero (which would not be noticeable by user but detected by sanitizers). (#9089) [@judicaelclair] - InvisibleButton: allow calling with size (0,0) to fit to available content diff --git a/imgui.cpp b/imgui.cpp index 82f38ee8b..799836955 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3399,7 +3399,8 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) if (is_nav_request) { data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringRect.Min.y, g.NavScoringRect.Max.y, nav_off_min, nav_off_max)); - data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringNoClipRect.Min.y, g.NavScoringNoClipRect.Max.y, nav_off_min, nav_off_max)); + if (!g.NavScoringNoClipRect.IsInverted()) + data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringNoClipRect.Min.y, g.NavScoringNoClipRect.Max.y, nav_off_min, nav_off_max)); } if (is_nav_request && (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && g.NavTabbingDir == -1) data->Ranges.push_back(ImGuiListClipperRange::FromIndices(clipper->ItemsCount - 1, clipper->ItemsCount)); diff --git a/imgui_internal.h b/imgui_internal.h index e9e644f64..50691e1b9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2352,7 +2352,7 @@ struct ImGuiContext ImGuiDir NavMoveDirForDebug; ImGuiDir NavMoveClipDir; // FIXME-NAV: Describe the purpose of this better. Might want to rename? ImRect NavScoringRect; // Rectangle used for scoring, in screen space. Based of window->NavRectRel[], modified for directional navigation scoring. - ImRect NavScoringNoClipRect; // Some nav operations (such as PageUp/PageDown) enforce a region which clipper will attempt to always keep submitted + ImRect NavScoringNoClipRect; // Some nav operations (such as PageUp/PageDown) enforce a region which clipper will attempt to always keep submitted. Unset/invalid if inverted. int NavScoringDebugCount; // Metrics for debugging int NavTabbingDir; // Generally -1 or +1, 0 when tabbing without a nav id int NavTabbingCounter; // >0 when counting items for tabbing From ea83628438f5d29f2b576b694efd3e864fc00b1c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 3 Feb 2026 17:33:45 +0100 Subject: [PATCH 04/11] Nav: fixed navigation cursor briefly appearing when using API to focus an InputText() in a window with _NoNavInputs flag. (#9214) Amend 1566c96cc --- imgui.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 799836955..d45bc03fb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3972,6 +3972,9 @@ void ImGui::RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFl return; if (id == g.LastItemData.ID && (g.LastItemData.ItemFlags & ImGuiItemFlags_NoNav)) return; + + // We don't early out on 'window->Flags & ImGuiWindowFlags_NoNavInputs' because it would be inconsistent with + // other code directly checking NavCursorVisible. Instead we aim for NavCursorVisible to always be false. ImGuiWindow* window = g.CurrentWindow; if (window->DC.NavHideHighlightOneFrame) return; @@ -12953,7 +12956,9 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind void ImGui::SetNavCursorVisible(bool visible) { ImGuiContext& g = *GImGui; - if (g.IO.ConfigNavCursorVisibleAlways) + if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + visible = false; + else if (g.IO.ConfigNavCursorVisibleAlways) visible = true; g.NavCursorVisible = visible; } @@ -12962,7 +12967,9 @@ void ImGui::SetNavCursorVisible(bool visible) void ImGui::SetNavCursorVisibleAfterMove() { ImGuiContext& g = *GImGui; - if (g.IO.ConfigNavCursorVisibleAuto) + if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + g.NavCursorVisible = false; + else if (g.IO.ConfigNavCursorVisibleAuto) g.NavCursorVisible = true; g.NavHighlightItemUnderNav = g.NavMousePosDirty = true; } @@ -13906,7 +13913,7 @@ void ImGui::NavUpdateCreateMoveRequest() IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", window ? window->Name : "", g.NavLayer); g.NavInitRequest = g.NavInitRequestFromMove = true; g.NavInitResult.ID = 0; - if (g.IO.ConfigNavCursorVisibleAuto) + if (g.IO.ConfigNavCursorVisibleAuto) // NO check for _NoNavInputs here as we assume MoveRequests cannot be created. g.NavCursorVisible = true; } From 226f62fa8fde6d51ed5fd2bf96d463c9ff08d0c7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Feb 2026 15:25:26 +0100 Subject: [PATCH 05/11] Demo: amend Shortcuts demo to clarify that ImGuiInputFlags_RouteOverActive may be used with focused route. (#9004) --- imgui_demo.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b88e7bf2a..7ab820573 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7916,6 +7916,11 @@ static void DemoWindowInputs() ImGui::CheckboxFlags("ImGuiInputFlags_Repeat", &route_options, ImGuiInputFlags_Repeat); ImGui::RadioButton("ImGuiInputFlags_RouteActive", &route_type, ImGuiInputFlags_RouteActive); ImGui::RadioButton("ImGuiInputFlags_RouteFocused (default)", &route_type, ImGuiInputFlags_RouteFocused); + ImGui::Indent(); + ImGui::BeginDisabled(route_type != ImGuiInputFlags_RouteFocused); + ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverActive##0", &route_options, ImGuiInputFlags_RouteOverActive); + ImGui::EndDisabled(); + ImGui::Unindent(); ImGui::RadioButton("ImGuiInputFlags_RouteGlobal", &route_type, ImGuiInputFlags_RouteGlobal); ImGui::Indent(); ImGui::BeginDisabled(route_type != ImGuiInputFlags_RouteGlobal); From 524f01d248599b55a56d8ba20879ffc4e107d6bd Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Feb 2026 16:29:26 +0100 Subject: [PATCH 06/11] Metrics: browsing font baked data persist tree state when e.g. using LoadAll. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index d45bc03fb..56655951b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -17313,7 +17313,7 @@ void ImGui::DebugNodeFont(ImFont* font) ImFontBaked* baked = &atlas->Builder->BakedPool[baked_n]; if (baked->OwnerFont != font) continue; - PushID(baked_n); + PushID(baked->BakedId); if (TreeNode("Glyphs", "Baked at { %.2fpx, d.%.2f }: %d glyphs%s", baked->Size, baked->RasterizerDensity, baked->Glyphs.Size, (baked->LastUsedFrame < atlas->Builder->FrameCount - 1) ? " *Unused*" : "")) { if (SmallButton("Load all")) From 1bcc23ef123869240971427902b32109c8157e24 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Feb 2026 16:46:15 +0100 Subject: [PATCH 07/11] Fonts: avoid baking ExtraSizeScale twice into Ascent/Descent. Amend 55ad3b4 With extreme values of ExtraSizeScale offset would be noticeable in Descent - TextLink() function - or Ascent - TableAngledHeadersRow() function. --- imgui_draw.cpp | 2 +- misc/freetype/imgui_freetype.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5c0767695..5466a809b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4699,7 +4699,7 @@ static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig { // FIXME-NEWFONTS: reevaluate how to use sizing metrics // FIXME-NEWFONTS: make use of line gap value - float scale_for_layout = bd_font_data->ScaleFactor * baked->Size; + float scale_for_layout = bd_font_data->ScaleFactor * baked->Size / src->ExtraSizeScale; int unscaled_ascent, unscaled_descent, unscaled_line_gap; stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); baked->Ascent = ImCeil(unscaled_ascent * scale_for_layout); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index c358d89db..447afe25b 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -451,7 +451,7 @@ static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* s { // Read metrics FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics; - const float scale = 1.0f / rasterizer_density; + const float scale = 1.0f / (rasterizer_density * src->ExtraSizeScale); baked->Ascent = (float)FT_CEIL(metrics.ascender) * scale; // The pixel extents above the baseline in pixels (typically positive). baked->Descent = (float)FT_CEIL(metrics.descender) * scale; // The extents below the baseline in pixels (typically negative). //LineSpacing = (float)FT_CEIL(metrics.height) * scale; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. From 5fe48b6a0e2e1c9d73d9d7f9ebbe42ced3c41e21 Mon Sep 17 00:00:00 2001 From: tanksdude <58898485+tanksdude@users.noreply.github.com> Date: Tue, 10 Feb 2026 07:40:52 -0800 Subject: [PATCH 08/11] Docs: fixed some typos (#9217) --- backends/imgui_impl_glfw.h | 2 +- docs/BACKENDS.md | 2 +- docs/CHANGELOG.txt | 4 ++-- examples/example_glfw_wgpu/CMakeLists.txt | 2 +- examples/example_glfw_wgpu/README.md | 2 +- examples/example_sdl2_wgpu/CMakeLists.txt | 2 +- examples/example_sdl2_wgpu/README.md | 2 +- examples/example_sdl3_wgpu/CMakeLists.txt | 2 +- examples/example_sdl3_wgpu/README.md | 2 +- imgui.cpp | 12 ++++++------ imgui.h | 2 +- imgui_draw.cpp | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index c01600d0c..7dc8cb5e1 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -48,7 +48,7 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_InstallEmscriptenCallbacks(GLFWwindow* wi IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window); IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window); -// GFLW callbacks options: +// GLFW callbacks options: // - Set 'chain_for_all_windows=true' to enable chaining callbacks for all windows (including secondary viewports created by backends or by user) IMGUI_IMPL_API void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows); diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index 62acb1e21..7839764cd 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -337,7 +337,7 @@ void MyImGuiBackend_UpdateTexture(ImTextureData* tex) { // Create texture based on tex->Width, tex->Height. // - Most backends only support tex->Format == ImTextureFormat_RGBA32. - // - Backends for particularly memory constrainted platforms may support tex->Format == ImTextureFormat_Alpha8. + // - Backends for particularly memory constrained platforms may support tex->Format == ImTextureFormat_Alpha8. // Upload all texture pixels // - Read from our CPU-side copy of the texture and copy to your graphics API. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 253a4b020..00349b9e7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -346,7 +346,7 @@ Other Changes: debug/metrics window is not in the same viewport as the table. - Backends: - NULL: added imgui_impl_null platform/renderer backend. - This is designed if you need to run e.g. context with no input or no ouput. + This is designed if you need to run e.g. context with no input or no output. - GLFW: fixed building on Linux platforms where Wayland headers are not available. (#9024, #8969, #8921, #8920) [@jagot] - GLFW: lower minimum requirement from GLFW 3.1 to GLFW 3.0. Though @@ -828,7 +828,7 @@ Breaking changes: which font input is providing which glyph. - Fonts: **IMPORTANT** on Thread Safety: - A few functions such as font->CalcTextSizeA() were by sheer luck (== accidentally) - thread-safe even thou we had never provided that guarantee before. They are + thread-safe even though we had never provided that guarantee before. They are definitively not thread-safe anymore as new glyphs may be loaded. - Textures: diff --git a/examples/example_glfw_wgpu/CMakeLists.txt b/examples/example_glfw_wgpu/CMakeLists.txt index 11248df26..86291f9e2 100644 --- a/examples/example_glfw_wgpu/CMakeLists.txt +++ b/examples/example_glfw_wgpu/CMakeLists.txt @@ -102,7 +102,7 @@ else() # Native/Desktop build option(DAWN_FETCH_DEPENDENCIES "Use fetch_dawn_dependencies.py as an alternative to using depot_tools" ON) set(DAWN_BUILD_MONOLITHIC_LIBRARY "STATIC" CACHE STRING "Build monolithic library: SHARED, STATIC, or OFF.") - option(DAWN_USE_GLFW OFF) # disable buildin GLFW in DAWN when we use SDL2 / SDL3 + option(DAWN_USE_GLFW OFF) # disable builtin GLFW in DAWN when we use SDL2 / SDL3 # Dawn builds many things by default - disable things we don't need option(DAWN_BUILD_SAMPLES "Enables building Dawn's samples" OFF) diff --git a/examples/example_glfw_wgpu/README.md b/examples/example_glfw_wgpu/README.md index 119647211..04320d22c 100644 --- a/examples/example_glfw_wgpu/README.md +++ b/examples/example_glfw_wgpu/README.md @@ -89,7 +89,7 @@ Once the procedure for the specific builder is generated, the build command is * --- ### CMake useful options -#### Generator types (alternative to **ninja** bulder): +#### Generator types (alternative to **ninja** builder): - `-G Ninja` to build with __ninja__ builder - `-G "Unix Makefiles"` to build with __make__ builder - `-G "Visual Studio 17 2022" -A x64` to create a VS 2022 solution (.sln) file, Windows only diff --git a/examples/example_sdl2_wgpu/CMakeLists.txt b/examples/example_sdl2_wgpu/CMakeLists.txt index c4c3eee86..ae0d626a1 100644 --- a/examples/example_sdl2_wgpu/CMakeLists.txt +++ b/examples/example_sdl2_wgpu/CMakeLists.txt @@ -92,7 +92,7 @@ else() # Native/Desktop build else() set(IMGUI_DAWN_DIR CACHE PATH "Path to Dawn repository") - option(DAWN_USE_GLFW OFF) # disable buildin GLFW in DAWN when we use SDL2 / SDL3 + option(DAWN_USE_GLFW OFF) # disable builtin GLFW in DAWN when we use SDL2 / SDL3 option(DAWN_FETCH_DEPENDENCIES "Use fetch_dawn_dependencies.py as an alternative to using depot_tools" ON) set(DAWN_BUILD_MONOLITHIC_LIBRARY "STATIC" CACHE STRING "Build monolithic library: SHARED, STATIC, or OFF.") diff --git a/examples/example_sdl2_wgpu/README.md b/examples/example_sdl2_wgpu/README.md index cdfd032da..afba7b857 100644 --- a/examples/example_sdl2_wgpu/README.md +++ b/examples/example_sdl2_wgpu/README.md @@ -89,7 +89,7 @@ Once the procedure for the specific builder is generated, the build command is * --- ### CMake useful options -#### Generator types (alternative to **ninja** bulder): +#### Generator types (alternative to **ninja** builder): - `-G Ninja` to build with __ninja__ builder - `-G "Unix Makefiles"` to build with __make__ builder - `-G "Visual Studio 17 2022" -A x64` to create a VS 2022 solution (.sln) file, Windows only diff --git a/examples/example_sdl3_wgpu/CMakeLists.txt b/examples/example_sdl3_wgpu/CMakeLists.txt index 0b8dc48e9..2f3d48f62 100644 --- a/examples/example_sdl3_wgpu/CMakeLists.txt +++ b/examples/example_sdl3_wgpu/CMakeLists.txt @@ -95,7 +95,7 @@ else() # Native/Desktop build else() set(IMGUI_DAWN_DIR CACHE PATH "Path to Dawn repository") - option(DAWN_USE_GLFW OFF) # disable buildin GLFW in DAWN when we use SDL2 / SDL3 + option(DAWN_USE_GLFW OFF) # disable builtin GLFW in DAWN when we use SDL2 / SDL3 option(DAWN_FETCH_DEPENDENCIES "Use fetch_dawn_dependencies.py as an alternative to using depot_tools" ON) set(DAWN_BUILD_MONOLITHIC_LIBRARY "STATIC" CACHE STRING "Build monolithic library: SHARED, STATIC, or OFF.") diff --git a/examples/example_sdl3_wgpu/README.md b/examples/example_sdl3_wgpu/README.md index bd7c33652..35857be9e 100644 --- a/examples/example_sdl3_wgpu/README.md +++ b/examples/example_sdl3_wgpu/README.md @@ -89,7 +89,7 @@ Once the procedure for the specific builder is generated, the build command is * --- ### CMake useful options -#### Generator types (alternative to **ninja** bulder): +#### Generator types (alternative to **ninja** builder): - `-G Ninja` to build with __ninja__ builder - `-G "Unix Makefiles"` to build with __make__ builder - `-G "Visual Studio 17 2022" -A x64` to create a VS 2022 solution (.sln) file, Windows only diff --git a/imgui.cpp b/imgui.cpp index 56655951b..35c7a7af2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -486,7 +486,7 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: io.Fonts->AddFontFromFileTTF("FontAwesome4.ttf", 0.0f, &cfg2); - You can use `Metrics/Debugger->Fonts->Font->Input Glyphs Overlap Detection Tool` to see list of glyphs available in multiple font sources. This can facilitate understanding which font input is providing which glyph. - Fonts: **IMPORTANT** on Thread Safety: - - A few functions such as font->CalcTextSizeA() were, by sheer luck (== accidentally) thread-safe even thou we had never provided that guarantee. They are definitively not thread-safe anymore as new glyphs may be loaded. + - A few functions such as font->CalcTextSizeA() were, by sheer luck (== accidentally) thread-safe even though we had never provided that guarantee. They are definitively not thread-safe anymore as new glyphs may be loaded. - Fonts: ImFont::FontSize was removed and does not make sense anymore. ImFont::LegacySize is the size passed to AddFont(). - Fonts: Removed support for PushFont(NULL) which was a shortcut for "default font". - Fonts: Renamed/moved 'io.FontGlobalScale' to 'style.FontScaleMain'. @@ -1467,7 +1467,7 @@ ImGuiStyle::ImGuiStyle() ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar - ScrollbarPadding = 2.0f; // Padding of scrollbar grab within its frame (same for both axises) + ScrollbarPadding = 2.0f; // Padding of scrollbar grab within its frame (same for both axes) GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. @@ -5215,7 +5215,7 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window) g.MovingWindow = window; } -// This is not 100% symetric with StartMouseMovingWindow(). +// This is not 100% symmetric 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). @@ -5296,7 +5296,7 @@ void ImGui::UpdateMouseMovingWindowEndFrame() StartMouseMovingWindow(hovered_window); //-V595 // FIXME: In principle 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. + // Please note how StartMouseMovingWindow() and StopMouseMovingWindow() and not entirely symmetrical, at the later doesn't clear ActiveId. // Cancel moving if clicked outside of title bar if ((hovered_window->BgClickFlags & ImGuiWindowBgClickFlags_Move) == 0) // set by io.ConfigWindowsMoveFromTitleBarOnly @@ -6704,7 +6704,7 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont size_desired[ImGuiAxis_Y] = (axis_mask & 2) ? size_contents.y + size_pad.y + decoration_h_without_scrollbars : window->Size.y; // Determine maximum window size - // Child windows are layed within their parent (unless they are also popups/menus) and thus have no restriction + // Child windows are laid within their parent (unless they are also popups/menus) and thus have no restriction ImVec2 size_max = ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Popup)) ? ImVec2(FLT_MAX, FLT_MAX) : ImGui::GetMainViewport()->WorkSize - style.DisplaySafeAreaPadding * 2.0f; if (window->Flags & ImGuiWindowFlags_Tooltip) @@ -8030,7 +8030,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) g.TooltipPreviousWindow = window; // Set default BgClickFlags - // This is set at the end of this function, so UpdateWindowManualResize()/ClampWindowPos() may use last-frame value if overriden by user code. + // This is set at the end of this function, so UpdateWindowManualResize()/ClampWindowPos() may use last-frame value if overridden by user code. // FIXME: The general intent is that we will later expose config options to default to enable scrolling + select scrolling mouse button. window->BgClickFlags = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->BgClickFlags : (g.IO.ConfigWindowsMoveFromTitleBarOnly ? ImGuiWindowBgClickFlags_None : ImGuiWindowBgClickFlags_Move); diff --git a/imgui.h b/imgui.h index 0706da641..8d0374b68 100644 --- a/imgui.h +++ b/imgui.h @@ -3815,7 +3815,7 @@ struct ImFontBaked unsigned int MetricsTotalSurface:26;// 3 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) unsigned int WantDestroy:1; // 0 // // Queued for destroy unsigned int LoadNoFallback:1; // 0 // // Disable loading fallback in lower-level calls. - unsigned int LoadNoRenderOnLayout:1;// 0 // // Enable a two-steps mode where CalcTextSize() calls will load AdvanceX *without* rendering/packing glyphs. Only advantagous if you know that the glyph is unlikely to actually be rendered, otherwise it is slower because we'd do one query on the first CalcTextSize and one query on the first Draw. + unsigned int LoadNoRenderOnLayout:1;// 0 // // Enable a two-steps mode where CalcTextSize() calls will load AdvanceX *without* rendering/packing glyphs. Only advantageous if you know that the glyph is unlikely to actually be rendered, otherwise it is slower because we'd do one query on the first CalcTextSize and one query on the first Draw. int LastUsedFrame; // 4 // // Record of that time this was bounds ImGuiID BakedId; // 4 // // Unique ID for this baked storage ImFont* OwnerFont; // 4-8 // in // Parent font diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5466a809b..dd66e24b7 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3695,7 +3695,7 @@ void ImFontAtlasFontDestroySourceData(ImFontAtlas* atlas, ImFontConfig* src) IM_UNUSED(atlas); // IF YOU GET A CRASH IN THE IM_FREE() CALL HERE AND USED AddFontFromMemoryTTF(): // - DUE TO LEGACY REASON AddFontFromMemoryTTF() TRANSFERS MEMORY OWNERSHIP BY DEFAULT. - // - IT WILL THEREFORE CRASH WHEN PASSED DATA WHICH MAY NOT BE FREEED BY IMGUI. + // - IT WILL THEREFORE CRASH WHEN PASSED DATA WHICH MAY NOT BE FREED BY IMGUI. // - USE `ImFontConfig font_cfg; font_cfg.FontDataOwnedByAtlas = false; io.Fonts->AddFontFromMemoryTTF(....., &cfg);` to disable passing ownership/ // WE WILL ADDRESS THIS IN A FUTURE REWORK OF THE API. if (src->FontDataOwnedByAtlas) From c71b2a1fe63ff935af7e05aa6079d6ba7f161cda Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 10 Feb 2026 17:56:37 +0100 Subject: [PATCH 09/11] Revert "Fonts: avoid baking ExtraSizeScale twice into Ascent/Descent." This reverts commit 1bcc23ef123869240971427902b32109c8157e24. --- imgui_draw.cpp | 2 +- misc/freetype/imgui_freetype.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index dd66e24b7..fd7c0be7e 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4699,7 +4699,7 @@ static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig { // FIXME-NEWFONTS: reevaluate how to use sizing metrics // FIXME-NEWFONTS: make use of line gap value - float scale_for_layout = bd_font_data->ScaleFactor * baked->Size / src->ExtraSizeScale; + float scale_for_layout = bd_font_data->ScaleFactor * baked->Size; int unscaled_ascent, unscaled_descent, unscaled_line_gap; stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); baked->Ascent = ImCeil(unscaled_ascent * scale_for_layout); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 447afe25b..c358d89db 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -451,7 +451,7 @@ static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* s { // Read metrics FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics; - const float scale = 1.0f / (rasterizer_density * src->ExtraSizeScale); + const float scale = 1.0f / rasterizer_density; baked->Ascent = (float)FT_CEIL(metrics.ascender) * scale; // The pixel extents above the baseline in pixels (typically positive). baked->Descent = (float)FT_CEIL(metrics.descender) * scale; // The extents below the baseline in pixels (typically negative). //LineSpacing = (float)FT_CEIL(metrics.height) * scale; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. From fd9873a5c2ed84c5cf080f894428c1020e83f782 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 10 Feb 2026 18:12:53 +0100 Subject: [PATCH 10/11] Tables: internals: extract TableSetColumnDisplayOrder() out of TableBeginApplyRequests() and clarify API limitations. --- imgui_internal.h | 1 + imgui_tables.cpp | 45 +++++++++++++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 50691e1b9..d596db4e4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3543,6 +3543,7 @@ namespace ImGui IMGUI_API float TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n); IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); + IMGUI_API void TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order); IMGUI_API void TableRemove(ImGuiTable* table); IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table); IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index d4e57e831..6eaa973af 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -699,7 +699,7 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table) } // Handle reordering request - // Note: we don't clear ReorderColumn after handling the request. + // Note: we don't clear ReorderColumn after handling the request (FIXME: clarify why or add a test). if (table->InstanceCurrent == 0) { if (table->HeldHeaderColumn == -1 && table->ReorderColumn != -1) @@ -711,24 +711,12 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table) // In the configuration below, moving C to the right of E will lead to: // ... C [D] E ---> ... [D] E C (Column name/index) // ... 2 3 4 ... 2 3 4 (Display order) - const int reorder_dir = table->ReorderColumnDir; - IM_ASSERT(reorder_dir == -1 || reorder_dir == +1); + IM_ASSERT(table->ReorderColumnDir == -1 || table->ReorderColumnDir == +1); IM_ASSERT(table->Flags & ImGuiTableFlags_Reorderable); ImGuiTableColumn* src_column = &table->Columns[table->ReorderColumn]; - ImGuiTableColumn* dst_column = &table->Columns[(reorder_dir == -1) ? src_column->PrevEnabledColumn : src_column->NextEnabledColumn]; - IM_UNUSED(dst_column); - const int src_order = src_column->DisplayOrder; - const int dst_order = dst_column->DisplayOrder; - src_column->DisplayOrder = (ImGuiTableColumnIdx)dst_order; - for (int order_n = src_order + reorder_dir; order_n != dst_order + reorder_dir; order_n += reorder_dir) - table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder -= (ImGuiTableColumnIdx)reorder_dir; - IM_ASSERT(dst_column->DisplayOrder == dst_order - reorder_dir); - - // Display order is stored in both columns->IndexDisplayOrder and table->DisplayOrder[]. Rebuild later from the former. - for (int column_n = 0; column_n < table->ColumnsCount; column_n++) - table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n; + ImGuiTableColumn* dst_column = &table->Columns[(table->ReorderColumnDir < 0) ? src_column->PrevEnabledColumn : src_column->NextEnabledColumn]; + TableSetColumnDisplayOrder(table, table->ReorderColumn, dst_column->DisplayOrder); table->ReorderColumnDir = 0; - table->IsSettingsDirty = true; } } @@ -742,6 +730,31 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table) } } +// Note that TableSetupScrollFreeze() enforce a display order range for frozen columns. +// So reordering a column across the frozen column barrier is illegal and will be undone. +void ImGui::TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order) +{ + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + IM_ASSERT(dst_order >= 0 && dst_order < table->ColumnsCount); + + ImGuiTableColumn* src_column = &table->Columns[column_n]; + const int src_order = src_column->DisplayOrder; + if (src_order == dst_order) + return; + const int reorder_dir = (dst_order < src_order) ? -1 : +1; + + src_column->DisplayOrder = (ImGuiTableColumnIdx)dst_order; + for (int order_n = src_order + reorder_dir; order_n != dst_order + reorder_dir; order_n += reorder_dir) + table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder -= (ImGuiTableColumnIdx)reorder_dir; + //IM_ASSERT(dst_column->DisplayOrder == dst_order - reorder_dir); + + // Display order is stored in both columns->IndexDisplayOrder and table->DisplayOrder[]. Rebuild later from the former. + // FIXME-OPT: If this is called multiple times we'd effectively have a O(N^2) thing going on. + for (int n = 0; n < table->ColumnsCount; n++) + table->DisplayOrderToIndex[table->Columns[n].DisplayOrder] = (ImGuiTableColumnIdx)n; + table->IsSettingsDirty = true; +} + // Adjust flags: default width mode + stretch columns are not allowed when auto extending static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags flags_in) { From 9f30044333a8259a21cac923edd273e171d07dcb Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 10 Feb 2026 20:47:56 +0100 Subject: [PATCH 11/11] Backends: GLFW: try to set IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND automatically if headers are not available. (#9225) Amend/fix 10d0162378 for system without X11/Wayland headers. (#8921, #8920, #8969) --- backends/imgui_impl_glfw.cpp | 10 ++++++++++ docs/CHANGELOG.txt | 1 + 2 files changed, 11 insertions(+) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index f166b45d2..da54589fe 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -29,6 +29,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-02-10: Try to set IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND automatically if corresponding headers are not accessible. (#9225) // 2025-12-12: Added IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND to forcefully disable either. // 2025-12-10: Avoid repeated glfwSetCursor()/glfwSetInputMode() calls when unnecessary. Lowers overhead for very high framerates (e.g. 10k+ FPS). // 2025-11-06: Lower minimum requirement to GLFW 3.0. Though a recent version e.g GLFW 3.4 is highly recommended. @@ -109,6 +110,15 @@ #pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is. #endif +#if defined(__has_include) +#if !__has_include() || !__has_include() +#define IMGUI_IMPL_GLFW_DISABLE_X11 +#endif +#if !__has_include() +#define IMGUI_IMPL_GLFW_DISABLE_WAYLAND +#endif +#endif + // GLFW #if !defined(IMGUI_IMPL_GLFW_DISABLE_X11) && (defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)) #define GLFW_HAS_X11 1 diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 00349b9e7..69da2270c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -219,6 +219,7 @@ Other Changes: Lowers overhead for very high framerates (e.g. 10k+ FPS). [@maxliani] - GLFW: Added IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND to forcefully disable either. (#9109, #9116) + Try to set them automatically if headers are not accessible. (#9225) - OpenGL3: Fixed embedded loader multiple init/shutdown cycles broken on some platforms. (#8792, #9112) - SDL2, SDL3: changed `GetClipboardText()` handler to return NULL on error aka