From c6e54c7ab54f1c96bf4a501e79c809d0b47d4e1d Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 13 Jan 2026 16:38:58 +0100 Subject: [PATCH 1/9] Comments about input queue being close to be supporting multi-thread. (#5772) --- imgui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 5a49b8918..5bbb31b9c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10483,6 +10483,8 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) #endif // Remaining events will be processed on the next frame + // FIXME-MULTITHREADING: io.AddKeyEvent() etc. calls are mostly thread-safe apart from the fact they push to this + // queue which may be resized here. Could potentially rework this to narrow down the section needing a mutex? (#5772) if (event_n == g.InputEventsQueue.Size) g.InputEventsQueue.resize(0); else From c91bcea7a8cb0271bbdb11f6f8c9c2e7cff8c84e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Jan 2026 13:30:19 +0100 Subject: [PATCH 2/9] Backends: SDLGPU3: fixed missing release of TexSamplerNearest. (#9196) Amend/fix 8b86c939c7e --- backends/imgui_impl_sdlgpu3.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 9019c7de3..975fcefb9 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -637,6 +637,7 @@ void ImGui_ImplSDLGPU3_DestroyDeviceObjects() if (bd->VertexShader) { SDL_ReleaseGPUShader(v->Device, bd->VertexShader); bd->VertexShader = nullptr; } if (bd->FragmentShader) { SDL_ReleaseGPUShader(v->Device, bd->FragmentShader); bd->FragmentShader = nullptr; } if (bd->TexSamplerLinear) { SDL_ReleaseGPUSampler(v->Device, bd->TexSamplerLinear); bd->TexSamplerLinear = nullptr; } + if (bd->TexSamplerNearest) { SDL_ReleaseGPUSampler(v->Device, bd->TexSamplerNearest); bd->TexSamplerNearest = nullptr; } if (bd->Pipeline) { SDL_ReleaseGPUGraphicsPipeline(v->Device, bd->Pipeline); bd->Pipeline = nullptr; } } From d12b1a938e27b4b71f4d7ae0995f6681ae47b7a9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 Jan 2026 11:37:55 +0100 Subject: [PATCH 3/9] Demo: improved Selectable() demos. (#9193) --- docs/CHANGELOG.txt | 2 ++ imgui.h | 2 +- imgui_demo.cpp | 53 +++++++++++++++++++++++++++++++++++++--------- imgui_widgets.cpp | 1 + 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e2f14edec..4e126395d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -198,6 +198,8 @@ Other Changes: - Debug Log: fixed incorrectly printing characters in IO log when submitting non-ASCII values to `io.AddInputCharacter()`. (#9099) - Debug Log: can output to debugger on Windows. (#5855) +- Demo: + - Slightly improve Selectable() demos. (#9193) - Backends: - DirectX10: added `SamplerNearest` in `ImGui_ImplDX10_RenderState`. (+renamed `SamplerDefault` to `SamplerLinear`, which was tagged as beta API) diff --git a/imgui.h b/imgui.h index 936ce0add..0706da641 100644 --- a/imgui.h +++ b/imgui.h @@ -1880,7 +1880,7 @@ enum ImGuiColorEditFlags_ ImGuiColorEditFlags_NoTooltip = 1 << 6, // // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview. ImGuiColorEditFlags_NoLabel = 1 << 7, // // ColorEdit, ColorPicker: disable display of inline text label (the label is still forwarded to the tooltip and picker). ImGuiColorEditFlags_NoSidePreview = 1 << 8, // // ColorPicker: disable bigger color preview on right side of the picker, use small color square preview instead. - ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source. + ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target/source. ColorButton: disable drag and drop source. ImGuiColorEditFlags_NoBorder = 1 << 10, // // ColorButton: disable border (which is enforced by default) ImGuiColorEditFlags_NoColorMarkers = 1 << 11, // // ColorEdit: disable rendering R/G/B/A color marker. May also be disabled globally by setting style.ColorMarkerSize = 0. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5db91155b..b88e7bf2a 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2309,15 +2309,45 @@ static void DemoWindowWidgetsSelectables() ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line"); - if (ImGui::TreeNode("Rendering more items on the same line")) + IMGUI_DEMO_MARKER("Widgets/Selectables/Multiple items on the same line"); + if (ImGui::TreeNode("Multiple items on the same line")) { - // (1) Using SetNextItemAllowOverlap() - // (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically. - static bool selected[3] = { false, false, false }; - ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1"); - ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2"); - ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3"); + // (1) + // - Using SetNextItemAllowOverlap() + // - Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically. + { + static bool selected[3] = {}; + ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1"); + ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2"); + ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3"); + } + + // (2) + // - Using ImGuiSelectableFlags_AllowOverlap is a shortcut for calling SetNextItemAllowOverlap() + // - No visible label, display contents inside the selectable bounds. + // - We don't maintain actual selection in this example to keep things simple. + ImGui::Spacing(); + { + static bool checked[5] = {}; + static int selected_n = 0; + const float color_marker_w = ImGui::CalcTextSize("x").x; + for (int n = 0; n < 5; n++) + { + ImGui::PushID(n); + ImGui::AlignTextToFramePadding(); + if (ImGui::Selectable("##selectable", selected_n == n, ImGuiSelectableFlags_AllowOverlap)) + selected_n = n; + ImGui::SameLine(0, 0); + ImGui::Checkbox("##check", &checked[n]); + ImGui::SameLine(); + ImVec4 color((n & 1) ? 1.0f : 0.2f, (n & 2) ? 1.0f : 0.2f, 0.2f, 1.0f); + ImGui::ColorButton("##color", color, ImGuiColorEditFlags_NoTooltip, ImVec2(color_marker_w, 0)); + ImGui::SameLine(); + ImGui::Text("Some label"); + ImGui::PopID(); + } + } + ImGui::TreePop(); } @@ -2368,13 +2398,14 @@ static void DemoWindowWidgetsSelectables() if (winning_state) ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f))); + const float size = ImGui::CalcTextSize("Sailor").x; for (int y = 0; y < 4; y++) for (int x = 0; x < 4; x++) { if (x > 0) ImGui::SameLine(); ImGui::PushID(y * 4 + x); - if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50))) + if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(size, size))) { // Toggle clicked cell + toggle neighbors selected[y][x] ^= 1; @@ -2397,7 +2428,9 @@ static void DemoWindowWidgetsSelectables() "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item " "basis using PushStyleVar(). You'll probably want to always keep your default situation to " "left-align otherwise it becomes difficult to layout multiple items on a same line"); + static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true }; + const float size = ImGui::CalcTextSize("(1.0,1.0)").x; for (int y = 0; y < 3; y++) { for (int x = 0; x < 3; x++) @@ -2407,7 +2440,7 @@ static void DemoWindowWidgetsSelectables() sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y); if (x > 0) ImGui::SameLine(); ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment); - ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80)); + ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(size, size)); ImGui::PopStyleVar(); } } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index de19ecf28..6dcb12a40 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6484,6 +6484,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl } // Initialize/override default color options +// FIXME: Could be moved to a simple IO field. void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags) { ImGuiContext& g = *GImGui; From ab6c9d9b128485d2c596d1bfd3bf4a4fdbac7e26 Mon Sep 17 00:00:00 2001 From: Tom Seddon Date: Sat, 24 Jan 2026 17:21:23 +0000 Subject: [PATCH 4/9] Ignore -Wsign-conversion warnings when building with gcc. (#9192) Co-authored-by: Tom Seddon --- imgui.cpp | 1 + imgui_draw.cpp | 1 + imgui_internal.h | 1 + imgui_tables.cpp | 1 + imgui_widgets.cpp | 1 + 5 files changed, 5 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 5bbb31b9c..6894b5dcf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1279,6 +1279,7 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: #pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#pragma GCC diagnostic ignored "-Wsign-conversion" // warning: conversion to 'xxxx' from 'xxxx' may change the sign of the result #endif // Debug options diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 4d386e56a..00e058351 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -82,6 +82,7 @@ Index of this file: #pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#pragma GCC diagnostic ignored "-Wsign-conversion" // warning: conversion to 'xxxx' from 'xxxx' may change the sign of the result #endif //------------------------------------------------------------------------- diff --git a/imgui_internal.h b/imgui_internal.h index 0f5e5d9cd..ad7a1479f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -106,6 +106,7 @@ Index of this file: #pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated +#pragma GCC diagnostic ignored "-Wsign-conversion" // warning: conversion to 'xxxx' from 'xxxx' may change the sign of the result #endif // In 1.89.4, we moved the implementation of "courtesy maths operators" from imgui_internal.h in imgui.h diff --git a/imgui_tables.cpp b/imgui_tables.cpp index bb2be7631..d4e57e831 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -240,6 +240,7 @@ Index of this file: #pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*' #pragma GCC diagnostic ignored "-Wstrict-overflow" #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wsign-conversion" // warning: conversion to 'xxxx' from 'xxxx' may change the sign of the result #endif //----------------------------------------------------------------------------- diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6dcb12a40..8911863da 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -92,6 +92,7 @@ Index of this file: #pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#pragma GCC diagnostic ignored "-Wsign-conversion" // warning: conversion to 'xxxx' from 'xxxx' may change the sign of the result #endif //------------------------------------------------------------------------- From 814c6a194bcb1172df8b8ac9d6520ac0e77654dc Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 Jan 2026 12:29:42 +0100 Subject: [PATCH 5/9] Log/Capture: fixed erroneously injecting extra carriage returns in output. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4e126395d..ceba9c0a7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -180,6 +180,8 @@ Other Changes: nesting a tooltip in a disabled block. (#9180, #7640) [@RegimantasSimkus] - Added GetItemFlags() in public API for consistency and to expose generic flags of last submitted item. (#9127) +- Log/Capture: fixed erroneously injecting extra carriage returns in output + buffer when ItemSpacing.y > FramePadding.y + 1. - Images: - Added style.ImageRounding, ImGuiStyleVar_ImageRounding to configure rounding of Image() widgets. (#2942, #845) diff --git a/imgui.cpp b/imgui.cpp index 6894b5dcf..7f8710cd9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15071,7 +15071,7 @@ void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* if (!text_end) text_end = FindRenderedTextEnd(text, text_end); - const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + g.Style.FramePadding.y + 1); + const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + ImMax(g.Style.FramePadding.y, g.Style.ItemSpacing.y) + 1); if (ref_pos) g.LogLinePosY = ref_pos->y; if (log_new_line) From 8306e32495448c21dc37973fa6dfc546d1a067d1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 28 Jan 2026 15:14:15 +0100 Subject: [PATCH 6/9] Nav: fixed speed scale for resizing/moving with keyboard/gamepad. (#323) Fix 04157da29. --- docs/CHANGELOG.txt | 4 ++++ imgui.cpp | 4 ++-- imgui_internal.h | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ceba9c0a7..1207595d2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -172,6 +172,10 @@ Other Changes: - Fixed remote/shortcut InputText() not teleporting mouse cursor when nav cursor is visible and `io.ConfigNavMoveSetMousePos` is enabled. - Fixed a looping/wrapping issue when done in menu layer. (#9178) + - Fixed speed scale for resizing/moving with keyboard/gamepad. We incorrectly + 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) - 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 7f8710cd9..4813c1bf1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7006,7 +7006,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, int* border_hove if (nav_resize_dir.x != 0.0f || nav_resize_dir.y != 0.0f) { const float NAV_RESIZE_SPEED = 600.0f; - const float resize_step = NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y); + const float resize_step = NAV_RESIZE_SPEED * g.IO.DeltaTime * GetScale(); g.NavWindowingAccumDeltaSize += nav_resize_dir * resize_step; g.NavWindowingAccumDeltaSize = ImMax(g.NavWindowingAccumDeltaSize, clamp_rect.Min - window->Pos - window->Size); // We need Pos+Size >= clmap_rect.Min, so Size >= clmap_rect.Min - Pos, so size_delta >= clmap_rect.Min - window->Pos - window->Size g.NavWindowingToggleLayer = false; @@ -14521,7 +14521,7 @@ static void ImGui::NavUpdateWindowing() if (nav_move_dir.x != 0.0f || nav_move_dir.y != 0.0f) { const float NAV_MOVE_SPEED = 800.0f; - const float move_step = NAV_MOVE_SPEED * io.DeltaTime * ImMin(io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); + const float move_step = NAV_MOVE_SPEED * io.DeltaTime * GetScale(); g.NavWindowingAccumDeltaPos += nav_move_dir * move_step; g.NavHighlightItemUnderNav = true; ImVec2 accum_floored = ImTrunc(g.NavWindowingAccumDeltaPos); diff --git a/imgui_internal.h b/imgui_internal.h index ad7a1479f..c17873ca4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3150,6 +3150,7 @@ namespace ImGui // - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. IMGUI_API ImGuiIO& GetIO(ImGuiContext* ctx); IMGUI_API ImGuiPlatformIO& GetPlatformIO(ImGuiContext* ctx); + inline float GetScale() { ImGuiContext& g = *GImGui; return g.Style._MainScale; } // FIXME-DPI: I don't want to formalize this just yet. Because reasons. Please don't use. inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; } IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id); From 960aff24fc7a238a11276e5b5ac650ce76bd61db Mon Sep 17 00:00:00 2001 From: Ahmed Samy Date: Tue, 27 Jan 2026 00:43:09 +0200 Subject: [PATCH 7/9] Backends: Win32: use XInput Packet to avoid resubmitting gamepad data. (#9202, #8556) --- backends/imgui_impl_win32.cpp | 8 ++++++++ docs/CHANGELOG.txt | 2 ++ 2 files changed, 10 insertions(+) diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index c344a1417..de92040aa 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-01-28: Inputs: Minor optimization not submitting gamepad input if packet number has not changed (reworked from 2025-09-23 attempt). (#9202, #8556) // 2025-12-03: Inputs: handle WM_IME_CHAR/WM_IME_COMPOSITION messages to support Unicode inputs on MBCS (non-Unicode) Windows. (#9099, #3653, #5961) // 2025-10-19: Inputs: Revert previous change to allow for io.ClearInputKeys() on focus-out not losing gamepad state. // 2025-09-23: Inputs: Minor optimization not submitting gamepad input if packet number has not changed. @@ -127,6 +128,7 @@ struct ImGui_ImplWin32_Data HMODULE XInputDLL; PFN_XInputGetCapabilities XInputGetCapabilities; PFN_XInputGetState XInputGetState; + DWORD XInputPacketNumber; #endif ImGui_ImplWin32_Data() { memset((void*)this, 0, sizeof(*this)); } @@ -358,6 +360,9 @@ static void ImGui_ImplWin32_UpdateGamepads(ImGuiIO& io) if (!bd->HasGamepad || bd->XInputGetState == nullptr || bd->XInputGetState(0, &xinput_state) != ERROR_SUCCESS) return; io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + if (bd->XInputPacketNumber != 0 && bd->XInputPacketNumber == xinput_state.dwPacketNumber) + return; + bd->XInputPacketNumber = xinput_state.dwPacketNumber; #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V) #define MAP_BUTTON(KEY_NO, BUTTON_ENUM) { io.AddKeyEvent(KEY_NO, (gamepad.wButtons & BUTTON_ENUM) != 0); } @@ -771,6 +776,9 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPA case WM_SETFOCUS: case WM_KILLFOCUS: io.AddFocusEvent(msg == WM_SETFOCUS); +#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD + bd->XInputPacketNumber = 0; // FIXME: Technically, calling io.ClearInputKeys() directly would require this as well. +#endif return 0; case WM_INPUTLANGCHANGE: ImGui_ImplWin32_UpdateKeyboardCodePage(io); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1207595d2..80bd16b19 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -229,6 +229,8 @@ Other Changes: devices. (#8784) [@FelixStach] - Win32: handle `WM_IME_CHAR`/`WM_IME_COMPOSITION` to support Unicode inputs on MBCS (non-Unicode) Windows. (#9099, #3653, #5961) [@ulhc, @ocornut, @Othereum] + - Win32: minor optimization not submitting gamepad input if packet number has not + changed (reworked previous 1.92.4). (#9202, #8556) [@AhmedSamyMousa, @MidTerm-CN] - Examples: - Win32+DirectX12: ignore seemingly incorrect `D3D12_MESSAGE_ID_FENCE_ZERO_WAIT` warning on startups on some setups. (#9084, #9093) [@RT2Code, @LeoGautheron] From 6cc7787c77c344d3ecead3665d1805cc89bcbb39 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 29 Jan 2026 14:12:57 +0100 Subject: [PATCH 8/9] Windows: shallow tweaks in window bg rendering to simplify diff w/ docking. --- imgui.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 4813c1bf1..e8f54efd5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7129,7 +7129,13 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar } if (override_alpha) bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT); - window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom); + if (bg_col & IM_COL32_A_MASK) + { + ImRect bg_rect(window->Pos + ImVec2(0, window->TitleBarHeight), window->Pos + window->Size); + ImDrawFlags bg_rounding_flags = (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom; + ImDrawList* bg_draw_list = window->DrawList; + bg_draw_list->AddRectFilled(bg_rect.Min, bg_rect.Max, bg_col, window_rounding, bg_rounding_flags); + } } // Title bar @@ -12781,6 +12787,7 @@ void ImGui::BringWindowToFocusFront(ImGuiWindow* window) } // Note technically focus related but rather adjacent and close to BringWindowToFocusFront() +// FIXME-FOCUS: Could opt-in/opt-out enable modal check like in FocusWindow(). void ImGui::BringWindowToDisplayFront(ImGuiWindow* window) { ImGuiContext& g = *GImGui; From 5166bec5d8293021d7396ab1d623aabe329b0d0a Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 29 Jan 2026 17:23:28 +0100 Subject: [PATCH 9/9] Scrollbar: rounding corners selected based on a generic helper. CalcRoundingFlagsForRectInRect() is backported and used multiple times by docking. --- imgui_draw.cpp | 11 +++++++++++ imgui_internal.h | 1 + imgui_widgets.cpp | 15 +-------------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 00e058351..5c0767695 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -6114,6 +6114,17 @@ void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomRight); } +ImDrawFlags ImGui::CalcRoundingFlagsForRectInRect(const ImRect& r_in, const ImRect& r_outer, float threshold) +{ + bool round_l = r_in.Min.x <= r_outer.Min.x + threshold; + bool round_r = r_in.Max.x >= r_outer.Max.x - threshold; + bool round_t = r_in.Min.y <= r_outer.Min.y + threshold; + bool round_b = r_in.Max.y >= r_outer.Max.y - threshold; + return ImDrawFlags_RoundCornersNone + | ((round_t && round_l) ? ImDrawFlags_RoundCornersTopLeft : 0) | ((round_t && round_r) ? ImDrawFlags_RoundCornersTopRight : 0) + | ((round_b && round_l) ? ImDrawFlags_RoundCornersBottomLeft : 0) | ((round_b && round_r) ? ImDrawFlags_RoundCornersBottomRight : 0); +} + // Helper for ColorPicker4() // NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that. // Spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding altogether. diff --git a/imgui_internal.h b/imgui_internal.h index c17873ca4..b0da43d18 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3606,6 +3606,7 @@ namespace ImGui IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col); IMGUI_API void RenderRectFilledInRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float fill_x0, float fill_x1, float rounding); IMGUI_API void RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding); + IMGUI_API ImDrawFlags CalcRoundingFlagsForRectInRect(const ImRect& r_in, const ImRect& r_outer, float threshold); // Widgets: Text IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 8911863da..0fabf7965 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -982,20 +982,7 @@ void ImGui::Scrollbar(ImGuiAxis axis) // Calculate scrollbar bounding box ImRect bb = GetWindowScrollbarRect(window, axis); - ImDrawFlags rounding_corners = ImDrawFlags_RoundCornersNone; - if (axis == ImGuiAxis_X) - { - rounding_corners |= ImDrawFlags_RoundCornersBottomLeft; - if (!window->ScrollbarY) - rounding_corners |= ImDrawFlags_RoundCornersBottomRight; - } - else - { - if ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) - rounding_corners |= ImDrawFlags_RoundCornersTopRight; - if (!window->ScrollbarX) - rounding_corners |= ImDrawFlags_RoundCornersBottomRight; - } + ImDrawFlags rounding_corners = CalcRoundingFlagsForRectInRect(bb, window->Rect(), g.Style.WindowBorderSize); float size_visible = window->InnerRect.Max[axis] - window->InnerRect.Min[axis]; float size_contents = window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f; ImS64 scroll = (ImS64)window->Scroll[axis];