From 36133d8ac490bf8bae3390a398420ea948fd7ad9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 12 Sep 2025 16:03:18 +0200 Subject: [PATCH 01/19] InputText: Word-Wrap: hide vertical scrollbar but takes its width into account. (#3237, #952, #1062, #7363) Also increase IMGUI_VERSION_NUM for good measure, forgot to increase it when moving to public api. --- docs/CHANGELOG.txt | 6 +++--- imgui.h | 6 +++--- imgui_widgets.cpp | 14 ++++++++------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b50ad6816..bff030352 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,12 +56,12 @@ Other Changes: window has the ImGuiWindowFlags_NoNavFocus flag. (#8914) - Bullet: fixed tesselation amount which looked out of place in very large sizes. - InputText: added ImGuiInputTextFlags_WordWrap flag to word-wrap multi-line buffers. - (#3237, #952, #1062, #7363) + (#3237, #952, #1062, #7363). Current caveats: - This is marked as beta because not being tested enough. Please report any incorrect cursor movement, selection behavior etc. bug to #3237. - - Vertical scrollbar is made always visible. - - Wrapping points are not ideal. Wrapping of long words/sections (e.g. words + - Wrapping style is not ideal. Wrapping of long words/sections (e.g. words larger than total available width) may be particularly unpleasing. + - Wrapping width needs to always account for the possibility of a vertical scrollbar. - It is currently much slower than regular text fields. - Ballpark estimate of cost on my 2019 desktop PC: For a 100 KB text buffer: +~0.3 ms/+~1.0 ms (Optimized vs Debug builds). diff --git a/imgui.h b/imgui.h index 58c63f44a..8af72e2fc 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.3 WIP" -#define IMGUI_VERSION_NUM 19227 +#define IMGUI_VERSION_NUM 19228 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 @@ -1267,8 +1267,8 @@ enum ImGuiInputTextFlags_ // Multi-line Word-Wrapping [BETA] // - Not well tested yet. Please report any incorrect cursor movement, selection behavior etc. bug to https://github.com/ocornut/imgui/issues/3237. - // - Vertical scrollbar is made always visible. - // - Wrapping points are not ideal. Wrapping of long words/sections (e.g. words larger than total available width) may be particularly unpleasing. + // - Wrapping style is not ideal. Wrapping of long words/sections (e.g. words larger than total available width) may be particularly unpleasing. + // - Wrapping width needs to always account for the possibility of a vertical scrollbar. // - It is much slower than regular text fields. // Ballpark estimate of cost on my 2019 desktop PC: for a 100 KB text buffer: +~0.3 ms (Optimized) / +~1.0 ms (Debug build). // The CPU cost is very roughly proportional to text length, so a 10 KB buffer should cost about ten times less. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 4b680622f..50a2c896d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4672,10 +4672,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Ensure no clip rect so mouse hover can reach FramePadding edges - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoMove; - if (flags & ImGuiInputTextFlags_WordWrap) - window_flags |= ImGuiWindowFlags_AlwaysVerticalScrollbar; // FIXME-WORDWRAP: Makes things much simpler. Otherwise requires more work to track cursor reliably and avoid one-frame glitch. - bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), ImGuiChildFlags_Borders, window_flags); + bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove); g.NavActivateId = backup_activate_id; PopStyleVar(3); PopStyleColor(); @@ -4715,11 +4712,16 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0; const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0; - const bool is_wordwrap = (flags & ImGuiInputTextFlags_WordWrap) != 0; - const float wrap_width = is_wordwrap ? GetContentRegionAvail().x : 0.0f; if (is_resizable) IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! + // Word-wrapping: enforcing a fixed width not altered by vertical scrollbar makes things easier, notably to track cursor reliably and avoid one-frame glitches. + // Instead of using ImGuiWindowFlags_AlwaysVerticalScrollbar we account for that space if the scrollbar is not visible. + const bool is_wordwrap = (flags & ImGuiInputTextFlags_WordWrap) != 0; + float wrap_width = 0.0f; + if (is_wordwrap) + wrap_width = ImMax(1.0f, GetContentRegionAvail().x + (draw_window->ScrollbarY ? 0.0f : -g.Style.ScrollbarSize)); + const bool input_requested_by_nav = (g.ActiveId != id) && ((g.NavActivateId == id) && ((g.NavActivateFlags & ImGuiActivateFlags_PreferInput) || (g.NavInputSource == ImGuiInputSource_Keyboard))); const bool user_clicked = hovered && io.MouseClicked[0]; From 6d25cb844b1f828bc310f174d67b0fb1961701a5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 12 Sep 2025 16:41:05 +0200 Subject: [PATCH 02/19] CI: switch iOS build to macos-14 runner as macos-latest currently fails. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4ff14341e..783615aec 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -558,7 +558,7 @@ jobs: run: xcodebuild -project examples/example_apple_opengl2/example_apple_opengl2.xcodeproj -target example_osx_opengl2 iOS: - runs-on: macos-latest + runs-on: macos-14 steps: - uses: actions/checkout@v4 From 9f13684d706e7c717a208835955f13d19e0c23cc Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 12 Sep 2025 20:57:04 +0200 Subject: [PATCH 03/19] Examples: GLFW+OpenGL2: Fixed not applying content scale. (#8921) Note that this requires GLFW 3.3. --- docs/CHANGELOG.txt | 1 + examples/example_glfw_opengl2/main.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bff030352..d4523f7da 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -107,6 +107,7 @@ Other Changes: while navigating and to not close popup automatically. - CI: Updates Windows CI to use a more recent VulkanSDK. (#8925, #8778) [@yaz0r] - Examples: Android: Android+OpenGL3: update Gradle project (#8888, #8878) [@scribam] +- Examples: GLFW+OpenGL2: Fixed not applying content scale. (#8921) - Backends: SDL_GPU: Added ImGui_ImplSDLGPU3_InitInfo::SwapchainComposition and PresentMode to configure how secondary viewports are created. Currently only used multi-viewport mode. (#8892) [@PTSVU] diff --git a/examples/example_glfw_opengl2/main.cpp b/examples/example_glfw_opengl2/main.cpp index 411a5891d..4c19ffcc3 100644 --- a/examples/example_glfw_opengl2/main.cpp +++ b/examples/example_glfw_opengl2/main.cpp @@ -40,7 +40,8 @@ int main(int, char**) return 1; // Create window with graphics context - GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+OpenGL2 example", nullptr, nullptr); + float main_scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor()); // Valid on GLFW 3.3+ only + GLFWwindow* window = glfwCreateWindow((int)(1280 * main_scale), (int)(800 * main_scale), "Dear ImGui GLFW+OpenGL2 example", nullptr, nullptr); if (window == nullptr) return 1; glfwMakeContextCurrent(window); @@ -57,6 +58,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplOpenGL2_Init(); From cd476b27f8885ff7d81de032f26973131fa78ecb Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 12 Sep 2025 21:32:46 +0200 Subject: [PATCH 04/19] Examples: GLFW+Vulkan: Fixed not applying content scale. (#8921, #8756) --- docs/CHANGELOG.txt | 2 +- examples/example_glfw_vulkan/main.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d4523f7da..0a0acde7c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -107,7 +107,7 @@ Other Changes: while navigating and to not close popup automatically. - CI: Updates Windows CI to use a more recent VulkanSDK. (#8925, #8778) [@yaz0r] - Examples: Android: Android+OpenGL3: update Gradle project (#8888, #8878) [@scribam] -- Examples: GLFW+OpenGL2: Fixed not applying content scale. (#8921) +- Examples: GLFW+OpenGL2, GLFW+Vulkan: Fixed not applying content scale. (#8921, #8756) - Backends: SDL_GPU: Added ImGui_ImplSDLGPU3_InitInfo::SwapchainComposition and PresentMode to configure how secondary viewports are created. Currently only used multi-viewport mode. (#8892) [@PTSVU] diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index 7ad9778f1..ebc78bdd5 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -357,7 +357,8 @@ int main(int, char**) // Create window with Vulkan context glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+Vulkan example", nullptr, nullptr); + float main_scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor()); // Valid on GLFW 3.3+ only + GLFWwindow* window = glfwCreateWindow((int)(1280 * main_scale), (int)(800 * main_scale), "Dear ImGui GLFW+Vulkan example", nullptr, nullptr); if (!glfwVulkanSupported()) { printf("GLFW: Vulkan Not Supported\n"); @@ -393,6 +394,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplGlfw_InitForVulkan(window, true); ImGui_ImplVulkan_InitInfo init_info = {}; From 22a6a83c5467ca6b15c9bda4203b82afeca8fa5e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 15 Sep 2025 15:16:42 +0200 Subject: [PATCH 05/19] Backends: SDL3: use SDL_GetWindowDisplayScale() on Mac to output DisplayFrameBufferScale. The function is more reliable during resolution changes e.g. going fullscreen. (#8703, #4414) --- backends/imgui_impl_sdl3.cpp | 14 ++++++++++++-- docs/CHANGELOG.txt | 3 +++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 48e766bcd..17613d30a 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-15: Use SDL_GetWindowDisplayScale() on Mac to output DisplayFrameBufferScale. The function is more reliable during resolution changes e.g. going fullscreen. (#8703, #4414) // 2025-06-27: IME: avoid calling SDL_StartTextInput() again if already active. (#8727) // 2025-04-22: IME: honor ImGuiPlatformImeData->WantTextInput as an alternative way to call SDL_StartTextInput(), without IME being necessarily visible. // 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561) @@ -778,15 +779,24 @@ static void ImGui_ImplSDL3_UpdateGamepads() static void ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale(SDL_Window* window, ImVec2* out_size, ImVec2* out_framebuffer_scale) { int w, h; - int display_w, display_h; SDL_GetWindowSize(window, &w, &h); if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) w = h = 0; + +#if defined(__APPLE__) + float fb_scale_x = SDL_GetWindowDisplayScale(window); // Seems more reliable during resolution change (#8703) + float fb_scale_y = fb_scale_x; +#else + int display_w, display_h; SDL_GetWindowSizeInPixels(window, &display_w, &display_h); + float fb_scale_x = (w > 0) ? (float)display_w / w : 1.0f; + float fb_scale_y = (h > 0) ? (float)display_h / h : 1.0f; +#endif + if (out_size != nullptr) *out_size = ImVec2((float)w, (float)h); if (out_framebuffer_scale != nullptr) - *out_framebuffer_scale = (w > 0 && h > 0) ? ImVec2((float)display_w / w, (float)display_h / h) : ImVec2(1.0f, 1.0f); + *out_framebuffer_scale = ImVec2(fb_scale_x, fb_scale_y); } void ImGui_ImplSDL3_NewFrame() diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0a0acde7c..db4587e69 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -108,6 +108,9 @@ Other Changes: - CI: Updates Windows CI to use a more recent VulkanSDK. (#8925, #8778) [@yaz0r] - Examples: Android: Android+OpenGL3: update Gradle project (#8888, #8878) [@scribam] - Examples: GLFW+OpenGL2, GLFW+Vulkan: Fixed not applying content scale. (#8921, #8756) +- Backends: SDL3: use SDL_GetWindowDisplayScale() on Mac to obtain DisplayFrameBufferScale, + fixing incorrect values during resolution changes e.g. going fullscreen. + (#8703, #4414) [@jclounge] - Backends: SDL_GPU: Added ImGui_ImplSDLGPU3_InitInfo::SwapchainComposition and PresentMode to configure how secondary viewports are created. Currently only used multi-viewport mode. (#8892) [@PTSVU] From e044d99710cc1d7c451259cfeb440d5f84701466 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 15 Sep 2025 16:33:56 +0200 Subject: [PATCH 06/19] Examples: standardized all examples to have a base window size of 1280x800. --- examples/example_allegro5/main.cpp | 2 +- examples/example_apple_metal/main.mm | 2 +- examples/example_apple_opengl2/main.mm | 2 +- examples/example_glfw_metal/main.mm | 2 +- examples/example_glfw_wgpu/main.cpp | 2 +- examples/example_glut_opengl2/main.cpp | 2 +- examples/example_sdl2_directx11/main.cpp | 2 +- examples/example_sdl2_metal/main.mm | 2 +- examples/example_sdl2_opengl2/main.cpp | 2 +- examples/example_sdl2_opengl3/main.cpp | 2 +- examples/example_sdl2_sdlrenderer2/main.cpp | 2 +- examples/example_sdl2_vulkan/main.cpp | 2 +- examples/example_sdl3_metal/main.mm | 2 +- examples/example_sdl3_opengl3/main.cpp | 2 +- examples/example_sdl3_sdlgpu3/main.cpp | 2 +- examples/example_sdl3_sdlrenderer3/main.cpp | 2 +- examples/example_sdl3_vulkan/main.cpp | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/examples/example_allegro5/main.cpp b/examples/example_allegro5/main.cpp index cde2c676a..08b809e35 100644 --- a/examples/example_allegro5/main.cpp +++ b/examples/example_allegro5/main.cpp @@ -28,7 +28,7 @@ int main(int, char**) al_install_mouse(); al_init_primitives_addon(); al_set_new_display_flags(ALLEGRO_RESIZABLE); - ALLEGRO_DISPLAY* display = al_create_display(1280, 720); + ALLEGRO_DISPLAY* display = al_create_display(1280, 800); al_set_window_title(display, "Dear ImGui Allegro 5 example"); ALLEGRO_EVENT_QUEUE* queue = al_create_event_queue(); al_register_event_source(queue, al_get_display_event_source(display)); diff --git a/examples/example_apple_metal/main.mm b/examples/example_apple_metal/main.mm index 0349dfbdc..4904973ac 100644 --- a/examples/example_apple_metal/main.mm +++ b/examples/example_apple_metal/main.mm @@ -94,7 +94,7 @@ -(void)loadView { - self.view = [[MTKView alloc] initWithFrame:CGRectMake(0, 0, 1200, 720)]; + self.view = [[MTKView alloc] initWithFrame:CGRectMake(0, 0, 1200, 800)]; } -(void)viewDidLoad diff --git a/examples/example_apple_opengl2/main.mm b/examples/example_apple_opengl2/main.mm index 9b4fa1860..d7aa7eb5b 100644 --- a/examples/example_apple_opengl2/main.mm +++ b/examples/example_apple_opengl2/main.mm @@ -171,7 +171,7 @@ if (_window != nil) return (_window); - NSRect viewRect = NSMakeRect(100.0, 100.0, 100.0 + 1280.0, 100 + 720.0); + NSRect viewRect = NSMakeRect(100.0, 100.0, 100.0 + 1280.0, 100 + 800.0); _window = [[NSWindow alloc] initWithContentRect:viewRect styleMask:NSWindowStyleMaskTitled|NSWindowStyleMaskMiniaturizable|NSWindowStyleMaskResizable|NSWindowStyleMaskClosable backing:NSBackingStoreBuffered defer:YES]; [_window setTitle:@"Dear ImGui OSX+OpenGL2 Example"]; diff --git a/examples/example_glfw_metal/main.mm b/examples/example_glfw_metal/main.mm index 9f4b82c4f..4ec8b5927 100644 --- a/examples/example_glfw_metal/main.mm +++ b/examples/example_glfw_metal/main.mm @@ -61,7 +61,7 @@ int main(int, char**) // Create window with graphics context glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+Metal example", nullptr, nullptr); + GLFWwindow* window = glfwCreateWindow(1280, 800, "Dear ImGui GLFW+Metal example", nullptr, nullptr); if (window == nullptr) return 1; diff --git a/examples/example_glfw_wgpu/main.cpp b/examples/example_glfw_wgpu/main.cpp index e30df5662..670dd08c2 100644 --- a/examples/example_glfw_wgpu/main.cpp +++ b/examples/example_glfw_wgpu/main.cpp @@ -37,7 +37,7 @@ static WGPUSurface wgpu_surface = nullptr; static WGPUTextureFormat wgpu_preferred_fmt = WGPUTextureFormat_RGBA8Unorm; static WGPUSwapChain wgpu_swap_chain = nullptr; static int wgpu_swap_chain_width = 1280; -static int wgpu_swap_chain_height = 720; +static int wgpu_swap_chain_height = 800; // Forward declarations static bool InitWGPU(GLFWwindow* window); diff --git a/examples/example_glut_opengl2/main.cpp b/examples/example_glut_opengl2/main.cpp index e72b94830..72da416f9 100644 --- a/examples/example_glut_opengl2/main.cpp +++ b/examples/example_glut_opengl2/main.cpp @@ -48,7 +48,7 @@ int main(int argc, char** argv) glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS); #endif glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_MULTISAMPLE); - glutInitWindowSize(1280, 720); + glutInitWindowSize(1280, 800); glutCreateWindow("Dear ImGui GLUT+OpenGL2 Example"); // Setup GLUT display function diff --git a/examples/example_sdl2_directx11/main.cpp b/examples/example_sdl2_directx11/main.cpp index 2e347752f..a2b39f362 100644 --- a/examples/example_sdl2_directx11/main.cpp +++ b/examples/example_sdl2_directx11/main.cpp @@ -50,7 +50,7 @@ int main(int, char**) // Setup window float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+DirectX11 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+DirectX11 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(800 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); diff --git a/examples/example_sdl2_metal/main.mm b/examples/example_sdl2_metal/main.mm index 97a643759..80c7e7b1a 100644 --- a/examples/example_sdl2_metal/main.mm +++ b/examples/example_sdl2_metal/main.mm @@ -60,7 +60,7 @@ int main(int, char**) // Enable native IME. SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL+Metal example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL+Metal example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 800, SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); if (window == nullptr) { printf("Error creating window: %s\n", SDL_GetError()); diff --git a/examples/example_sdl2_opengl2/main.cpp b/examples/example_sdl2_opengl2/main.cpp index 7385f4cd1..a06b58c8c 100644 --- a/examples/example_sdl2_opengl2/main.cpp +++ b/examples/example_sdl2_opengl2/main.cpp @@ -47,7 +47,7 @@ int main(int, char**) SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(800 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); diff --git a/examples/example_sdl2_opengl3/main.cpp b/examples/example_sdl2_opengl3/main.cpp index c59836f6e..96631271b 100644 --- a/examples/example_sdl2_opengl3/main.cpp +++ b/examples/example_sdl2_opengl3/main.cpp @@ -81,7 +81,7 @@ int main(int, char**) SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(800 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); diff --git a/examples/example_sdl2_sdlrenderer2/main.cpp b/examples/example_sdl2_sdlrenderer2/main.cpp index 76f17d3f6..60b365e6e 100644 --- a/examples/example_sdl2_sdlrenderer2/main.cpp +++ b/examples/example_sdl2_sdlrenderer2/main.cpp @@ -44,7 +44,7 @@ int main(int, char**) // Create window with SDL_Renderer graphics context float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+SDL_Renderer example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+SDL_Renderer example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(800 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index de6745623..4a1228058 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -360,7 +360,7 @@ int main(int, char**) // Create window with Vulkan graphics context float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+Vulkan example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+Vulkan example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(800 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); diff --git a/examples/example_sdl3_metal/main.mm b/examples/example_sdl3_metal/main.mm index 98c4a9490..022e0f432 100644 --- a/examples/example_sdl3_metal/main.mm +++ b/examples/example_sdl3_metal/main.mm @@ -30,7 +30,7 @@ int main(int, char**) // Create SDL window graphics context float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); SDL_WindowFlags window_flags = SDL_WINDOW_METAL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+Metal example", (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+Metal example", (int)(1280 * main_scale), (int)(800 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); diff --git a/examples/example_sdl3_opengl3/main.cpp b/examples/example_sdl3_opengl3/main.cpp index 25b6b1937..36b5e2eba 100644 --- a/examples/example_sdl3_opengl3/main.cpp +++ b/examples/example_sdl3_opengl3/main.cpp @@ -70,7 +70,7 @@ int main(int, char**) SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); SDL_WindowFlags window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+OpenGL3 example", (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+OpenGL3 example", (int)(1280 * main_scale), (int)(800 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp index bef16fe5b..3f797ecd6 100644 --- a/examples/example_sdl3_sdlgpu3/main.cpp +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -37,7 +37,7 @@ int main(int, char**) // Create SDL window graphics context float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_GPU example", (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_GPU example", (int)(1280 * main_scale), (int)(800 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); diff --git a/examples/example_sdl3_sdlrenderer3/main.cpp b/examples/example_sdl3_sdlrenderer3/main.cpp index f98986943..2256b7da7 100644 --- a/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/examples/example_sdl3_sdlrenderer3/main.cpp @@ -34,7 +34,7 @@ int main(int, char**) // Create window with SDL_Renderer graphics context float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_Renderer example", (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_Renderer example", (int)(1280 * main_scale), (int)(800 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index 743e68dba..dd9a460c9 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -355,7 +355,7 @@ int main(int, char**) // Create window with Vulkan graphics context float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); SDL_WindowFlags window_flags = SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+Vulkan example", (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+Vulkan example", (int)(1280 * main_scale), (int)(800 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); From 3c6c5692b894252cdf3c5e6dae7cc5405b1f07b2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 15 Sep 2025 16:40:10 +0200 Subject: [PATCH 07/19] Examples: Win32+Vulkan, GLFW+Metal: Fixed not applying content scale. (#8921, #8756) Somehow it breaks in Win32+OpenGL3 example: when enabled Win32 applies some extra scale. --- docs/CHANGELOG.txt | 3 +- examples/example_glfw_metal/main.mm | 47 ++++++++++++++----------- examples/example_win32_opengl3/main.cpp | 12 +++++-- examples/example_win32_vulkan/main.cpp | 14 ++++++-- 4 files changed, 49 insertions(+), 27 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index db4587e69..766473516 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -107,7 +107,8 @@ Other Changes: while navigating and to not close popup automatically. - CI: Updates Windows CI to use a more recent VulkanSDK. (#8925, #8778) [@yaz0r] - Examples: Android: Android+OpenGL3: update Gradle project (#8888, #8878) [@scribam] -- Examples: GLFW+OpenGL2, GLFW+Vulkan: Fixed not applying content scale. (#8921, #8756) +- Examples: GLFW+OpenGL2, GLFW+Vulkan, GLFW+Metal, Win32+Vulkan: Fixed not applying + content scale consistently with other examples. (#8921, #8756) - Backends: SDL3: use SDL_GetWindowDisplayScale() on Mac to obtain DisplayFrameBufferScale, fixing incorrect values during resolution changes e.g. going fullscreen. (#8703, #4414) [@jclounge] diff --git a/examples/example_glfw_metal/main.mm b/examples/example_glfw_metal/main.mm index 4ec8b5927..cc86d655c 100644 --- a/examples/example_glfw_metal/main.mm +++ b/examples/example_glfw_metal/main.mm @@ -27,17 +27,40 @@ static void glfw_error_callback(int error, const char* description) int main(int, char**) { + glfwSetErrorCallback(glfw_error_callback); + if (!glfwInit()) + return 1; + + // Create window with graphics context + float main_scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor()); // Valid on GLFW 3.3+ only + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + GLFWwindow* window = glfwCreateWindow((int)(1280 * main_scale), (int)(800 * main_scale), "Dear ImGui GLFW+Metal example", nullptr, nullptr); + if (window == nullptr) + return 1; + // Setup Dear ImGui context IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls - // Setup style + // Setup Dear ImGui style ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + + id device = MTLCreateSystemDefaultDevice(); + id commandQueue = [device newCommandQueue]; + + // Setup Platform/Renderer backends + ImGui_ImplGlfw_InitForOpenGL(window, true); + ImGui_ImplMetal_Init(device); + // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. @@ -54,24 +77,6 @@ int main(int, char**) //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); - // Setup window - glfwSetErrorCallback(glfw_error_callback); - if (!glfwInit()) - return 1; - - // Create window with graphics context - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(1280, 800, "Dear ImGui GLFW+Metal example", nullptr, nullptr); - if (window == nullptr) - return 1; - - id device = MTLCreateSystemDefaultDevice(); - id commandQueue = [device newCommandQueue]; - - // Setup Platform/Renderer backends - ImGui_ImplGlfw_InitForOpenGL(window, true); - ImGui_ImplMetal_Init(device); - NSWindow *nswin = glfwGetCocoaWindow(window); CAMetalLayer *layer = [CAMetalLayer layer]; layer.device = device; diff --git a/examples/example_win32_opengl3/main.cpp b/examples/example_win32_opengl3/main.cpp index 8748ab777..648d0d969 100644 --- a/examples/example_win32_opengl3/main.cpp +++ b/examples/example_win32_opengl3/main.cpp @@ -36,11 +36,14 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Main code int main(int, char**) { + // Make process DPI aware and obtain main monitor scale + //ImGui_ImplWin32_EnableDpiAwareness(); // FIXME: This somehow doesn't work in the Win32+OpenGL example. Why? + float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); + // Create application window - //ImGui_ImplWin32_EnableDpiAwareness(); WNDCLASSEXW wc = { sizeof(wc), CS_OWNDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr }; ::RegisterClassExW(&wc); - HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui Win32+OpenGL3 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr); + HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui Win32+OpenGL3 Example", WS_OVERLAPPEDWINDOW, 100, 100, (int)(1280 * main_scale), (int)(800 * main_scale), nullptr, nullptr, wc.hInstance, nullptr); // Initialize OpenGL if (!CreateDeviceWGL(hwnd, &g_MainWindow)) @@ -67,6 +70,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsClassic(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplWin32_InitForOpenGL(hwnd); ImGui_ImplOpenGL3_Init(); diff --git a/examples/example_win32_vulkan/main.cpp b/examples/example_win32_vulkan/main.cpp index aa80e8696..b4b3a0860 100644 --- a/examples/example_win32_vulkan/main.cpp +++ b/examples/example_win32_vulkan/main.cpp @@ -342,11 +342,14 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Main code int main(int, char**) { + // Make process DPI aware and obtain main monitor scale + ImGui_ImplWin32_EnableDpiAwareness(); + float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); + // Create application window - //ImGui_ImplWin32_EnableDpiAwareness(); WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr }; ::RegisterClassExW(&wc); - HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui Win32+Vulkan Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr); + HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui Win32+Vulkan Example", WS_OVERLAPPEDWINDOW, 100, 100, (int)(1280 * main_scale), (int)(800 * main_scale), nullptr, nullptr, wc.hInstance, nullptr); ImVector extensions; extensions.push_back("VK_KHR_surface"); @@ -369,7 +372,7 @@ int main(int, char**) // Show the window // FIXME: Retrieve client size from window itself. ImGui_ImplVulkanH_Window* wd = &g_MainWindowData; - SetupVulkanWindow(wd, surface, 1280, 800); + SetupVulkanWindow(wd, surface, (int)(1280 * main_scale), (int)(800 * main_scale)); ::ShowWindow(hwnd, SW_SHOWDEFAULT); ::UpdateWindow(hwnd); @@ -384,6 +387,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplWin32_Init(hwnd); ImGui_ImplVulkan_InitInfo init_info = {}; From 10d0162378261ef3cbc92fb684236d7a0a5ac83a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 15 Sep 2025 18:20:07 +0200 Subject: [PATCH 08/19] Backends: GLFW: added ImGui_ImplGlfw_IsWayland(). (#8921, #8920) (technically presently untested but we've researched this) --- backends/imgui_impl_glfw.cpp | 51 ++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 0cb49fda2..a8696ade2 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -104,20 +104,25 @@ // GLFW #include - #ifdef _WIN32 #undef APIENTRY -#ifndef GLFW_EXPOSE_NATIVE_WIN32 +#ifndef GLFW_EXPOSE_NATIVE_WIN32 // for glfwGetWin32Window() #define GLFW_EXPOSE_NATIVE_WIN32 #endif -#include // for glfwGetWin32Window() -#endif -#ifdef __APPLE__ -#ifndef GLFW_EXPOSE_NATIVE_COCOA +#elif defined(__APPLE__) +#ifndef GLFW_EXPOSE_NATIVE_COCOA // for glfwGetCocoaWindow() #define GLFW_EXPOSE_NATIVE_COCOA #endif -#include // for glfwGetCocoaWindow() +#elif !defined(__EMSCRIPTEN__) +#ifndef GLFW_EXPOSE_NATIVE_X11 // for glfwGetX11Window() on Freedesktop (Linux, BSD, etc.) +#define GLFW_EXPOSE_NATIVE_X11 #endif +#ifndef GLFW_EXPOSE_NATIVE_WAYLAND +#define GLFW_EXPOSE_NATIVE_WAYLAND +#endif +#endif +#include +#undef Status // X11 headers are leaking this. #ifndef _WIN32 #include // for usleep() #endif @@ -144,8 +149,14 @@ #define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetGamepadState() new api #define GLFW_HAS_GETKEYNAME (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwGetKeyName() #define GLFW_HAS_GETERROR (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetError() +#define GLFW_HAS_GETPLATFORM (GLFW_VERSION_COMBINED >= 3400) // 3.4+ glfwGetPlatform() +#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +#define GLFW_HAS_X11_OR_WAYLAND 1 +#else +#define GLFW_HAS_X11_OR_WAYLAND 0 +#endif -// Map GLFWWindow* to ImGuiContext*. +// Map GLFWWindow* to ImGuiContext*. // - Would be simpler if we could use glfwSetWindowUserPointer()/glfwGetWindowUserPointer(), but this is a single and shared resource. // - Would be simpler if we could use e.g. std::map<> as well. But we don't. // - This is not particularly optimized as we expect size to be small and queries to be rare. @@ -155,14 +166,14 @@ static void ImGui_ImplGlfw_ContextMap_Add(GLFWwindow* window, ImGuiContext* ctx) static void ImGui_ImplGlfw_ContextMap_Remove(GLFWwindow* window) { for (ImGui_ImplGlfw_WindowToContext& entry : g_ContextMap) if (entry.Window == window) { g_ContextMap.erase_unsorted(&entry); return; } } static ImGuiContext* ImGui_ImplGlfw_ContextMap_Get(GLFWwindow* window) { for (ImGui_ImplGlfw_WindowToContext& entry : g_ContextMap) if (entry.Window == window) return entry.Context; return nullptr; } -// GLFW data enum GlfwClientApi { - GlfwClientApi_Unknown, GlfwClientApi_OpenGL, GlfwClientApi_Vulkan, + GlfwClientApi_Unknown, // Anything else fits here. }; +// GLFW data struct ImGui_ImplGlfw_Data { ImGuiContext* Context; @@ -172,6 +183,7 @@ struct ImGui_ImplGlfw_Data GLFWwindow* MouseWindow; GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT]; ImVec2 LastValidMousePos; + bool IsWayland; bool InstalledCallbacks; bool CallbacksChainForAllWindows; char BackendPlatformName[32]; @@ -216,6 +228,23 @@ static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData(GLFWwindow* window) } // Functions +static bool ImGui_ImplGlfw_IsWayland() +{ +#if GLFW_HAS_X11_OR_WAYLAND + return false; +#elif GLFW_HAS_GETPLATFORM + return glfwGetPlatform() == GLFW_PLATFORM_WAYLAND; +#else + const char* version = glfwGetVersionString(); + if (strstr(version, "Wayland") == NULL) // e.g. Ubuntu 22.04 ships with GLFW 3.3.6 compiled without Wayland + return false; +#ifdef GLFW_EXPOSE_NATIVE_X11 + if (glfwGetX11Display() != NULL) + return false; +#endif + return true; +#endif +} // Not static to allow third-party code to use that if they want to (but undocumented) ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode); @@ -365,7 +394,6 @@ static bool ImGui_ImplGlfw_ShouldChainCallback(ImGui_ImplGlfw_Data* bd, GLFWwind void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); - if (bd->PrevUserCallbackMousebutton != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) bd->PrevUserCallbackMousebutton(window, button, action, mods); @@ -630,6 +658,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw bd->Context = ImGui::GetCurrentContext(); bd->Window = window; bd->Time = 0.0; + bd->IsWayland = ImGui_ImplGlfw_IsWayland(); ImGui_ImplGlfw_ContextMap_Add(window, bd->Context); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); From 2675b7ca26978e76f6ee4fbba19cf3b9a2034661 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 15 Sep 2025 18:49:05 +0200 Subject: [PATCH 09/19] Backends: GLFW: Content Scales always reported as 1.0 on Wayland, FramebufferScale always reported as 1.0 on X11. (#8920, #8921) --- backends/imgui_impl_glfw.cpp | 19 ++++++++++++++++++- docs/CHANGELOG.txt | 6 ++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index a8696ade2..8e391b44a 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) +// 2025-09-15: Content Scales always reported as 1.0 on Wayland. FramebufferScale are always reported as 1.0 on X11. (#8920, #8921) // 2025-07-08: Made ImGui_ImplGlfw_GetContentScaleForWindow(), ImGui_ImplGlfw_GetContentScaleForMonitor() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) // 2025-06-18: Added support for multiple Dear ImGui contexts. (#8676, #8239, #8069) // 2025-06-11: Added ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) and ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) helper to facilitate making DPI-aware apps. @@ -906,6 +907,11 @@ static void ImGui_ImplGlfw_UpdateGamepads() // - Some accessibility applications are declaring virtual monitors with a DPI of 0.0f, see #7902. We preserve this value for caller to handle. float ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) { +#if GLFW_HAS_X11_OR_WAYLAND + if (ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window)) + if (bd->IsWayland) + return 1.0f; +#endif #if GLFW_HAS_PER_MONITOR_DPI && !(defined(__APPLE__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__)) float x_scale, y_scale; glfwGetWindowContentScale(window, &x_scale, &y_scale); @@ -918,6 +924,10 @@ float ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) float ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) { +#if GLFW_HAS_X11_OR_WAYLAND + if (ImGui_ImplGlfw_IsWayland()) // We can't access our bd->IsWayland cache for a monitor. + return 1.0f; +#endif #if GLFW_HAS_PER_MONITOR_DPI && !(defined(__APPLE__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__)) float x_scale, y_scale; glfwGetMonitorContentScale(monitor, &x_scale, &y_scale); @@ -934,10 +944,17 @@ static void ImGui_ImplGlfw_GetWindowSizeAndFramebufferScale(GLFWwindow* window, int display_w, display_h; glfwGetWindowSize(window, &w, &h); glfwGetFramebufferSize(window, &display_w, &display_h); + float fb_scale_x = (w > 0) ? (float)display_w / w : 1.0f; + float fb_scale_y = (h > 0) ? (float)display_h / h : 1.0f; +#if GLFW_HAS_X11_OR_WAYLAND + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); + if (!bd->IsWayland) + fb_scale_x = fb_scale_y = 1.0f; +#endif if (out_size != nullptr) *out_size = ImVec2((float)w, (float)h); if (out_framebuffer_scale != nullptr) - *out_framebuffer_scale = (w > 0 && h > 0) ? ImVec2((float)display_w / (float)w, (float)display_h / (float)h) : ImVec2(1.0f, 1.0f); + *out_framebuffer_scale = ImVec2(fb_scale_x, fb_scale_y); } void ImGui_ImplGlfw_NewFrame() diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 766473516..5cd953ea3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -109,6 +109,12 @@ Other Changes: - Examples: Android: Android+OpenGL3: update Gradle project (#8888, #8878) [@scribam] - Examples: GLFW+OpenGL2, GLFW+Vulkan, GLFW+Metal, Win32+Vulkan: Fixed not applying content scale consistently with other examples. (#8921, #8756) +- Backends: GLFW: distinguish X11 vs Wayland to fix various scaling issues. + (#8920, #8921) [@TheBrokenRail, @pthom, @ocornut] + - window/monitor content scales are always reported as 1.0 on Wayland. + - framebuffer scales are always reported as 1.0 on X11. (#8920, #8921) +- Backends: GLFW: + [@TheBrokenRail, @pthom, @ocornut] - Backends: SDL3: use SDL_GetWindowDisplayScale() on Mac to obtain DisplayFrameBufferScale, fixing incorrect values during resolution changes e.g. going fullscreen. (#8703, #4414) [@jclounge] From 72c00f39c14806fe1bc60219886c867c4c518e9f Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 15 Sep 2025 19:16:05 +0200 Subject: [PATCH 10/19] Backends: GLFW: fix ImGui_ImplGlfw_IsWayland() amend broken 10d0162. (#8921, #8920) Accidentally broke this while shuffling code... --- backends/imgui_impl_glfw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 8e391b44a..5a897eed8 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -231,7 +231,7 @@ static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData(GLFWwindow* window) // Functions static bool ImGui_ImplGlfw_IsWayland() { -#if GLFW_HAS_X11_OR_WAYLAND +#if !GLFW_HAS_X11_OR_WAYLAND return false; #elif GLFW_HAS_GETPLATFORM return glfwGetPlatform() == GLFW_PLATFORM_WAYLAND; From d92c8c6aff0fd11f28a542160c821218a63d43d9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 15 Sep 2025 19:20:56 +0200 Subject: [PATCH 11/19] Backends: SDL2: Content Scales are always reported as 1.0 on Wayland. (#8921) SDL_GetDisplayDPI() seems generally broken on X11/Wayland, but our logs shows that on Wayland we get both a content scale from SDL_GetDisplayDPI() and a framebuffer scale. --- backends/imgui_impl_glfw.cpp | 2 +- backends/imgui_impl_sdl2.cpp | 4 ++++ docs/CHANGELOG.txt | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 5a897eed8..42e02ccc8 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -29,7 +29,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-09-15: Content Scales always reported as 1.0 on Wayland. FramebufferScale are always reported as 1.0 on X11. (#8920, #8921) +// 2025-09-15: Content Scales are always reported as 1.0 on Wayland. FramebufferScale are always reported as 1.0 on X11. (#8920, #8921) // 2025-07-08: Made ImGui_ImplGlfw_GetContentScaleForWindow(), ImGui_ImplGlfw_GetContentScaleForMonitor() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) // 2025-06-18: Added support for multiple Dear ImGui contexts. (#8676, #8239, #8069) // 2025-06-11: Added ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) and ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) helper to facilitate making DPI-aware apps. diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 291edb811..08e7988e2 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-15: Content Scales are always reported as 1.0 on Wayland. (#8921) // 2025-07-08: Made ImGui_ImplSDL2_GetContentScaleForWindow(), ImGui_ImplSDL2_GetContentScaleForDisplay() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) // 2025-06-11: Added ImGui_ImplSDL2_GetContentScaleForWindow(SDL_Window* window) and ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index) helper to facilitate making DPI-aware apps. // 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561) @@ -719,6 +720,9 @@ float ImGui_ImplSDL2_GetContentScaleForWindow(SDL_Window* window) float ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index) { + const char* sdl_driver = SDL_GetCurrentVideoDriver(); + if (sdl_driver && strcmp(sdl_driver, "wayland") == 0) + return 1.0f; #if SDL_HAS_PER_MONITOR_DPI #if !defined(__APPLE__) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) float dpi = 0.0f; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5cd953ea3..9495d5af1 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -112,9 +112,9 @@ Other Changes: - Backends: GLFW: distinguish X11 vs Wayland to fix various scaling issues. (#8920, #8921) [@TheBrokenRail, @pthom, @ocornut] - window/monitor content scales are always reported as 1.0 on Wayland. - - framebuffer scales are always reported as 1.0 on X11. (#8920, #8921) -- Backends: GLFW: - [@TheBrokenRail, @pthom, @ocornut] + - framebuffer scales are always reported as 1.0 on X11. +- Backends: SDL2: window/monitor content scales are always reported as 1.0 on Wayland. + (#8920, #8921) [@TheBrokenRail, @pthom, @ocornut] - Backends: SDL3: use SDL_GetWindowDisplayScale() on Mac to obtain DisplayFrameBufferScale, fixing incorrect values during resolution changes e.g. going fullscreen. (#8703, #4414) [@jclounge] From 6274ca4266670fc4297b0377579978157098bbe9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 15 Sep 2025 19:28:01 +0200 Subject: [PATCH 12/19] Backends: GLFW: fixed build for Emscripten which doesn't expose glfw3native.h. Amend 10d0162 --- backends/imgui_impl_glfw.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 42e02ccc8..8a646b5dd 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -110,10 +110,12 @@ #ifndef GLFW_EXPOSE_NATIVE_WIN32 // for glfwGetWin32Window() #define GLFW_EXPOSE_NATIVE_WIN32 #endif +#include #elif defined(__APPLE__) #ifndef GLFW_EXPOSE_NATIVE_COCOA // for glfwGetCocoaWindow() #define GLFW_EXPOSE_NATIVE_COCOA #endif +#include #elif !defined(__EMSCRIPTEN__) #ifndef GLFW_EXPOSE_NATIVE_X11 // for glfwGetX11Window() on Freedesktop (Linux, BSD, etc.) #define GLFW_EXPOSE_NATIVE_X11 @@ -121,8 +123,8 @@ #ifndef GLFW_EXPOSE_NATIVE_WAYLAND #define GLFW_EXPOSE_NATIVE_WAYLAND #endif -#endif #include +#endif #undef Status // X11 headers are leaking this. #ifndef _WIN32 #include // for usleep() From 431f2c5abd2065be04772fedfe02120805305a97 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 15 Sep 2025 19:32:03 +0200 Subject: [PATCH 13/19] InputText: fixed dubious code handling ImGuiInputTextFlags_EscapeClearsAll. Specifically the missing = 0. Somehow only now got reported by Emscripten CI. --- imgui_widgets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 50a2c896d..412835892 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5180,7 +5180,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ apply_new_text = ""; apply_new_text_length = 0; value_changed = true; - IMSTB_TEXTEDIT_CHARTYPE empty_string; + char empty_string = 0; stb_textedit_replace(state, state->Stb, &empty_string, 0); } else if (strcmp(state->TextA.Data, state->TextToRevertTo.Data) != 0) From f6890ed007da2efee80a91f140bcb57a68811c22 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 17 Sep 2025 16:34:33 +0200 Subject: [PATCH 14/19] Nav, Inputs: fixed a crash that could occur when opening a popup following the processing of a global shortcut while no windows were focused. Regression test: "window_popup_from_shortcut" --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9495d5af1..b1575131c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -54,6 +54,8 @@ Other Changes: e.g. using clipper with ItemsHeight=1 in order to clip in pixel units. (#8886) - Nav: fixed Ctrl+Tab window appearing as empty when the sole active and focused window has the ImGuiWindowFlags_NoNavFocus flag. (#8914) +- Nav: fixed a crash that could occur when opening a popup following the processing + of a global shortcut while no windows were focused. - Bullet: fixed tesselation amount which looked out of place in very large sizes. - InputText: added ImGuiInputTextFlags_WordWrap flag to word-wrap multi-line buffers. (#3237, #952, #1062, #7363). Current caveats: diff --git a/imgui.cpp b/imgui.cpp index eb84cdd4c..514f1ecdc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -13413,6 +13413,9 @@ static ImVec2 ImGui::NavCalcPreferredRefPos() const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID; + if (source != ImGuiInputSource_Mouse && !activated_shortcut && window == NULL) + source = ImGuiInputSource_Mouse; + // Testing for !activated_shortcut here could in theory be removed if we decided that activating a remote shortcut altered one of the g.NavDisableXXX flag. if (source == ImGuiInputSource_Mouse) { @@ -13432,7 +13435,7 @@ static ImVec2 ImGui::NavCalcPreferredRefPos() ref_rect = WindowRectRelToAbs(window, window->NavRectRel[g.NavLayer]); // Take account of upcoming scrolling (maybe set mouse pos should be done in EndFrame?) - if (window->LastFrameActive != g.FrameCount && (window->ScrollTarget.x != FLT_MAX || window->ScrollTarget.y != FLT_MAX)) + if (window != NULL && window->LastFrameActive != g.FrameCount && (window->ScrollTarget.x != FLT_MAX || window->ScrollTarget.y != FLT_MAX)) { ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window); ref_rect.Translate(window->Scroll - next_scroll); From 6d834d325e3ccba9a972f974d281dbe5c17a31da Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 17 Sep 2025 17:36:47 +0200 Subject: [PATCH 15/19] Debug Tools: ID Stack Tool: fixed misleading/unnecessary run of UpdateDebugToolStackQueries() on first frame. (#4631) `if (g.FrameCount != tool->LastActiveFrame + 1)` test failing on first frame. Was not harmful but probably confusing in a debugger. --- imgui_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_internal.h b/imgui_internal.h index 8bd05c326..29cfda0e7 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2134,7 +2134,7 @@ struct ImGuiIDStackTool ImGuiTextBuffer ResultPathsBuf; ImGuiTextBuffer ResultTempBuf; - ImGuiIDStackTool() { memset(this, 0, sizeof(*this)); OptHexEncodeNonAsciiChars = true; CopyToClipboardLastTime = -FLT_MAX; } + ImGuiIDStackTool() { memset(this, 0, sizeof(*this)); LastActiveFrame = -1; OptHexEncodeNonAsciiChars = true; CopyToClipboardLastTime = -FLT_MAX; } }; //----------------------------------------------------------------------------- From 7e473d38d31c6944c9039976947ef16b796dce7c Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 17 Sep 2025 17:52:50 +0200 Subject: [PATCH 16/19] Debug Tools: ID Stack Tool: internal renaming (should be no-op). --- imgui.cpp | 32 ++++++++++++++++---------------- imgui_internal.h | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 514f1ecdc..94092c3e4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4069,7 +4069,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) WheelingWindowReleaseTimer = 0.0f; DebugDrawIdConflictsId = 0; - DebugHookIdInfo = 0; + DebugHookIdInfoId = 0; HoveredId = HoveredIdPreviousFrame = 0; HoveredIdPreviousFrameItemCount = 0; HoveredIdAllowOverlap = false; @@ -8980,7 +8980,7 @@ ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); #ifndef IMGUI_DISABLE_DEBUG_TOOLS ImGuiContext& g = *Ctx; - if (g.DebugHookIdInfo == id) + if (g.DebugHookIdInfoId == id) ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end); #endif return id; @@ -8992,7 +8992,7 @@ ImGuiID ImGuiWindow::GetID(const void* ptr) ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); #ifndef IMGUI_DISABLE_DEBUG_TOOLS ImGuiContext& g = *Ctx; - if (g.DebugHookIdInfo == id) + if (g.DebugHookIdInfoId == id) ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL); #endif return id; @@ -9004,7 +9004,7 @@ ImGuiID ImGuiWindow::GetID(int n) ImGuiID id = ImHashData(&n, sizeof(n), seed); #ifndef IMGUI_DISABLE_DEBUG_TOOLS ImGuiContext& g = *Ctx; - if (g.DebugHookIdInfo == id) + if (g.DebugHookIdInfoId == id) ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL); #endif return id; @@ -9067,7 +9067,7 @@ void ImGui::PushOverrideID(ImGuiID id) ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; #ifndef IMGUI_DISABLE_DEBUG_TOOLS - if (g.DebugHookIdInfo == id) + if (g.DebugHookIdInfoId == id) DebugHookIdInfo(id, ImGuiDataType_ID, NULL, NULL); #endif window->IDStack.push_back(id); @@ -9081,7 +9081,7 @@ ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed) ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); #ifndef IMGUI_DISABLE_DEBUG_TOOLS ImGuiContext& g = *GImGui; - if (g.DebugHookIdInfo == id) + if (g.DebugHookIdInfoId == id) DebugHookIdInfo(id, ImGuiDataType_String, str, str_end); #endif return id; @@ -9092,7 +9092,7 @@ ImGuiID ImGui::GetIDWithSeed(int n, ImGuiID seed) ImGuiID id = ImHashData(&n, sizeof(n), seed); #ifndef IMGUI_DISABLE_DEBUG_TOOLS ImGuiContext& g = *GImGui; - if (g.DebugHookIdInfo == id) + if (g.DebugHookIdInfoId == id) DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL); #endif return id; @@ -17661,21 +17661,21 @@ void ImGui::UpdateDebugToolStackQueries() ImGuiIDStackTool* tool = &g.DebugIDStackTool; // Clear hook when id stack tool is not visible - g.DebugHookIdInfo = 0; + g.DebugHookIdInfoId = 0; if (g.FrameCount != tool->LastActiveFrame + 1) return; // Update queries. The steps are: -1: query Stack, >= 0: query each stack item // We can only perform 1 ID Info query every frame. This is designed so the GetID() tests are cheap and constant-time - const ImGuiID query_id = g.HoveredIdPreviousFrame ? g.HoveredIdPreviousFrame : g.ActiveId; - if (tool->QueryId != query_id) + const ImGuiID query_main_id = g.HoveredIdPreviousFrame ? g.HoveredIdPreviousFrame : g.ActiveId; + if (tool->QueryMainId != query_main_id) { - tool->QueryId = query_id; + tool->QueryMainId = query_main_id; tool->StackLevel = -1; tool->Results.resize(0); tool->ResultPathsBuf.resize(0); } - if (query_id == 0) + if (query_main_id == 0) return; // Advance to next stack level when we got our result, or after 2 frames (in case we never get a result) @@ -17687,10 +17687,10 @@ void ImGui::UpdateDebugToolStackQueries() // Update hook stack_level = tool->StackLevel; if (stack_level == -1) - g.DebugHookIdInfo = query_id; - if (stack_level >= 0 && stack_level < tool->Results.Size) + g.DebugHookIdInfoId = query_main_id; + else if (stack_level >= 0 && stack_level < tool->Results.Size) { - g.DebugHookIdInfo = tool->Results[stack_level].ID; + g.DebugHookIdInfoId = tool->Results[stack_level].ID; tool->Results[stack_level].QueryFrameCount++; } } @@ -17801,7 +17801,7 @@ void ImGui::ShowIDStackToolWindow(bool* p_open) p = p_next; } } - Text("0x%08X", tool->QueryId); + Text("0x%08X", tool->QueryMainId); SameLine(); MetricsHelpMarker("Hover an item with the mouse to display elements of the ID Stack leading to the item's final ID.\nEach level of the stack correspond to a PushID() call.\nAll levels of the stack are hashed together to make the final ID of a widget (ID displayed at the bottom level of the stack).\nRead FAQ entry about the ID stack for details."); diff --git a/imgui_internal.h b/imgui_internal.h index 29cfda0e7..32d04df4e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2126,7 +2126,7 @@ struct ImGuiIDStackTool { int LastActiveFrame; int StackLevel; // -1: query stack and resize Results, >= 0: individual stack level - ImGuiID QueryId; // ID to query details for + ImGuiID QueryMainId; // ID to query details for ImVector Results; bool OptHexEncodeNonAsciiChars; bool OptCopyToClipboardOnCtrlC; @@ -2216,7 +2216,7 @@ struct ImGuiContext // Item/widgets state and tracking information ImGuiID DebugDrawIdConflictsId; // Set when we detect multiple items with the same identifier - ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by ID Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line] + ImGuiID DebugHookIdInfoId; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by ID Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line] ImGuiID HoveredId; // Hovered widget, filled during the frame ImGuiID HoveredIdPreviousFrame; int HoveredIdPreviousFrameItemCount; // Count numbers of items using the same ID as last frame's hovered id From 9cf9d2be8366a0b4193cfb31da911184b0db6898 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 17 Sep 2025 18:06:03 +0200 Subject: [PATCH 17/19] Debug Tools: ID Stack Tool: fixed a crash when using PushOverrideID(0) during a query. (#8937, #4631) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 11 +++++++++++ imgui_internal.h | 1 + 3 files changed, 14 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b1575131c..48de7e881 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -103,6 +103,8 @@ Other Changes: is now skipped. (#8904, #4631) - Debug Tools: ID Stack Tool: added option to hex-encode non-ASCII characters in output path. (#8904, #4631) +- Debug Tools: ID Stack Tool: fixed a crash when using PushOverrideID(0) during + a query. (#8937, #4631) - Debug Tools: Fixed assertion failure when opening a combo box while using io.ConfigDebugBeginReturnValueOnce/ConfigDebugBeginReturnValueLoop. (#8931) [@harrymander] - Demo: tweaked ShowFontSelector() and ShowStyleSelector() to update selection diff --git a/imgui.cpp b/imgui.cpp index 94092c3e4..88ceb1f6c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -17662,6 +17662,7 @@ void ImGui::UpdateDebugToolStackQueries() // Clear hook when id stack tool is not visible g.DebugHookIdInfoId = 0; + tool->QueryHookActive = false; if (g.FrameCount != tool->LastActiveFrame + 1) return; @@ -17687,11 +17688,15 @@ void ImGui::UpdateDebugToolStackQueries() // Update hook stack_level = tool->StackLevel; if (stack_level == -1) + { g.DebugHookIdInfoId = query_main_id; + tool->QueryHookActive = true; + } else if (stack_level >= 0 && stack_level < tool->Results.Size) { g.DebugHookIdInfoId = tool->Results[stack_level].ID; tool->Results[stack_level].QueryFrameCount++; + tool->QueryHookActive = true; } } @@ -17701,11 +17706,17 @@ void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* dat ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; ImGuiIDStackTool* tool = &g.DebugIDStackTool; + if (tool->QueryHookActive == false) + { + IM_ASSERT(id == 0); + return; + } // Step 0: stack query // This assumes that the ID was computed with the current ID stack, which tends to be the case for our widget. if (tool->StackLevel == -1) { + IM_ASSERT(tool->Results.Size == 0); tool->StackLevel++; tool->Results.resize(window->IDStack.Size + 1, ImGuiStackLevelInfo()); for (int n = 0; n < window->IDStack.Size + 1; n++) diff --git a/imgui_internal.h b/imgui_internal.h index 32d04df4e..d2a3f4d8b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2128,6 +2128,7 @@ struct ImGuiIDStackTool int StackLevel; // -1: query stack and resize Results, >= 0: individual stack level ImGuiID QueryMainId; // ID to query details for ImVector Results; + bool QueryHookActive; // Used to disambiguate the case where DebugHookIdInfoId == 0 which is valid. bool OptHexEncodeNonAsciiChars; bool OptCopyToClipboardOnCtrlC; float CopyToClipboardLastTime; From 70a43f30886f73d4119785a9615bb7233c92d690 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 17 Sep 2025 18:12:32 +0200 Subject: [PATCH 18/19] Fixed build with IMGUI_ENABLE_TEST_ENGINE. --- imgui.cpp | 2 +- imgui.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 88ceb1f6c..aff0f7b32 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -17833,7 +17833,7 @@ void ImGui::ShowIDStackToolWindow(bool* p_open) Text("- Path \"%s\"", tool->ResultTempBuf.c_str()); #ifdef IMGUI_ENABLE_TEST_ENGINE - Text("- Label \"%s\"", tool->QueryId ? ImGuiTestEngine_FindItemDebugLabel(&g, tool->QueryId) : ""); + Text("- Label \"%s\"", tool->QueryMainId ? ImGuiTestEngine_FindItemDebugLabel(&g, tool->QueryMainId) : ""); #endif Separator(); diff --git a/imgui.h b/imgui.h index 8af72e2fc..47fe424c5 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.3 WIP" -#define IMGUI_VERSION_NUM 19228 +#define IMGUI_VERSION_NUM 19229 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 From 1c544ee9416ec98e545e73636ba98dec5c2e18fa Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 17 Sep 2025 18:15:01 +0200 Subject: [PATCH 19/19] Version 1.92.3 --- docs/CHANGELOG.txt | 16 ++++++++-------- imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 48de7e881..01df5a742 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,27 +36,27 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.92.3 WIP (In Progress) + VERSION 1.92.3 (Released 2025-09-17) ----------------------------------------------------------------------- -Breaking Changes: +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.92.3 Other Changes: -- Scrollbar, Style: added configurable style.ScrollbarPadding value and corresponding - ImGuiStyleVar_ScrollbarPadding enum, instead of hardcoded computed default. (#8895) -- Fonts: fixed an assertion failure when a rectangle entry has been reused - 1024 times (e.g. due to constant change of font types). (#8906) [@cfillion] - Fonts: fixed merging a font and specifying a font target in DstFont that's not the last added font (regression in 1.92). (#8912) +- Fonts: fixed an assertion failure when a rectangle entry has been reused + 1024 times (e.g. due to constant change of font size). (#8906) [@cfillion] - Clipper, Tables: added ImGuiListClipperFlags_NoSetTableRowCounters as a way to disable the assumption that 1 clipper item == 1 table row, which breaks when e.g. using clipper with ItemsHeight=1 in order to clip in pixel units. (#8886) +- Scrollbar, Style: added configurable style.ScrollbarPadding value and corresponding + ImGuiStyleVar_ScrollbarPadding enum, instead of an hard-coded computed default. (#8895) - Nav: fixed Ctrl+Tab window appearing as empty when the sole active and focused window has the ImGuiWindowFlags_NoNavFocus flag. (#8914) - Nav: fixed a crash that could occur when opening a popup following the processing of a global shortcut while no windows were focused. -- Bullet: fixed tesselation amount which looked out of place in very large sizes. +- Bullet: fixed tessellation which looked out of place in very large sizes. - InputText: added ImGuiInputTextFlags_WordWrap flag to word-wrap multi-line buffers. (#3237, #952, #1062, #7363). Current caveats: - This is marked as beta because not being tested enough. @@ -64,7 +64,7 @@ Other Changes: - Wrapping style is not ideal. Wrapping of long words/sections (e.g. words larger than total available width) may be particularly unpleasing. - Wrapping width needs to always account for the possibility of a vertical scrollbar. - - It is currently much slower than regular text fields. + - It is currently much slower than regular text fields: - Ballpark estimate of cost on my 2019 desktop PC: For a 100 KB text buffer: +~0.3 ms/+~1.0 ms (Optimized vs Debug builds). - The CPU cost is very roughly proportional to text length, so a 10 KB buffer diff --git a/imgui.cpp b/imgui.cpp index aff0f7b32..22d371ad8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.3 WIP +// dear imgui, v1.92.3 // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 47fe424c5..aa44a51f3 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.3 WIP +// dear imgui, v1.92.3 // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.92.3 WIP" -#define IMGUI_VERSION_NUM 19229 +#define IMGUI_VERSION "1.92.3" +#define IMGUI_VERSION_NUM 19230 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d667c8b70..27d3300b9 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.3 WIP +// dear imgui, v1.92.3 // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 9b01047f0..8a629b44d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.3 WIP +// dear imgui, v1.92.3 // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index d2a3f4d8b..ece4afbd9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.3 WIP +// dear imgui, v1.92.3 // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 5b4e3e07d..f5c4c25aa 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.3 WIP +// dear imgui, v1.92.3 // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 412835892..776a7135c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.3 WIP +// dear imgui, v1.92.3 // (widgets code) /*