From 960921f03a2bf628a802b4611af9fc3c3c9430fe Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 3 Jan 2026 01:07:58 +0100 Subject: [PATCH 01/25] Happy new year! --- LICENSE.txt | 2 +- imgui.cpp | 2 +- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 00ae473a..d5ba3155 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2025 Omar Cornut +Copyright (c) 2014-2026 Omar Cornut Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/imgui.cpp b/imgui.cpp index c87fa3eb..6ba9d0b4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -27,7 +27,7 @@ // Everything else should be asked in 'Issues'! We are building a database of cross-linked knowledge there. // Since 1.92, we encourage font loading questions to also be posted in 'Issues'. -// Copyright (c) 2014-2025 Omar Cornut +// Copyright (c) 2014-2026 Omar Cornut // Developed by Omar Cornut and every direct or indirect contributors to the GitHub. // See LICENSE.txt for copyright and licensing details (standard MIT License). // This library is free but needs your support to sustain development and maintenance. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b5d7e0b4..b01c8694 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8108,7 +8108,7 @@ void ImGui::ShowAboutWindow(bool* p_open) ImGui::TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding"); ImGui::Separator(); - ImGui::Text("(c) 2014-2025 Omar Cornut"); + ImGui::Text("(c) 2014-2026 Omar Cornut"); ImGui::Text("Developed by Omar Cornut and all Dear ImGui contributors."); ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information."); ImGui::Text("If your company uses this, please consider funding the project."); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 494237d5..b839291b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -5732,7 +5732,7 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, Im } // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. -// DO NOT CALL DIRECTLY THIS WILL CHANGE WILDLY IN 2025-2025. Use ImDrawList::AddText(). +// DO NOT CALL DIRECTLY THIS WILL CHANGE WILDLY IN 2026. Use ImDrawList::AddText(). void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, ImDrawTextFlags flags) { // Align to be pixel perfect From 25158fe33bd22871eab47b4a06f951fd6655fad8 Mon Sep 17 00:00:00 2001 From: Sammy Fatnassi Date: Sat, 3 Jan 2026 14:26:29 -0500 Subject: [PATCH 02/25] Textures: prevent assert/crash of having a destroyed texture recreated without the pixels data available (#9150, #8811) Amend 8c22b8aef --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index c69eb190..62fac515 100644 --- a/imgui.h +++ b/imgui.h @@ -3509,7 +3509,7 @@ struct ImTextureData // - Call SetTexID() and SetStatus() after honoring texture requests. Never modify TexID and Status directly! // - A backend may decide to destroy a texture that we did not request to destroy, which is fine (e.g. freeing resources), but we immediately set the texture back in _WantCreate mode. void SetTexID(ImTextureID tex_id) { TexID = tex_id; } - void SetStatus(ImTextureStatus status) { Status = status; if (status == ImTextureStatus_Destroyed && !WantDestroyNextFrame) Status = ImTextureStatus_WantCreate; } + void SetStatus(ImTextureStatus status) { Status = status; if (status == ImTextureStatus_Destroyed && !WantDestroyNextFrame && Pixels != nullptr) Status = ImTextureStatus_WantCreate; } }; //----------------------------------------------------------------------------- From f106ccd5fa11eeb751ba91cb301d0bcaec3361ef Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 5 Jan 2026 15:58:08 +0100 Subject: [PATCH 03/25] Backends: Vulkan: clarify ImGui_ImplVulkanH_Window members. --- backends/imgui_impl_vulkan.h | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index fde5bed2..550834ab 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -223,21 +223,24 @@ struct ImGui_ImplVulkanH_FrameSemaphores // (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.) struct ImGui_ImplVulkanH_Window { - int Width; - int Height; - VkSwapchainKHR Swapchain; - VkSurfaceKHR Surface; - VkSurfaceFormatKHR SurfaceFormat; - VkPresentModeKHR PresentMode; - VkRenderPass RenderPass; - VkPipeline Pipeline; // The window pipeline may uses a different VkRenderPass than the one passed in ImGui_ImplVulkan_InitInfo - bool UseDynamicRendering; - bool ClearEnable; - VkClearValue ClearValue; - uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount) - uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count) - uint32_t SemaphoreCount; // Number of simultaneous in-flight frames + 1, to be able to use it in vkAcquireNextImageKHR - uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data) + // Input + VkSurfaceFormatKHR SurfaceFormat; + VkPresentModeKHR PresentMode; + bool UseDynamicRendering; + bool ClearEnable; + VkClearValue ClearValue; + + // Internal + int Width; // Generally same as passed to ImGui_ImplVulkanH_CreateOrResizeWindow() + int Height; + VkSwapchainKHR Swapchain; + VkSurfaceKHR Surface; + VkRenderPass RenderPass; + VkPipeline Pipeline; // The window pipeline may uses a different VkRenderPass than the one passed in ImGui_ImplVulkan_InitInfo + uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount) + uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count) + uint32_t SemaphoreCount; // Number of simultaneous in-flight frames + 1, to be able to use it in vkAcquireNextImageKHR + uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data) ImVector Frames; ImVector FrameSemaphores; From 1dc1964d5b24652a64eef270985cb77f4730c4cb Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 5 Jan 2026 16:26:59 +0100 Subject: [PATCH 04/25] Backends: Vulkan: change ImGui_ImplVulkanH_Window::ClearEnable to fuller featured AttachmentDesc. (#9152) --- backends/imgui_impl_vulkan.cpp | 13 ++++--------- backends/imgui_impl_vulkan.h | 21 ++++++++++++++++----- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 242fa53b..2386f0bd 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -27,6 +27,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-01-05: Vulkan: Helper for creating render pass uses ImGui_ImplVulkanH_Window::AttachmentDesc to create render pass. Removed ClearEnabled. (#9152) // 2025-11-24: Vulkan: Helper for creating a swap-chain (used by examples and multi-viewports) selects VkSwapchainCreateInfoKHR's compositeAlpha based on cap.supportedCompositeAlpha. (#8784) // 2025-10-15: Vulkan: Added IMGUI_IMPL_VULKAN_VOLK_FILENAME to configure path to volk.h header. (#9008) // 2025-09-26: *BREAKING CHANGE*: moved some fields in ImGui_ImplVulkan_InitInfo: init_info.RenderPass --> init_info.PipelineInfoMain.RenderPass, init_info.Subpass --> init_info.PipelineInfoMain.Subpass, init_info.MSAASamples --> init_info.PipelineInfoMain.MSAASamples, init_info.PipelineRenderingCreateInfo --> init_info.PipelineInfoMain.PipelineRenderingCreateInfo. @@ -1685,15 +1686,9 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V // Create the Render Pass if (wd->UseDynamicRendering == false) { - VkAttachmentDescription attachment = {}; - attachment.format = wd->SurfaceFormat.format; - attachment.samples = VK_SAMPLE_COUNT_1_BIT; - attachment.loadOp = wd->ClearEnable ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + VkAttachmentDescription attachment = wd->AttachmentDesc; + if (attachment.format == VK_FORMAT_UNDEFINED) + attachment.format = wd->SurfaceFormat.format; VkAttachmentReference color_attachment = {}; color_attachment.attachment = 0; color_attachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 550834ab..c6cd72cf 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -224,11 +224,11 @@ struct ImGui_ImplVulkanH_FrameSemaphores struct ImGui_ImplVulkanH_Window { // Input + bool UseDynamicRendering; VkSurfaceFormatKHR SurfaceFormat; VkPresentModeKHR PresentMode; - bool UseDynamicRendering; - bool ClearEnable; - VkClearValue ClearValue; + VkAttachmentDescription AttachmentDesc; // RenderPass creation: main attachment description. + VkClearValue ClearValue; // RenderPass creation: clear value when using VK_ATTACHMENT_LOAD_OP_CLEAR. // Internal int Width; // Generally same as passed to ImGui_ImplVulkanH_CreateOrResizeWindow() @@ -247,8 +247,19 @@ struct ImGui_ImplVulkanH_Window ImGui_ImplVulkanH_Window() { memset((void*)this, 0, sizeof(*this)); - PresentMode = (VkPresentModeKHR)~0; // Ensure we get an error if user doesn't set this. - ClearEnable = true; + + // Parameters to create SwapChain + PresentMode = (VkPresentModeKHR)~0; // Ensure we get an error if user doesn't set this. + + // Parameters to create RenderPass + AttachmentDesc.format = VK_FORMAT_UNDEFINED; // Will automatically use wd->SurfaceFormat.format. + AttachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT; + AttachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + AttachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + AttachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + AttachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + AttachmentDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + AttachmentDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; } }; From 69a501df6e6887a074b3c17a1c1bdd40a4c06dee Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 5 Jan 2026 16:46:56 +0100 Subject: [PATCH 05/25] Backends: OpenGL3: call ImGui_ImplOpenGL3_InitLoader() in ImGui_ImplOpenGL3_CreateDeviceObjects() / ImGui_ImplOpenGL3_DestroyDeviceObjects(). (#9112) --- backends/imgui_impl_opengl3.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 3ead5fec..133b0ed2 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -291,7 +291,8 @@ struct ImGui_ImplOpenGL3_VtxAttribState bool ImGui_ImplOpenGL3_InitLoader(); bool ImGui_ImplOpenGL3_InitLoader() { - // Initialize our loader + // Lazily initialize our loader if not already done + // (to facilitate handling multiple DLL boundaries and multiple context shutdowns we call this from all main entry points) #ifdef IMGUI_IMPL_OPENGL_LOADER_IMGL3W if (glGetIntegerv == nullptr && imgl3wInit() != 0) { @@ -302,6 +303,13 @@ bool ImGui_ImplOpenGL3_InitLoader() return true; } +static void ImGui_ImplOpenGL3_ShutdownLoader() +{ +#ifdef IMGUI_IMPL_OPENGL_LOADER_IMGL3W + imgl3wShutdown(); +#endif +} + // Functions bool ImGui_ImplOpenGL3_Init(const char* glsl_version) { @@ -433,9 +441,7 @@ void ImGui_ImplOpenGL3_Shutdown() platform_io.ClearRendererHandlers(); IM_DELETE(bd); -#ifdef IMGUI_IMPL_OPENGL_LOADER_IMGL3W - imgl3wShutdown(); -#endif + ImGui_ImplOpenGL3_ShutdownLoader(); } void ImGui_ImplOpenGL3_NewFrame() @@ -443,8 +449,7 @@ void ImGui_ImplOpenGL3_NewFrame() ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplOpenGL3_Init()?"); - ImGui_ImplOpenGL3_InitLoader(); // Lazily init loader if not already done for e.g. DLL boundaries. - + ImGui_ImplOpenGL3_InitLoader(); if (!bd->ShaderHandle) if (!ImGui_ImplOpenGL3_CreateDeviceObjects()) IM_ASSERT(0 && "ImGui_ImplOpenGL3_CreateDeviceObjects() failed!"); @@ -535,7 +540,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) if (fb_width <= 0 || fb_height <= 0) return; - ImGui_ImplOpenGL3_InitLoader(); // Lazily init loader if not already done for e.g. DLL boundaries. + ImGui_ImplOpenGL3_InitLoader(); ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); @@ -838,6 +843,7 @@ static bool CheckProgram(GLuint handle, const char* desc) bool ImGui_ImplOpenGL3_CreateDeviceObjects() { + ImGui_ImplOpenGL3_InitLoader(); ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); // Backup GL state @@ -1036,6 +1042,7 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects() void ImGui_ImplOpenGL3_DestroyDeviceObjects() { + ImGui_ImplOpenGL3_InitLoader(); ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; } if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; } From b467a0466c56936ba86a3369eb5603221fc95bc5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 6 Jan 2026 19:07:46 +0100 Subject: [PATCH 06/25] Docs: amends comments about fonts. --- docs/FONTS.md | 14 ++++++++++---- imconfig.h | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/FONTS.md b/docs/FONTS.md index ab1deb98..a3eb57d9 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -3,10 +3,16 @@ _(You may browse this at https://github.com/ocornut/imgui/blob/master/docs/FONTS ## Dear ImGui: Using Fonts The code in Dear ImGui embeds a copy of [ProggyClean.ttf](https://github.com/bluescan/proggyfonts) by Tristan Grimmer, -a 13 pixels high, pixel-perfect font used by default. We embed it in the source code so you can use Dear ImGui without any file system access. ProggyClean does not scale smoothly, therefore it is recommended that you load your own file when using Dear ImGui in an application aiming to look nice and wanting to support multiple resolutions. -The code in Dear ImGui embeds a partial copy of [ProggyVector.ttf](https://github.com/bluescan/proggyfonts) by Tristan Grimmer. +a 13 pixels high, pixel-perfect font used by default. ProggyClean does not scale very nicely. -You may also load external .TTF/.OTF files. +The code in Dear ImGui embeds a partial copy of [ProggyVector.ttf](https://github.com/bluescan/proggyfonts) by Tristan Grimmer and Source Foundry Authors, +a font mimicking ProggyClean which does scale nicely. + +We embed fonts in the code so you can use Dear ImGui without any file system access. +If you use either of those fonts in your shipping product you should include their license as part of your software (see below for links). +If you don't use them you can set `IMGUI_DISABLE_DEFAULT_FONT` in your [imconfig.h](https://github.com/ocornut/imgui/blob/master/imconfig.h) file to ship binaries without the fonts and save about ~26 KB. + +You may also load external .TTF/.OTF files, see instructions on this page. In the [misc/fonts/](https://github.com/ocornut/imgui/tree/master/misc/fonts) folder you can find a few suggested fonts, provided as a convenience. **Also read the FAQ:** https://www.dearimgui.com/faq (there is a Fonts section!) @@ -581,7 +587,7 @@ Some fonts files are available in the `misc/fonts/` folder:
https://github.com/bluescan/proggyfonts **ProggyVector.ttf**, by Tristan Grimmer, Source Foundry Authors -
MIT License +
MIT License + Bitstream Vera License
https://github.com/bluescan/proggyfonts **Karla-Regular.ttf**, by Jonathan Pinhorn diff --git a/imconfig.h b/imconfig.h index c6d9b8d5..322e5b89 100644 --- a/imconfig.h +++ b/imconfig.h @@ -49,7 +49,7 @@ //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). -//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded font (ProggyClean.ttf), remove ~9.5 KB from output binary. AddFontDefault() will assert. +//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded fonts (ProggyClean/ProggyVector), remove ~9 KB + ~17 KB from output binary. AddFontDefaultXXX() functions will assert. //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available //---- Enable Test Engine / Automation features. From 4ce188def8af61acce1aef5c2bca0481888326b8 Mon Sep 17 00:00:00 2001 From: JD31 Date: Wed, 7 Jan 2026 16:37:59 +0100 Subject: [PATCH 07/25] Backends: WebGPU: clarify build failure when attempting to build with Dawn for iOS. (#9155, #9156) --- backends/imgui_impl_wgpu.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 47c31726..c8722cd4 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -1020,15 +1020,18 @@ void ImGui_ImplWGPU_DebugPrintAdapterInfo(const WGPUAdapter& adapter) #if defined(__APPLE__) // MacOS specific: is necessary to compile with "-x objective-c++" flags // (e.g. using cmake: set_source_files_properties(${IMGUI_DIR}/backends/imgui_impl_wgpu.cpp PROPERTIES COMPILE_FLAGS "-x objective-c++") ) +#include +#if TARGET_OS_OSX #include #include #endif +#endif WGPUSurface ImGui_ImplWGPU_CreateWGPUSurfaceHelper(ImGui_ImplWGPU_CreateSurfaceInfo* info) { WGPUSurfaceDescriptor surface_descriptor = {}; WGPUSurface surface = {}; -#if defined(__APPLE__) +#if defined(__APPLE__) && TARGET_OS_OSX if (strcmp(info->System, "cocoa") == 0) { IM_ASSERT(info->RawWindow != nullptr); @@ -1075,7 +1078,7 @@ WGPUSurface ImGui_ImplWGPU_CreateWGPUSurfaceHelper(ImGui_ImplWGPU_CreateSurfaceI surface = wgpuInstanceCreateSurface(info->Instance, &surface_descriptor); } #else -#error "Unsupported WebGPU native platform!" + fprintf(stderr, "'CreateWGPUSurfaceHelper' is not implemented for this platform\n"); #endif return surface; } From 7b3ad4a282dc6f5007c49d35853e32f364e3e3d7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 7 Jan 2026 18:15:15 +0100 Subject: [PATCH 08/25] (Breaking) Popups: changed 'ImGuiPopupFlags popup_flags = 1' default value to be '= 0' for BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid(), OpenPopupOnItemClick(). (#9157, #9146) --- docs/CHANGELOG.txt | 27 +++++++++++++++++++++++++++ imgui.cpp | 39 +++++++++++++++++++++++++++++++++++---- imgui.h | 39 +++++++++++++++++++-------------------- imgui_internal.h | 1 + 4 files changed, 82 insertions(+), 24 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 154a8d44..2cb0d5d9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -70,6 +70,33 @@ Breaking Changes: the issue altogether. - Removed ImFontConfig::PixelSnapV added in 1.92 which turns out is unnecessary (and misdocumented). Post-rescale GlyphOffset is always rounded. + - Popups: changed compile-time 'ImGuiPopupFlags popup_flags = 1' default value to be '= 0' for + BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid(), OpenPopupOnItemClick(). + The default value has same meaning before and after. (#9157, #9146) + - Before this version, those functions had a 'ImGuiPopupFlags popup_flags = 1' default + value in their function signature. This was introduced by a change on 2020/06/23 (1.77) + while changing the signature from 'int mouse_button' to 'ImGuiPopupFlags popup_flags' + and trying to preserve then-legacy behavior. + - We have now changed this behavior to: cleanup a very old API quirk, facilitate use by + bindings, and to remove the last and error-prone non-zero default value. Also because we + deemed it extremely rare to use those helper functions with the Left mouse button! + As using the LMB would generally be triggered via another widget, e.g. a Button() + + a OpenPopup()/BeginPopup() call. + - Before: The default = 1 means ImGuiPopupFlags_MouseButtonRight. + Explicitly passing a literal 0 means ImGuiPopupFlags_MouseButtonLeft. + - After: The default = 0 means ImGuiPopupFlags_MouseButtonRight. + Explicitly passing a literal 1 also means ImGuiPopupFlags_MouseButtonRight + (if legacy behavior are enabled) or will assert (if legacy behavior are disabled). + - TL;DR: if you don't want to use right mouse button for popups, always specify it + explicitly using a named ImGuiPopupFlags_MouseButtonXXXX value. + Recap: + - BeginPopupContextItem("foo"); // Behavior unchanged (use Right button) + - BeginPopupContextItem("foo", ImGuiPopupFlags_MouseButtonLeft); // Behavior unchanged (use Left button) + - BeginPopupContextItem("foo", ImGuiPopupFlags_MouseButtonLeft | xxx); // Behavior unchanged (use Left button + flags) + - BeginPopupContextItem("foo", ImGuiPopupFlags_MouseButtonRight | xxx); // Behavior unchanged (use Right button + flags) + - BeginPopupContextItem("foo", 1); // Behavior unchanged (as a courtesy we legacy interpret 1 as ImGuiPopupFlags_MouseButtonRight, will assert if disabling legacy behaviors. + - BeginPopupContextItem("foo", 0); // !! Behavior changed !! Was Left button. Now will defaults to Right button! --> Use ImGuiPopupFlags_MouseButtonLeft. + - BeginPopupContextItem("foo", ImGuiPopupFlags_NoReopen); // !! Behavior changed !! Was Left button + flags. Now will defaults to Right button! --> Use ImGuiPopupFlags_MouseButtonLeft | xxx. Other Changes: diff --git a/imgui.cpp b/imgui.cpp index 6ba9d0b4..da9a7019 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -394,6 +394,24 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2026/01/07 (1.92.6) - Popups: changed compile-time 'ImGuiPopupFlags popup_flags = 1' default value to be '= 0' for BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid(), OpenPopupOnItemClick(). Default value has same meaning before and after. + - Refer to GitHub topic #9157 if you have any question. + - Before this version, those functions had a 'ImGuiPopupFlags popup_flags = 1' default value in their function signature. + Explicitly passing a literal 0 meant ImGuiPopupFlags_MouseButtonLeft. The default literal 1 meant ImGuiPopupFlags_MouseButtonRight. + This was introduced by a change on 2020/06/23 (1.77) while changing the signature from 'int mouse_button' to 'ImGuiPopupFlags popup_flags' and trying to preserve then-legacy behavior. + We have now changed this behavior to cleanup a very old API quirk, facilitate use by bindings, and to remove the last and error-prone non-zero default value. + Also because we deemed it extremely rare to use those helper functions with the Left mouse button! As using the LMB would generally be triggered via another widget, e.g. a Button() + a OpenPopup()/BeginPopup() call. + - Before: The default = 1 means ImGuiPopupFlags_MouseButtonRight. Explicitly passing a literal 0 means ImGuiPopupFlags_MouseButtonLeft. + - After: The default = 0 means ImGuiPopupFlags_MouseButtonRight. Explicitly passing a literal 1 also means ImGuiPopupFlags_MouseButtonRight (if legacy behavior are enabled) or will assert (if legacy behavior are disabled). + - TL;DR: if you don't want to use right mouse button for popups, always specify it explicitly using a named ImGuiPopupFlags_MouseButtonXXXX value. + Recap: + - BeginPopupContextItem("foo"); // Behavior unchanged (use Right button) + - BeginPopupContextItem("foo", ImGuiPopupFlags_MouseButtonLeft); // Behavior unchanged (use Left button) + - BeginPopupContextItem("foo", ImGuiPopupFlags_MouseButtonLeft | xxx); // Behavior unchanged (use Left button + flags) + - BeginPopupContextItem("foo", ImGuiPopupFlags_MouseButtonRight | xxx); // Behavior unchanged (use Right button + flags) + - BeginPopupContextItem("foo", 1); // Behavior unchanged (as a courtesy we legacy interpret 1 as ImGuiPopupFlags_MouseButtonRight, will assert if disabling legacy behaviors. + - BeginPopupContextItem("foo", 0); // !! Behavior changed !! Was Left button. Now will defaults to Right button! --> Use ImGuiPopupFlags_MouseButtonLeft. + - BeginPopupContextItem("foo", ImGuiPopupFlags_NoReopen); // !! Behavior changed !! Was Left button + flags. Now will defaults to Right button! --> Use ImGuiPopupFlags_MouseButtonLeft | xxx. - 2025/12/23 (1.92.6) - Fonts:AddFontDefault() now automatically selects an embedded font between the new scalable AddFontDefaultVector() and the classic pixel-clean AddFontDefaultBitmap(). The default selection is based on (style.FontSizeBase * FontScaleMain * FontScaleDpi) reaching a small threshold. Prefer calling either based on your own logic. You can call AddFontDefaultBitmap() to ensure legacy behavior. - 2025/12/23 (1.92.6) - Fonts: removed ImFontConfig::PixelSnapV added in 1.92 which turns out is unnecessary (and misdocumented). Post-rescale GlyphOffset is always rounded. @@ -12454,13 +12472,26 @@ void ImGui::EndPopup() g.WithinEndChildID = backup_within_end_child_id; } +ImGuiMouseButton ImGui::GetMouseButtonFromPopupFlags(ImGuiPopupFlags flags) +{ +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if ((flags & ImGuiPopupFlags_InvalidMask_) != 0) // 1,2 --> ImGuiMouseButton_Right, ImGuiMouseButton_Middle + return (flags & ImGuiPopupFlags_InvalidMask_); +#else + IM_ASSERT((flags & ImGuiPopupFlags_InvalidMask_) == 0); +#endif + if (flags & ImGuiPopupFlags_MouseButtonMask_) + return ((flags & ImGuiPopupFlags_MouseButtonMask_) >> ImGuiPopupFlags_MouseButtonShift_) - 1; + return ImGuiMouseButton_Right; // Default == 1 +} + // Helper to open a popup if mouse button is released over the item // - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup() void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + ImGuiMouseButton mouse_button = GetMouseButtonFromPopupFlags(popup_flags); if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) { ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! @@ -12493,7 +12524,7 @@ bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flag return false; ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) - int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + ImGuiMouseButton mouse_button = GetMouseButtonFromPopupFlags(popup_flags); if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) OpenPopupEx(id, popup_flags); return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); @@ -12506,7 +12537,7 @@ bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_fl if (!str_id) str_id = "window_context"; ImGuiID id = window->GetID(str_id); - int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + ImGuiMouseButton mouse_button = GetMouseButtonFromPopupFlags(popup_flags); if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) if (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered()) OpenPopupEx(id, popup_flags); @@ -12520,7 +12551,7 @@ bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flag if (!str_id) str_id = "void_context"; ImGuiID id = window->GetID(str_id); - int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + ImGuiMouseButton mouse_button = GetMouseButtonFromPopupFlags(popup_flags); if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) if (GetTopMostPopupModal() == NULL) OpenPopupEx(id, popup_flags); diff --git a/imgui.h b/imgui.h index 62fac515..2df75541 100644 --- a/imgui.h +++ b/imgui.h @@ -30,7 +30,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.6 WIP" -#define IMGUI_VERSION_NUM 19258 +#define IMGUI_VERSION_NUM 19259 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 @@ -853,20 +853,23 @@ namespace ImGui // - CloseCurrentPopup() is called by default by Selectable()/MenuItem() when activated (FIXME: need some options). // - Use ImGuiPopupFlags_NoOpenOverExistingPopup to avoid opening a popup if there's already one at the same level. This is equivalent to e.g. testing for !IsAnyPopupOpen() prior to OpenPopup(). // - Use IsWindowAppearing() after BeginPopup() to tell if a window just opened. - // - IMPORTANT: Notice that for OpenPopupOnItemClick() we exceptionally default flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter IMGUI_API void OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags = 0); // call to mark popup as open (don't call every frame!). IMGUI_API void OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags = 0); // id overload to facilitate calling from nested stacks - IMGUI_API void OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // helper to open popup when clicked on last item. Default to ImGuiPopupFlags_MouseButtonRight == 1. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors) + IMGUI_API void OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 0); // helper to open popup when clicked on last item. Default to ImGuiPopupFlags_MouseButtonRight == 1. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors) IMGUI_API void CloseCurrentPopup(); // manually close the popup we have begin-ed into. - // Popups: open+begin combined functions helpers + // Popups: Open+Begin popup combined functions helpers to create context menus. // - Helpers to do OpenPopup+BeginPopup where the Open action is triggered by e.g. hovering an item and right-clicking. - // - They are convenient to easily create context menus, hence the name. // - IMPORTANT: Notice that BeginPopupContextXXX takes ImGuiPopupFlags just like OpenPopup() and unlike BeginPopup(). For full consistency, we may add ImGuiWindowFlags to the BeginPopupContextXXX functions in the future. - // - IMPORTANT: Notice that we exceptionally default their flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter, so if you add other flags remember to re-add the ImGuiPopupFlags_MouseButtonRight. - IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked on last item. Use str_id==NULL to associate the popup to previous item. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! - IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);// open+begin popup when clicked on current window. - IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked in void (where there are no windows). + // - IMPORTANT: If you ever used the left mouse button with BeginPopupContextXXX() helpers before 1.92.6: + // - Before this version, OpenPopupOnItemClick(), BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid() had 'a ImGuiPopupFlags popup_flags = 1' default value in their function signature. + // - Before: Explicitly passing a literal 0 meant ImGuiPopupFlags_MouseButtonLeft. The default = 1 meant ImGuiPopupFlags_MouseButtonRight. + // - After: The default = 0 means ImGuiPopupFlags_MouseButtonRight. Explicitly passing a literal 1 also means ImGuiPopupFlags_MouseButtonRight (if legacy behavior are enabled) or will assert (if legacy behavior are disabled). + // - TL;DR: if you don't want to use right mouse button for popups, always specify it explicitly using a named ImGuiPopupFlags_MouseButtonXXXX value. + // - Read "API BREAKING CHANGES" 2026/01/07 (1.92.6) entry in imgui.cpp or GitHub topic #9157 for all details. + IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 0); // open+begin popup when clicked on last item. Use str_id==NULL to associate the popup to previous item. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! + IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 0);// open+begin popup when clicked on current window. + IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 0); // open+begin popup when clicked in void (where there are no windows). // Popups: query functions // - IsPopupOpen(): return true if the popup is open at the current BeginPopup() level of the popup stack. @@ -1322,21 +1325,14 @@ enum ImGuiTreeNodeFlags_ }; // Flags for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() functions. -// - To be backward compatible with older API which took an 'int mouse_button = 1' argument instead of 'ImGuiPopupFlags flags', -// we need to treat small flags values as a mouse button index, so we encode the mouse button in the first few bits of the flags. -// It is therefore guaranteed to be legal to pass a mouse button index in ImGuiPopupFlags. -// - For the same reason, we exceptionally default the ImGuiPopupFlags argument of BeginPopupContextXXX functions to 1 instead of 0. -// IMPORTANT: because the default parameter is 1 (==ImGuiPopupFlags_MouseButtonRight), if you rely on the default parameter -// and want to use another flag, you need to pass in the ImGuiPopupFlags_MouseButtonRight flag explicitly. +// - IMPORTANT: If you ever used the left mouse button with BeginPopupContextXXX() helpers before 1.92.6: Read "API BREAKING CHANGES" 2026/01/07 (1.92.6) entry in imgui.cpp or GitHub topic #9157. // - Multiple buttons currently cannot be combined/or-ed in those functions (we could allow it later). enum ImGuiPopupFlags_ { ImGuiPopupFlags_None = 0, - ImGuiPopupFlags_MouseButtonLeft = 0, // For BeginPopupContext*(): open on Left Mouse release. Guaranteed to always be == 0 (same as ImGuiMouseButton_Left) - ImGuiPopupFlags_MouseButtonRight = 1, // For BeginPopupContext*(): open on Right Mouse release. Guaranteed to always be == 1 (same as ImGuiMouseButton_Right) - ImGuiPopupFlags_MouseButtonMiddle = 2, // For BeginPopupContext*(): open on Middle Mouse release. Guaranteed to always be == 2 (same as ImGuiMouseButton_Middle) - ImGuiPopupFlags_MouseButtonMask_ = 0x1F, - ImGuiPopupFlags_MouseButtonDefault_ = 1, + ImGuiPopupFlags_MouseButtonLeft = 1 << 2, // For BeginPopupContext*(): open on Left Mouse release. Only one button allowed! + ImGuiPopupFlags_MouseButtonRight = 2 << 2, // For BeginPopupContext*(): open on Right Mouse release. Only one button allowed! (default) + ImGuiPopupFlags_MouseButtonMiddle = 3 << 2, // For BeginPopupContext*(): open on Middle Mouse release. Only one button allowed! ImGuiPopupFlags_NoReopen = 1 << 5, // For OpenPopup*(), BeginPopupContext*(): don't reopen same popup if already open (won't reposition, won't reinitialize navigation) //ImGuiPopupFlags_NoReopenAlwaysNavInit = 1 << 6, // For OpenPopup*(), BeginPopupContext*(): focus and initialize navigation even when not reopening. ImGuiPopupFlags_NoOpenOverExistingPopup = 1 << 7, // For OpenPopup*(), BeginPopupContext*(): don't open if there's already a popup at the same level of the popup stack @@ -1344,6 +1340,9 @@ enum ImGuiPopupFlags_ ImGuiPopupFlags_AnyPopupId = 1 << 10, // For IsPopupOpen(): ignore the ImGuiID parameter and test for any popup. ImGuiPopupFlags_AnyPopupLevel = 1 << 11, // For IsPopupOpen(): search/test at any level of the popup stack (default test in the current level) ImGuiPopupFlags_AnyPopup = ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel, + ImGuiPopupFlags_MouseButtonShift_ = 2, // [Internal] + ImGuiPopupFlags_MouseButtonMask_ = 0x0C, // [Internal] + ImGuiPopupFlags_InvalidMask_ = 0x03, // [Internal] Reserve legacy bits 0-1 to detect incorrectly passing 1 or 2 to the function. }; // Flags for ImGui::Selectable() diff --git a/imgui_internal.h b/imgui_internal.h index 0a37c16e..86606f39 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3314,6 +3314,7 @@ namespace ImGui IMGUI_API ImGuiWindow* FindBlockingModal(ImGuiWindow* window); IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window); IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy); + IMGUI_API ImGuiMouseButton GetMouseButtonFromPopupFlags(ImGuiPopupFlags flags); // Tooltips IMGUI_API bool BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags); From 43a90adc618207da0e9ef6274f1b172c76f220ae Mon Sep 17 00:00:00 2001 From: maf Date: Thu, 8 Jan 2026 16:17:44 +0800 Subject: [PATCH 09/25] Docs: Fix spelling errors (#9158) --- imgui.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 2df75541..8d6b6371 100644 --- a/imgui.h +++ b/imgui.h @@ -1539,7 +1539,7 @@ enum ImGuiSortDirection : ImU8 // All our named keys are >= 512. Keys value 0 to 511 are left unused and were legacy native/opaque key values (< 1.87). // Support for legacy keys was completely removed in 1.91.5. // Read details about the 1.87+ transition : https://github.com/ocornut/imgui/issues/4921 -// Note that "Keys" related to physical keys and are not the same concept as input "Characters", the later are submitted via io.AddInputCharacter(). +// Note that "Keys" related to physical keys and are not the same concept as input "Characters", the latter are submitted via io.AddInputCharacter(). // The keyboard key enum values are named after the keys on a standard US keyboard, and on other keyboard types the keys reported may not match the keycaps. enum ImGuiKey : int { @@ -2438,7 +2438,7 @@ struct ImGuiIO // Options to configure Error Handling and how we handle recoverable errors [EXPERIMENTAL] // - Error recovery is provided as a way to facilitate: - // - Recovery after a programming error (native code or scripting language - the later tends to facilitate iterating on code while running). + // - Recovery after a programming error (native code or scripting language - the latter tends to facilitate iterating on code while running). // - Recovery after running an exception handler or any error processing which may skip code after an error has been detected. // - Error recovery is not perfect nor guaranteed! It is a feature to ease development. // You not are not supposed to rely on it in the course of a normal application run. From 9ce41a92c34ec0170247dfd09c0c48ae92e19109 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 8 Jan 2026 14:31:25 +0100 Subject: [PATCH 10/25] Misc/shallow merges from docking branch to reduce small drift. --- backends/imgui_impl_glfw.cpp | 6 +++--- backends/imgui_impl_glfw.h | 4 ++-- backends/imgui_impl_metal.mm | 2 +- backends/imgui_impl_osx.mm | 12 +++++++----- backends/imgui_impl_sdl2.cpp | 6 +++--- backends/imgui_impl_sdl3.cpp | 10 +++------- backends/imgui_impl_vulkan.cpp | 2 +- backends/imgui_impl_vulkan.h | 1 - backends/imgui_impl_win32.cpp | 6 +++--- examples/example_glfw_opengl2/Makefile | 3 ++- imgui_widgets.cpp | 2 +- 11 files changed, 26 insertions(+), 28 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 35b167b2..82c512fe 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -11,8 +11,8 @@ // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors) with GLFW 3.1+. Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Multiple Dear ImGui contexts support. // Missing features or Issues: -// [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. -// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. +// [ ] Platform: Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. +// [ ] Platform: Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -156,13 +156,13 @@ // We gather version tests as define in order to easily see which features are version-dependent. #define GLFW_VERSION_COMBINED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION) +#define GLFW_HAS_CREATECURSOR (GLFW_VERSION_COMBINED >= 3100) // 3.1+ glfwCreateCursor() #define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetMonitorContentScale #ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released? #define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR #else #define GLFW_HAS_NEW_CURSORS (0) #endif -#define GLFW_HAS_CREATECURSOR (GLFW_VERSION_COMBINED >= 3100) // 3.1+ glfwCreateCursor() #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() diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index 98fae51c..c01600d0 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -11,8 +11,8 @@ // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors) with GLFW 3.1+. Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Multiple Dear ImGui contexts support. // Missing features or Issues: -// [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. -// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. +// [ ] Platform: Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. +// [ ] Platform: Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 2746efa9..96695d9b 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -19,7 +19,7 @@ // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplMetal_CreateFontsTexture() and ImGui_ImplMetal_DestroyFontsTexture(). // 2025-02-03: Metal: Crash fix. (#8367) -// 2024-01-08: Metal: Fixed memory leaks when using metal-cpp (#8276, #8166) or when using multiple contexts (#7419). +// 2025-01-08: Metal: Fixed memory leaks when using metal-cpp (#8276, #8166) or when using multiple contexts (#7419). // 2022-08-23: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'. // 2022-07-05: Metal: Add dispatch synchronization. // 2022-06-30: Metal: Use __bridge for ARC based systems. diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 189dd53e..0dfdd8e9 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -148,9 +148,11 @@ static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view); NSWindow* window = view.window; if (!window) return; - NSRect contentRect = [window contentRectForFrameRect:window.frame]; - NSRect rect = NSMakeRect(_posX, contentRect.size.height - _posY, 0, 0); - _imeRect = [window convertRectToScreen:rect]; + { + NSRect contentRect = [window contentRectForFrameRect:window.frame]; + NSRect rect = NSMakeRect(_posX, contentRect.size.height - _posY, 0, 0); + _imeRect = [window convertRectToScreen:rect]; + } } - (void)viewDidMoveToWindow @@ -629,9 +631,9 @@ void ImGui_ImplOSX_NewFrame(NSView* view) // Setup display size if (view) { - const float dpi = (float)[view.window backingScaleFactor]; + const float fb_scale = (float)[view.window backingScaleFactor]; io.DisplaySize = ImVec2((float)view.bounds.size.width, (float)view.bounds.size.height); - io.DisplayFramebufferScale = ImVec2(dpi, dpi); + io.DisplayFramebufferScale = ImVec2(fb_scale, fb_scale); } // Setup time step diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index c2dae405..371b1dac 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -140,7 +140,7 @@ struct ImGui_ImplSDL2_Data { SDL_Window* Window; - Uint32 WindowID; + Uint32 WindowID; // Stored in ImGuiViewport::PlatformHandle. Use SDL_GetWindowFromID() to get SDL_Window* from Uint32 WindowID. SDL_Renderer* Renderer; Uint64 Time; char* ClipboardTextData; @@ -368,7 +368,6 @@ static ImGuiViewport* ImGui_ImplSDL2_GetViewportForWindowID(Uint32 window_id) // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. -// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field. bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) { ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); @@ -462,7 +461,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) bd->MouseLastLeaveFrame = ImGui::GetFrameCount() + 1; if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED) io.AddFocusEvent(true); - else if (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST) + if (window_event == SDL_WINDOWEVENT_FOCUS_LOST) io.AddFocusEvent(false); return true; } @@ -487,6 +486,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void ImGuiIO& io = ImGui::GetIO(); IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); + //SDL_SetHint(SDL_HINT_EVENT_LOGGING, "2"); // Obtain compiled and runtime versions SDL_version ver_compiled; diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 81592959..ffd9f8a5 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -372,7 +372,6 @@ static void ImGui_ImplSDL3_UpdateKeyModifiers(SDL_Keymod sdl_key_mods) // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. -// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field. bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) { ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); @@ -495,6 +494,7 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); IM_UNUSED(sdl_gl_context); // Unused in this branch + //SDL_SetHint(SDL_HINT_EVENT_LOGGING, "2"); const int ver_linked = SDL_GetVersion(); @@ -555,22 +555,18 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void // Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered. // (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application. // It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click: - // you can ignore SDL_EVENT_MOUSE_BUTTON_DOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED) -#ifdef SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH + // you can ignore SDL_EVENT_MOUSE_BUTTON_DOWN events coming right after a SDL_EVENT_WINDOW_FOCUS_GAINED) SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); -#endif // From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710) -#ifdef SDL_HINT_MOUSE_AUTO_CAPTURE SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0"); -#endif return true; } +// Should technically be a SDL_GLContext but due to typedef it is sane to keep it void* in public interface. bool ImGui_ImplSDL3_InitForOpenGL(SDL_Window* window, void* sdl_gl_context) { - IM_UNUSED(sdl_gl_context); // Viewport branch will need this. return ImGui_ImplSDL3_Init(window, nullptr, sdl_gl_context); } diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 2386f0bd..f0ca7907 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -261,7 +261,7 @@ struct ImGui_ImplVulkan_Data VkPipelineCreateFlags PipelineCreateFlags; VkDescriptorSetLayout DescriptorSetLayout; VkPipelineLayout PipelineLayout; - VkPipeline Pipeline; + VkPipeline Pipeline; // pipeline for main render pass (created by app) VkShaderModule ShaderModuleVert; VkShaderModule ShaderModuleFrag; VkDescriptorPool DescriptorPool; diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index c6cd72cf..83376e59 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -77,7 +77,6 @@ // Specify settings to create pipeline and swapchain struct ImGui_ImplVulkan_PipelineInfo { - // For Main and Secondary viewports VkRenderPass RenderPass; // Ignored if using dynamic rendering uint32_t Subpass; // VkSampleCountFlagBits MSAASamples = {}; // 0 defaults to VK_SAMPLE_COUNT_1_BIT diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index c3b7ca9c..de3c6fbd 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -181,7 +181,7 @@ static bool ImGui_ImplWin32_InitEx(void* hwnd, bool platform_has_own_dc) bd->LastMouseCursor = ImGuiMouseCursor_COUNT; ImGui_ImplWin32_UpdateKeyboardCodePage(io); - // Set platform dependent data in viewport + // Our mouse update function expect PlatformHandle to be filled for the main viewport ImGuiViewport* main_viewport = ImGui::GetMainViewport(); main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (void*)bd->hWnd; IM_UNUSED(platform_has_own_dc); // Used in 'docking' branch @@ -650,8 +650,8 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPA bd->MouseTrackedArea = area; } POINT mouse_pos = { (LONG)GET_X_LPARAM(lParam), (LONG)GET_Y_LPARAM(lParam) }; - if (msg == WM_NCMOUSEMOVE && ::ScreenToClient(hwnd, &mouse_pos) == FALSE) // WM_NCMOUSEMOVE are provided in absolute coordinates. - return 0; + if (msg == WM_NCMOUSEMOVE) // WM_NCMOUSEMOVE are absolute coordinates. + ::ScreenToClient(hwnd, &mouse_pos); io.AddMouseSourceEvent(mouse_source); io.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y); return 0; diff --git a/examples/example_glfw_opengl2/Makefile b/examples/example_glfw_opengl2/Makefile index 1f15c15c..a8a0128d 100644 --- a/examples/example_glfw_opengl2/Makefile +++ b/examples/example_glfw_opengl2/Makefile @@ -21,6 +21,7 @@ SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl2.cpp OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) UNAME_S := $(shell uname -s) +LINUX_GL_LIBS = -lGL CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends CXXFLAGS += -g -Wall -Wformat @@ -32,7 +33,7 @@ LIBS = ifeq ($(UNAME_S), Linux) #LINUX ECHO_MESSAGE = "Linux" - LIBS += -lGL `pkg-config --static --libs glfw3` + LIBS += $(LINUX_GL_LIBS) `pkg-config --static --libs glfw3` CXXFLAGS += `pkg-config --cflags glfw3` CFLAGS = $(CXXFLAGS) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index fac10d83..83e931a0 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1720,7 +1720,7 @@ void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end const float separator_thickness = style.SeparatorTextBorderSize; const ImVec2 min_size(label_size.x + extra_w + padding.x * 2.0f, ImMax(label_size.y + padding.y * 2.0f, separator_thickness)); const ImRect bb(pos, ImVec2(window->WorkRect.Max.x, pos.y + min_size.y)); - const float text_baseline_y = ImTrunc((bb.GetHeight() - label_size.y) * style.SeparatorTextAlign.y + 0.99999f); //ImMax(padding.y, ImFloor((style.SeparatorTextSize - label_size.y) * 0.5f)); + const float text_baseline_y = ImTrunc((bb.GetHeight() - label_size.y) * style.SeparatorTextAlign.y + 0.99999f); //ImMax(padding.y, ImTrunc((style.SeparatorTextSize - label_size.y) * 0.5f)); ItemSize(min_size, text_baseline_y); if (!ItemAdd(bb, id)) return; From 3389dfd9dd9edf4d6f5884d9d1848446dce87689 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 8 Jan 2026 15:58:12 +0100 Subject: [PATCH 11/25] IsItemHovered() doesn't filter out the signal when activated item is a shortcut remote activation. (#9138, #456) Amend a201af7354 --- docs/CHANGELOG.txt | 4 +++- imgui.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2cb0d5d9..521ec6b5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -98,7 +98,6 @@ Breaking Changes: - BeginPopupContextItem("foo", 0); // !! Behavior changed !! Was Left button. Now will defaults to Right button! --> Use ImGuiPopupFlags_MouseButtonLeft. - BeginPopupContextItem("foo", ImGuiPopupFlags_NoReopen); // !! Behavior changed !! Was Left button + flags. Now will defaults to Right button! --> Use ImGuiPopupFlags_MouseButtonLeft | xxx. - Other Changes: - Fonts: @@ -155,6 +154,9 @@ Other Changes: noticeable by user but detected by sanitizers). (#9089) [@judicaelclair] - Added GetItemFlags() in public API for consistency and to expose generic flags of last submitted item. (#9127) +- IsItemHovered() without ImGuiHoveredFlags_AllowWhenBlockedByActiveItem + doesn't filter out the signal when activated item is a shortcut remote activation; + (which mimicks what's done internally in the ItemHoverable() function). (#9138) - Debug Tools: - Debug Log: fixed incorrectly printing characters in IO log when submitting non-ASCII values to io.AddInputCharacter(). (#9099) diff --git a/imgui.cpp b/imgui.cpp index da9a7019..996d162b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4824,7 +4824,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) // Test if another item is active (e.g. being dragged) const ImGuiID id = g.LastItemData.ID; if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0) - if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap) + if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap && !g.ActiveIdFromShortcut) { // When ActiveId == MoveId it means that either: // - (1) user clicked on void _or_ an item with no id, which triggers moving window (ActiveId is set even when window has _NoMove flag) @@ -13571,6 +13571,7 @@ static ImGuiInputSource ImGui::NavCalcPreferredRefPosSource() ImGuiContext& g = *GImGui; ImGuiWindow* window = g.NavWindow; const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID; + //const bool activated_shortcut = false // 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 ((!g.NavCursorVisible || !g.NavHighlightItemUnderNav || !window) && !activated_shortcut) @@ -13586,6 +13587,7 @@ static ImVec2 ImGui::NavCalcPreferredRefPos() ImGuiInputSource source = NavCalcPreferredRefPosSource(); const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID; + //const bool activated_shortcut = false if (source != ImGuiInputSource_Mouse && !activated_shortcut && window == NULL) source = ImGuiInputSource_Mouse; From 1566c96ccd5faa7fddf34329687ac16796bebabc Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 8 Jan 2026 17:04:52 +0100 Subject: [PATCH 12/25] InputText, Nav: fixed remote/shortcut InputText() not teleporting mouse cursor when nav cursor is active and io.ConfigNavMoveSetMousePos is enabled. Motivated by this, also made SetFocusID() immediately set g.NavIdIsAlive, which is more correct and might be other (positive) subtle side effects. --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 2 ++ imgui_widgets.cpp | 2 ++ 3 files changed, 7 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 521ec6b5..3a2bea6e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -150,6 +150,9 @@ Other Changes: end of a line rather than at the beginning of next line. (#8990, #3237) - Fixed low-level word-wrapping function reading from *text_end when passed a string range. (#9107) [@achabense] +- Nav: + - Fixed remote/shortcut InputText() not teleporting mouse cursor when + nav cursor is visible and `io.ConfigNavMoveSetMousePos` is enabled. - Scrollbar: fixed a codepath leading to a divide-by-zero (which would not be noticeable by user but detected by sanitizers). (#9089) [@judicaelclair] - Added GetItemFlags() in public API for consistency and to expose generic diff --git a/imgui.cpp b/imgui.cpp index 996d162b..4e59a1a6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -13055,6 +13055,8 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) window->NavLastIds[nav_layer] = id; if (g.LastItemData.ID == id) window->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect); + if (g.NavId == g.ActiveId && g.ActiveIdIsAlive) + g.NavIdIsAlive = true; if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) g.NavHighlightItemUnderNav = true; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 83e931a0..88d3b7ca 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4848,6 +4848,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ SetActiveID(id, window); SetFocusID(id, window); FocusWindow(window); + if (input_requested_by_nav) + SetNavCursorVisibleAfterMove(); } if (g.ActiveId == id) { From ca9b7b4071f89457c0e01919caade8b6c59d352d Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 8 Jan 2026 17:11:23 +0100 Subject: [PATCH 13/25] InputText, Nav: amend 1566c96. (incorrectly commited old chunk) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 4e59a1a6..d4bd9adb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -13055,7 +13055,7 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) window->NavLastIds[nav_layer] = id; if (g.LastItemData.ID == id) window->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect); - if (g.NavId == g.ActiveId && g.ActiveIdIsAlive) + if (id == g.ActiveIdIsAlive) g.NavIdIsAlive = true; if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) From 7a02f4b545e719a00ddb8b15d35bf6fbd78c301e Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 8 Jan 2026 17:14:38 +0100 Subject: [PATCH 14/25] Nav, Shortcuts, Tooltips: tooltip reference position not affected by remote shortcut activation. (#9138, #456) NavCalcPreferredRefPos() has different path for popups vs tooltip. Amend 197f8904fe --- imgui.cpp | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d4bd9adb..e4a63f9c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1347,8 +1347,8 @@ static bool NavScoreItem(ImGuiNavItemData* result, const ImRect& nav static void NavApplyItemToResult(ImGuiNavItemData* result); static void NavProcessItem(); static void NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags); -static ImGuiInputSource NavCalcPreferredRefPosSource(); -static ImVec2 NavCalcPreferredRefPos(); +static ImGuiInputSource NavCalcPreferredRefPosSource(ImGuiWindowFlags window_type); +static ImVec2 NavCalcPreferredRefPos(ImGuiWindowFlags window_type); static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); static void NavRestoreLayer(ImGuiNavLayer layer); @@ -12203,7 +12203,7 @@ void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags) popup_ref.RestoreNavWindow = g.NavWindow; // When popup closes focus may be restored to NavWindow (depend on window type). popup_ref.OpenFrameCount = g.FrameCount; popup_ref.OpenParentId = parent_window->IDStack.back(); - popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); + popup_ref.OpenPopupPos = NavCalcPreferredRefPos(ImGuiWindowFlags_Popup); popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos; IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopupEx(0x%08X)\n", id); @@ -12681,9 +12681,9 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) // as drag and drop tooltips are calling SetNextWindowPos() leading to 'window_pos_set_by_api' being set in Begin(). IM_ASSERT(g.CurrentWindow == window); const float scale = g.Style.MouseCursorScale; - const ImVec2 ref_pos = NavCalcPreferredRefPos(); + const ImVec2 ref_pos = NavCalcPreferredRefPos(ImGuiWindowFlags_Tooltip); - if (g.IO.MouseSource == ImGuiMouseSource_TouchScreen && NavCalcPreferredRefPosSource() == ImGuiInputSource_Mouse) + if (g.IO.MouseSource == ImGuiMouseSource_TouchScreen && NavCalcPreferredRefPosSource(ImGuiWindowFlags_Tooltip) == ImGuiInputSource_Mouse) { ImVec2 tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET_TOUCH * scale - (TOOLTIP_DEFAULT_PIVOT_TOUCH * window->Size); if (r_outer.Contains(ImRect(tooltip_pos, tooltip_pos + window->Size))) @@ -13568,33 +13568,29 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) } } -static ImGuiInputSource ImGui::NavCalcPreferredRefPosSource() +// Positioning logic altered slightly for remote activation: for Popup we want to use item rect, for Tooltip we leave things alone. (#9138) +// When calling for ImGuiWindowFlags_Popup we use LastItemData. +static ImGuiInputSource ImGui::NavCalcPreferredRefPosSource(ImGuiWindowFlags window_type) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.NavWindow; - const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID; - //const bool activated_shortcut = false - // 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 ((!g.NavCursorVisible || !g.NavHighlightItemUnderNav || !window) && !activated_shortcut) + const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID; + if ((window_type & ImGuiWindowFlags_Popup) && activated_shortcut) + return ImGuiInputSource_Keyboard; + + if (!g.NavCursorVisible || !g.NavHighlightItemUnderNav || !window) return ImGuiInputSource_Mouse; else return ImGuiInputSource_Keyboard; // or Nav in general } -static ImVec2 ImGui::NavCalcPreferredRefPos() +static ImVec2 ImGui::NavCalcPreferredRefPos(ImGuiWindowFlags window_type) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.NavWindow; - ImGuiInputSource source = NavCalcPreferredRefPosSource(); + ImGuiInputSource source = NavCalcPreferredRefPosSource(window_type); - const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID; - //const bool activated_shortcut = false - - 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) { // Mouse (we need a fallback in case the mouse becomes invalid after being used) @@ -13606,8 +13602,9 @@ static ImVec2 ImGui::NavCalcPreferredRefPos() else { // When navigation is active and mouse is disabled, pick a position around the bottom left of the currently navigated item + const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID; ImRect ref_rect; - if (activated_shortcut) + if (activated_shortcut && (window_type & ImGuiWindowFlags_Popup)) ref_rect = g.LastItemData.NavRect; else if (window != NULL) ref_rect = WindowRectRelToAbs(window, window->NavRectRel[g.NavLayer]); @@ -13806,7 +13803,7 @@ static void ImGui::NavUpdate() // Update mouse position if requested // (This will take into account the possibility that a Scroll was queued in the window to offset our absolute mouse position before scroll has been applied) if (set_mouse_pos && io.ConfigNavMoveSetMousePos && (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos)) - TeleportMousePos(NavCalcPreferredRefPos()); + TeleportMousePos(NavCalcPreferredRefPos(ImGuiWindowFlags_Popup)); // [DEBUG] g.NavScoringDebugCount = 0; From fedf227ea4f0bffbc75ff3d3de6631a4c57a4ba1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 8 Jan 2026 17:17:06 +0100 Subject: [PATCH 15/25] Amend 7a02f4b. --- docs/CHANGELOG.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3a2bea6e..c3ef808a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -157,9 +157,12 @@ Other Changes: noticeable by user but detected by sanitizers). (#9089) [@judicaelclair] - Added GetItemFlags() in public API for consistency and to expose generic flags of last submitted item. (#9127) -- IsItemHovered() without ImGuiHoveredFlags_AllowWhenBlockedByActiveItem - doesn't filter out the signal when activated item is a shortcut remote activation; - (which mimicks what's done internally in the ItemHoverable() function). (#9138) +- Shortcuts: + - IsItemHovered() without ImGuiHoveredFlags_AllowWhenBlockedByActiveItem + doesn't filter out the signal when activated item is a shortcut remote activation; + (which mimicks what's done internally in the ItemHoverable() function). (#9138) + - Fixed tooltip placement being affected for a frame when located over an item + activated by SetNextItemShortcut(). (#9138) - Debug Tools: - Debug Log: fixed incorrectly printing characters in IO log when submitting non-ASCII values to io.AddInputCharacter(). (#9099) From f5384544cb350dd2444c27c153ac563b91cf09da Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 8 Jan 2026 17:26:25 +0100 Subject: [PATCH 16/25] (Breaking) Commented out legacy names obsoleted in 1.90 (Sept 2023): BeginChildFrame(), EndChildFrame(), ShowStackToolWindow(), IM_OFFSETOF(), IM_FLOOR(). --- docs/CHANGELOG.txt | 6 ++++++ imgui.cpp | 7 +++---- imgui.h | 13 +++++++------ imgui_internal.h | 6 ++---- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c3ef808a..b7b4f2cd 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,12 @@ HOW TO UPDATE? Breaking Changes: +- Commented out legacy names obsoleted in 1.90 (Sept 2023): + - BeginChildFrame() --> BeginChild() with ImGuiChildFlags_FrameStyle flag. + - EndChildFrame() --> EndChild(). + - ShowStackToolWindow() --> ShowIDStackToolWindow(). + - IM_OFFSETOF() --> offsetof(). + - IM_FLOOR() --> IM_TRUNC() [internal, for positive values only] - Hashing: handling of "###" operator to reset to seed within a string identifier doesn't include the "###" characters in the output hash anymore: Before: GetID("Hello###World") == GetID("###World") != GetID("World"); diff --git a/imgui.cpp b/imgui.cpp index e4a63f9c..b1948d66 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -394,6 +394,7 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2026/01/08 (1.92.6) - Commented out legacy names obsoleted in 1.90 (Sept 2023): 'BeginChildFrame()' --> 'BeginChild()' with 'ImGuiChildFlags_FrameStyle'. 'EndChildFrame()' --> 'EndChild()'. 'ShowStackToolWindow()' --> 'ShowIDStackToolWindow()'. 'IM_OFFSETOF()' --> 'offsetof()'. - 2026/01/07 (1.92.6) - Popups: changed compile-time 'ImGuiPopupFlags popup_flags = 1' default value to be '= 0' for BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid(), OpenPopupOnItemClick(). Default value has same meaning before and after. - Refer to GitHub topic #9157 if you have any question. - Before this version, those functions had a 'ImGuiPopupFlags popup_flags = 1' default value in their function signature. @@ -6386,10 +6387,8 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I IM_ASSERT((child_flags & (ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY)) != 0 && "Must use ImGuiChildFlags_AutoResizeX or ImGuiChildFlags_AutoResizeY with ImGuiChildFlags_AlwaysAutoResize!"); } #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - //if (window_flags & ImGuiWindowFlags_AlwaysUseWindowPadding) - // child_flags |= ImGuiChildFlags_AlwaysUseWindowPadding; - //if (window_flags & ImGuiWindowFlags_NavFlattened) - // child_flags |= ImGuiChildFlags_NavFlattened; + //if (window_flags & ImGuiWindowFlags_AlwaysUseWindowPadding) { child_flags |= ImGuiChildFlags_AlwaysUseWindowPadding; } + //if (window_flags & ImGuiWindowFlags_NavFlattened) { child_flags |= ImGuiChildFlags_NavFlattened; } #endif if (child_flags & ImGuiChildFlags_AutoResizeX) child_flags &= ~ImGuiChildFlags_ResizeX; diff --git a/imgui.h b/imgui.h index 8d6b6371..fb2a505a 100644 --- a/imgui.h +++ b/imgui.h @@ -4035,15 +4035,16 @@ namespace ImGui IMGUI_API ImVec2 GetWindowContentRegionMin(); // Content boundaries min for the window (roughly (0,0)-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! IMGUI_API ImVec2 GetWindowContentRegionMax(); // Content boundaries max for the window (roughly (0,0)+Size-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! // OBSOLETED in 1.90.0 (from September 2023) - inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags window_flags = 0) { return BeginChild(id, size, ImGuiChildFlags_FrameStyle, window_flags); } - inline void EndChildFrame() { EndChild(); } - //inline bool BeginChild(const char* str_id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags){ return BeginChild(str_id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders - //inline bool BeginChild(ImGuiID id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags) { return BeginChild(id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders - inline void ShowStackToolWindow(bool* p_open = NULL) { ShowIDStackToolWindow(p_open); } IMGUI_API bool Combo(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int popup_max_height_in_items = -1); IMGUI_API bool ListBox(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int height_in_items = -1); // Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE) + // OBSOLETED in 1.90.0 (from September 2023) + //inline bool BeginChild(const char* str_id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags) { return BeginChild(str_id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders + //inline bool BeginChild(ImGuiID id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags) { return BeginChild(id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders + //inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0) { return BeginChild(id, size, ImGuiChildFlags_FrameStyle, flags); } + //inline void EndChildFrame() { EndChild(); } + //inline void ShowStackToolWindow(bool* p_open = NULL) { ShowIDStackToolWindow(p_open); } // OBSOLETED in 1.89.7 (from June 2023) //IMGUI_API void SetItemAllowOverlap(); // Use SetNextItemAllowOverlap() _before_ item. //-- OBSOLETED in 1.89.4 (from March 2023) @@ -4153,7 +4154,7 @@ typedef ImFontAtlasRect ImFontAtlasCustomRect; //typedef ImGuiKeyChord ImGuiKeyModFlags; // == int //enum ImGuiKeyModFlags_ { ImGuiKeyModFlags_None = 0, ImGuiKeyModFlags_Ctrl = ImGuiMod_Ctrl, ImGuiKeyModFlags_Shift = ImGuiMod_Shift, ImGuiKeyModFlags_Alt = ImGuiMod_Alt, ImGuiKeyModFlags_Super = ImGuiMod_Super }; -#define IM_OFFSETOF(_TYPE,_MEMBER) offsetof(_TYPE, _MEMBER) // OBSOLETED IN 1.90 (now using C++11 standard version) +//#define IM_OFFSETOF(_TYPE,_MEMBER) offsetof(_TYPE, _MEMBER) // OBSOLETED IN 1.90 (now using C++11 standard version) #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS diff --git a/imgui_internal.h b/imgui_internal.h index 86606f39..6af67614 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -278,9 +278,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 #define IM_TRUNC(_VAL) ((float)(int)(_VAL)) // Positive values only! ImTrunc() is not inlined in MSVC debug builds #define IM_ROUND(_VAL) ((float)(int)((_VAL) + 0.5f)) // Positive values only! -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -#define IM_FLOOR IM_TRUNC // [OBSOLETE] Renamed in 1.90.0 (Sept 2023) -#endif +//#define IM_FLOOR IM_TRUNC // [OBSOLETE] Renamed in 1.90.0 (Sept 2023) // Hint for branch prediction #if (defined(__cplusplus) && (__cplusplus >= 202002L)) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 202002L)) @@ -3784,7 +3782,7 @@ struct ImFontLoader IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); #endif #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -typedef ImFontLoader ImFontBuilderIO; // [renamed/changed in 1.92] The types are not actually compatible but we provide this as a compile-time error report helper. +typedef ImFontLoader ImFontBuilderIO; // [renamed/changed in 1.92.0] The types are not actually compatible but we provide this as a compile-time error report helper. #endif //----------------------------------------------------------------------------- From d1c5a66557b35f8ea473d33cf363c1b0ec46050d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 12 Jan 2026 12:11:10 +0100 Subject: [PATCH 17/25] Backends: WebGPU: rework unsupported path into an assert. (#9155, #9156) --- backends/imgui_impl_wgpu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index c8722cd4..e98e9f3c 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -1078,7 +1078,7 @@ WGPUSurface ImGui_ImplWGPU_CreateWGPUSurfaceHelper(ImGui_ImplWGPU_CreateSurfaceI surface = wgpuInstanceCreateSurface(info->Instance, &surface_descriptor); } #else - fprintf(stderr, "'CreateWGPUSurfaceHelper' is not implemented for this platform\n"); + IM_ASSERT(0 && "Unsupported WebGPU native platform!"); #endif return surface; } From f64c7c37efd9b0cead78e84f9378398b68ae5f61 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 12 Jan 2026 18:17:38 +0100 Subject: [PATCH 18/25] Fonts: fixed a crash when trying to use AddFont() with MergeMode=true on a font that has already been rendered. (#9162) --- docs/CHANGELOG.txt | 2 ++ imgui_draw.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b7b4f2cd..cd931535 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -74,6 +74,8 @@ Breaking Changes: until a shutdown of the owning context or font atlas. - The fact that handling of `FontDataOwnedByAtlas = false` was broken bypassed the issue altogether. + - Fixed a crash when trying to use AddFont() with MergeMode=true on a font that + has already been rendered. (#9162) [@ocornut, @cyfewlp] - Removed ImFontConfig::PixelSnapV added in 1.92 which turns out is unnecessary (and misdocumented). Post-rescale GlyphOffset is always rounded. - Popups: changed compile-time 'ImGuiPopupFlags popup_flags = 1' default value to be '= 0' for diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b839291b..780f6b84 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3049,6 +3049,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) { IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. font = font_cfg_in->DstFont ? font_cfg_in->DstFont : Fonts.back(); + ImFontAtlasFontDiscardBakes(this, font, 0); // Need to discard bakes if the font was already used, because baked->FontLoaderDatas[] will change size. (#9162) } // Add to list From 791ad9b82db44ada9fedb3e26b2d900974ac0959 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 13 Jan 2026 16:15:48 +0100 Subject: [PATCH 19/25] InvisibleButton: allow calling with size (0,0) to fit to available content size. (#9166, #7623) --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index cd931535..76d92219 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -163,6 +163,8 @@ Other Changes: nav cursor is visible and `io.ConfigNavMoveSetMousePos` is enabled. - 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 + size. (#9166, #7623) - Added GetItemFlags() in public API for consistency and to expose generic flags of last submitted item. (#9127) - Shortcuts: diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 88d3b7ca..4244c0be 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -836,11 +836,10 @@ bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiBut if (window->SkipItems) return false; - // Cannot use zero-size for InvisibleButton(). Unlike Button() there is not way to fallback using the label size. - IM_ASSERT(size_arg.x != 0.0f && size_arg.y != 0.0f); + // Ensure zero-size fits to contents + ImVec2 size = CalcItemSize(ImVec2(size_arg.x != 0.0f ? size_arg.x : -FLT_MIN, size_arg.y != 0.0f ? size_arg.y : -FLT_MIN), 0.0f, 0.0f); const ImGuiID id = window->GetID(str_id); - ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); ItemSize(size); if (!ItemAdd(bb, id, NULL, (flags & ImGuiButtonFlags_EnableNav) ? ImGuiItemFlags_None : ImGuiItemFlags_NoNav)) From 0d08927dae557cd537416661d932b19dc6f040db Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 14 Jan 2026 14:59:39 +0100 Subject: [PATCH 20/25] Error handling: Improve error handling and recovery for EndMenu()/EndCombo(). (#1651, #9165, #8499) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 2 +- imgui_widgets.cpp | 18 +++++++++++++++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 76d92219..0645eff9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -173,6 +173,8 @@ Other Changes: (which mimicks what's done internally in the ItemHoverable() function). (#9138) - Fixed tooltip placement being affected for a frame when located over an item activated by SetNextItemShortcut(). (#9138) +- Error Handling: + - Improve error handling and recovery for EndMenu()/EndCombo(). (#1651, #9165, #8499) - Debug Tools: - Debug Log: fixed incorrectly printing characters in IO log when submitting non-ASCII values to io.AddInputCharacter(). (#9099) diff --git a/imgui.cpp b/imgui.cpp index b1948d66..2a63f26e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -12455,7 +12455,7 @@ void ImGui::EndPopup() ImGuiWindow* window = g.CurrentWindow; if ((window->Flags & ImGuiWindowFlags_Popup) == 0 || g.BeginPopupStack.Size == 0) { - IM_ASSERT_USER_ERROR(0, "Calling EndPopup() too many times or in wrong window!"); + IM_ASSERT_USER_ERROR(0, "Calling EndPopup() in wrong window!"); return; } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 4244c0be..3b6ee215 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2053,8 +2053,15 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags void ImGui::EndCombo() { ImGuiContext& g = *GImGui; - EndPopup(); g.BeginComboDepth--; + char name[16]; + ImFormatString(name, IM_COUNTOF(name), "##Combo_%02d", g.BeginComboDepth); // FIXME: Move those to helpers? + if (strcmp(g.CurrentWindow->Name, name) != 0) + { + IM_ASSERT_USER_ERROR(0, "Calling EndCombo() in wrong window!"); + return; + } + EndPopup(); } // Call directly after the BeginCombo/EndCombo block. The preview is designed to only host non-interactive elements @@ -9399,7 +9406,12 @@ void ImGui::EndMenu() // Nav: When a left move request our menu failed, close ourselves. ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginMenu()/EndMenu() calls + + if ((window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) != (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) + { + IM_ASSERT_USER_ERROR(0, "Calling EndMenu() in wrong window!"); + return; + } ImGuiWindow* parent_window = window->ParentWindow; // Should always be != NULL is we passed assert. if (window->BeginCount == window->BeginCountPreviousFrame) if (g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet()) @@ -10343,7 +10355,7 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f ImGuiTabBar* tab_bar = g.CurrentTabBar; if (tab_bar == NULL) { - IM_ASSERT_USER_ERROR(tab_bar, "Needs to be called between BeginTabBar() and EndTabBar()!"); + IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); return false; } IM_ASSERT((flags & ImGuiTabItemFlags_Button) == 0); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead! From 7143d711bf3818f0ee342211ae5b381a31f94d32 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 14 Jan 2026 15:24:30 +0100 Subject: [PATCH 21/25] Images, Style: added style.ImageRounding, ImGuiStyleVar_ImageRounding to configure rounding of Image() widgets. (#2942, #845) Moving border drawing above AddImage() call, should not make a difference for square images. --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 3 +++ imgui.h | 2 ++ imgui_demo.cpp | 1 + imgui_widgets.cpp | 12 ++++++++---- 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0645eff9..1a732a04 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -167,6 +167,9 @@ Other Changes: size. (#9166, #7623) - Added GetItemFlags() in public API for consistency and to expose generic flags of last submitted item. (#9127) +- Images: + - Added style.ImageRounding, ImGuiStyleVar_ImageRounding to configure + rounding of Image() widgets. (#2942, #845) - Shortcuts: - IsItemHovered() without ImGuiHoveredFlags_AllowWhenBlockedByActiveItem doesn't filter out the signal when activated item is a shortcut remote activation; diff --git a/imgui.cpp b/imgui.cpp index 2a63f26e..105041d1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1470,6 +1470,7 @@ ImGuiStyle::ImGuiStyle() GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. + ImageRounding = 0.0f; // Rounding of Image() calls. ImageBorderSize = 0.0f; // Thickness of border around tabs. TabRounding = 5.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. TabBorderSize = 0.0f; // Thickness of border around tabs. @@ -1544,6 +1545,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) GrabMinSize = ImTrunc(GrabMinSize * scale_factor); GrabRounding = ImTrunc(GrabRounding * scale_factor); LogSliderDeadzone = ImTrunc(LogSliderDeadzone * scale_factor); + ImageRounding = ImTrunc(ImageRounding * scale_factor); ImageBorderSize = ImTrunc(ImageBorderSize * scale_factor); TabRounding = ImTrunc(TabRounding * scale_factor); TabMinWidthBase = ImTrunc(TabMinWidthBase * scale_factor); @@ -3603,6 +3605,7 @@ static const ImGuiStyleVarInfo GStyleVarsInfo[] = { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ScrollbarPadding) }, // ImGuiStyleVar_ScrollbarPadding { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ImageRounding) }, // ImGuiStyleVar_ImageRounding { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ImageBorderSize) }, // ImGuiStyleVar_ImageBorderSize { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabBorderSize) }, // ImGuiStyleVar_TabBorderSize diff --git a/imgui.h b/imgui.h index fb2a505a..33c642b0 100644 --- a/imgui.h +++ b/imgui.h @@ -1830,6 +1830,7 @@ enum ImGuiStyleVar_ ImGuiStyleVar_ScrollbarPadding, // float ScrollbarPadding ImGuiStyleVar_GrabMinSize, // float GrabMinSize ImGuiStyleVar_GrabRounding, // float GrabRounding + ImGuiStyleVar_ImageRounding, // float ImageRounding ImGuiStyleVar_ImageBorderSize, // float ImageBorderSize ImGuiStyleVar_TabRounding, // float TabRounding ImGuiStyleVar_TabBorderSize, // float TabBorderSize @@ -2300,6 +2301,7 @@ struct ImGuiStyle float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. + float ImageRounding; // Rounding of Image() calls. float ImageBorderSize; // Thickness of border around Image() calls. float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. float TabBorderSize; // Thickness of border around tabs. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b01c8694..5db91155 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8459,6 +8459,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f"); SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f"); SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"); + SliderFloat("ImageRounding", &style.ImageRounding, 0.0f, 12.0f, "%.0f"); SliderFloat("ImageBorderSize", &style.ImageBorderSize, 0.0f, 1.0f, "%.0f"); SeparatorText("Tooltips"); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3b6ee215..1071d3d8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1130,11 +1130,15 @@ void ImGui::ImageWithBg(ImTextureRef tex_ref, const ImVec2& image_size, const Im return; // Render - if (g.Style.ImageBorderSize > 0.0f) - window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border), 0.0f, ImDrawFlags_None, g.Style.ImageBorderSize); + float rounding = g.Style.ImageRounding; if (bg_col.w > 0.0f) - window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col)); - window->DrawList->AddImage(tex_ref, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); + window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col), rounding); + if (rounding > 0.0f) + window->DrawList->AddImageRounded(tex_ref, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col), rounding); + else + window->DrawList->AddImage(tex_ref, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); + if (g.Style.ImageBorderSize > 0.0f) + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border), rounding, ImDrawFlags_None, g.Style.ImageBorderSize); } void ImGui::Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1) From a1dfaf4869347b8f639f63cfc2636f2d9d8b20db Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 14 Jan 2026 15:54:55 +0100 Subject: [PATCH 22/25] ImageButton() doesn't use a clamped style.FrameRounding value but instead adjust inner image rounding when FramePadding > FrameRounding. (#2942, #845) --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1a732a04..2cc2d915 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -170,6 +170,8 @@ Other Changes: - Images: - Added style.ImageRounding, ImGuiStyleVar_ImageRounding to configure rounding of Image() widgets. (#2942, #845) + - ImageButton() doesn't use a clamped style.FrameRounding value but instead + adjust inner image rounding when FramePadding > FrameRounding. (#2942, #845) - Shortcuts: - IsItemHovered() without ImGuiHoveredFlags_AllowWhenBlockedByActiveItem doesn't filter out the signal when activated item is a shortcut remote activation; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1071d3d8..0a044a97 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1178,10 +1178,14 @@ bool ImGui::ImageButtonEx(ImGuiID id, ImTextureRef tex_ref, const ImVec2& image_ // Render const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); RenderNavCursor(bb, id); - RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, g.Style.FrameRounding)); + RenderFrame(bb.Min, bb.Max, col, true, g.Style.FrameRounding); if (bg_col.w > 0.0f) window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col)); - window->DrawList->AddImage(tex_ref, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); + float image_rounding = ImMax(g.Style.FrameRounding - ImMax(padding.x, padding.y), g.Style.ImageRounding); + if (image_rounding > 0.0f) + window->DrawList->AddImageRounded(tex_ref, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col), image_rounding); + else + window->DrawList->AddImage(tex_ref, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); return pressed; } From 9a6eb0ab2564925aac1bd1d9a7a3b3619192ca57 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 14 Jan 2026 19:23:57 +0100 Subject: [PATCH 23/25] Backends: Vulkan: ImGui_ImplVulkanH_DestroyWindow() oes not call vkDestroySurfaceKHR(): because surface is created by caller. (#9163) # Conflicts: # backends/imgui_impl_vulkan.cpp --- backends/imgui_impl_vulkan.cpp | 32 +++++++++++++++----------- backends/imgui_impl_vulkan.h | 5 ++-- docs/CHANGELOG.txt | 4 ++++ examples/example_glfw_vulkan/main.cpp | 12 +++++----- examples/example_sdl2_vulkan/main.cpp | 12 +++++----- examples/example_sdl3_vulkan/main.cpp | 12 +++++----- examples/example_win32_vulkan/main.cpp | 12 +++++----- 7 files changed, 49 insertions(+), 40 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index f0ca7907..f01d2145 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -27,12 +27,13 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-01-05: Vulkan: Helper for creating render pass uses ImGui_ImplVulkanH_Window::AttachmentDesc to create render pass. Removed ClearEnabled. (#9152) -// 2025-11-24: Vulkan: Helper for creating a swap-chain (used by examples and multi-viewports) selects VkSwapchainCreateInfoKHR's compositeAlpha based on cap.supportedCompositeAlpha. (#8784) +// 2025-09-26: [Helpers] *BREAKING CHANGE*: Vulkan: Helper ImGui_ImplVulkanH_DestroyWindow() does not call vkDestroySurfaceKHR(): as surface is created by caller of ImGui_ImplVulkanH_CreateOrResizeWindow(), it is more consistent that we don't destroy it. (#9163) +// 2026-01-05: [Helpers] *BREAKING CHANGE*: Vulkan: Helper for creating render pass uses ImGui_ImplVulkanH_Window::AttachmentDesc to create render pass. Removed ClearEnabled. (#9152) +// 2025-11-24: [Helpers] Vulkan: Helper for creating a swap-chain (used by examples and multi-viewports) selects VkSwapchainCreateInfoKHR's compositeAlpha based on cap.supportedCompositeAlpha. (#8784) // 2025-10-15: Vulkan: Added IMGUI_IMPL_VULKAN_VOLK_FILENAME to configure path to volk.h header. (#9008) // 2025-09-26: *BREAKING CHANGE*: moved some fields in ImGui_ImplVulkan_InitInfo: init_info.RenderPass --> init_info.PipelineInfoMain.RenderPass, init_info.Subpass --> init_info.PipelineInfoMain.Subpass, init_info.MSAASamples --> init_info.PipelineInfoMain.MSAASamples, init_info.PipelineRenderingCreateInfo --> init_info.PipelineInfoMain.PipelineRenderingCreateInfo. // 2025-09-26: *BREAKING CHANGE*: renamed ImGui_ImplVulkan_MainPipelineCreateInfo to ImGui_ImplVulkan_PipelineInfo. Introduced very recently so shouldn't affect many users. -// 2025-09-26: *BREAKING CHANGE*: helper ImGui_ImplVulkanH_CreateOrResizeWindow() added a VkImageUsageFlags image_usage` argument, default to VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT if 0. +// 2025-09-26: [Helpers] *BREAKING CHANGE*: Helper ImGui_ImplVulkanH_CreateOrResizeWindow() added a VkImageUsageFlags image_usage` argument, default to VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT if 0. // 2025-09-26: Vulkan: Added a way to customize shaders by filling ImGui_ImplVulkan_InitInfo::CustomShaderVertCreateInfo/CustomShaderFragCreateInfo. (#8585) // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-09-04: Vulkan: Added ImGui_ImplVulkan_CreateMainPipeline(). (#8110, #8111) @@ -46,8 +47,8 @@ // 2025-02-14: *BREAKING CHANGE*: Added uint32_t api_version to ImGui_ImplVulkan_LoadFunctions(). // 2025-02-13: Vulkan: Added ApiVersion field in ImGui_ImplVulkan_InitInfo. Default to header version if unspecified. Dynamic rendering path loads "vkCmdBeginRendering/vkCmdEndRendering" (without -KHR suffix) on API 1.3. (#8326) // 2025-01-09: Vulkan: Added IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE to clarify how many image sampler descriptors are expected to be available in descriptor pool. (#6642) -// 2025-01-06: Vulkan: Added more ImGui_ImplVulkanH_XXXX helper functions to simplify our examples. -// 2024-12-11: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) +// 2025-01-06: [Helpers] Vulkan: Added more ImGui_ImplVulkanH_XXXX helper functions to simplify our examples. +// 2024-12-11: [Helpers] Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) // 2024-11-27: Vulkan: Make user-provided descriptor pool optional. As a convenience, when setting init_info->DescriptorPoolSize the backend will create one itself. (#8172, #4867) // 2024-10-07: Vulkan: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-10-07: Vulkan: Expose selected render state in ImGui_ImplVulkan_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. @@ -55,7 +56,7 @@ // 2024-04-19: Vulkan: Added convenience support for Volk via IMGUI_IMPL_VULKAN_USE_VOLK define (you can also use IMGUI_IMPL_VULKAN_NO_PROTOTYPES + wrap Volk via ImGui_ImplVulkan_LoadFunctions().) // 2024-02-14: *BREAKING CHANGE*: Moved RenderPass parameter from ImGui_ImplVulkan_Init() function to ImGui_ImplVulkan_InitInfo structure. Not required when using dynamic rendering. // 2024-02-12: *BREAKING CHANGE*: Dynamic rendering now require filling PipelineRenderingCreateInfo structure. -// 2024-01-19: Vulkan: Fixed vkAcquireNextImageKHR() validation errors in VulkanSDK 1.3.275 by allocating one extra semaphore than in-flight frames. (#7236) +// 2024-01-19: [Helpers] Vulkan: Fixed vkAcquireNextImageKHR() validation errors in VulkanSDK 1.3.275 by allocating one extra semaphore than in-flight frames. (#7236) // 2024-01-11: Vulkan: Fixed vkMapMemory() calls unnecessarily using full buffer size (#3957). Fixed MinAllocationSize handing (#7189). // 2024-01-03: Vulkan: Added MinAllocationSize field in ImGui_ImplVulkan_InitInfo to workaround zealous "best practice" validation layer. (#7189, #4238) // 2024-01-03: Vulkan: Stopped creating command pools with VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT as we don't reset them. @@ -83,16 +84,16 @@ // 2019-05-29: Vulkan: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. // 2019-04-30: Vulkan: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. // 2019-04-04: *BREAKING CHANGE*: Vulkan: Added ImageCount/MinImageCount fields in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetMinImageCount(). -// 2019-04-04: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper. +// 2019-04-04: [Helpers] Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper. // 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like. // 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int). // 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display. // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. -// 2018-08-25: Vulkan: Fixed mishandled VkSurfaceCapabilitiesKHR::maxImageCount=0 case. +// 2018-08-25: [Helpers] Vulkan: Fixed mishandled VkSurfaceCapabilitiesKHR::maxImageCount=0 case. // 2018-06-22: Inverted the parameters to ImGui_ImplVulkan_RenderDrawData() to be consistent with other backends. // 2018-06-08: Misc: Extracted imgui_impl_vulkan.cpp/.h away from the old combined GLFW+Vulkan example. // 2018-06-08: Vulkan: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. -// 2018-03-03: Vulkan: Various refactor, created a couple of ImGui_ImplVulkanH_XXX helper that the example can use and that viewport support will use. +// 2018-03-03: [Helpers] Vulkan: Various refactor, created a couple of ImGui_ImplVulkanH_XXX helper that the example can use and that viewport support will use. // 2018-03-01: Vulkan: Renamed ImGui_ImplVulkan_Init_Info to ImGui_ImplVulkan_InitInfo and fields to match more closely Vulkan terminology. // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback, ImGui_ImplVulkan_Render() calls ImGui_ImplVulkan_RenderDrawData() itself. // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. @@ -1767,7 +1768,9 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count, VkImageUsageFlags image_usage) { IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!"); - (void)instance; + IM_ASSERT(wd->Surface != VK_NULL_HANDLE); + IM_UNUSED(instance); + ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count, image_usage); ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator); @@ -1850,6 +1853,7 @@ void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevic void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator) { + IM_UNUSED(instance); vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals) //vkQueueWaitIdle(bd->Queue); @@ -1862,9 +1866,11 @@ void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui vkDestroyPipeline(device, wd->Pipeline, allocator); vkDestroyRenderPass(device, wd->RenderPass, allocator); vkDestroySwapchainKHR(device, wd->Swapchain, allocator); - vkDestroySurfaceKHR(instance, wd->Surface, allocator); - - *wd = ImGui_ImplVulkanH_Window(); + wd->RenderPass = VK_NULL_HANDLE; + wd->Swapchain = VK_NULL_HANDLE; + wd->Width = wd->Height = 0; + wd->FrameIndex = wd->ImageCount = wd->SemaphoreCount = wd->SemaphoreIndex = 0; + //vkDestroySurfaceKHR(instance, wd->Surface, allocator); // v1.92.6 (~2026-01-16): because wd->Surface is user provided we don't attempt to destroy it ourself. } void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator) diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 83376e59..0ebe1d42 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -171,6 +171,7 @@ struct ImGui_ImplVulkan_RenderState // Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app. // // You probably do NOT need to use or care about those functions. +// WE DO NOT PROVIDE STRONG GUARANTEES OF BACKWARD/FORWARD COMPATIBILITY. // Those functions only exist because: // 1) they facilitate the readability and maintenance of the multiple main.cpp examples files. // 2) the multi-viewport / platform window implementation needs them internally. @@ -181,8 +182,6 @@ struct ImGui_ImplVulkan_RenderState // render pass, frame buffers, etc.). You may read this code if you are curious, but // it is recommended you use your own custom tailored code to do equivalent work. // -// We don't provide a strong guarantee that we won't change those functions API. -// // The ImGui_ImplVulkanH_XXX functions should NOT interact with any of the state used // by the regular ImGui_ImplVulkan_XXX functions. //------------------------------------------------------------------------- @@ -224,6 +223,7 @@ struct ImGui_ImplVulkanH_Window { // Input bool UseDynamicRendering; + VkSurfaceKHR Surface; // Surface created and destroyed by caller. VkSurfaceFormatKHR SurfaceFormat; VkPresentModeKHR PresentMode; VkAttachmentDescription AttachmentDesc; // RenderPass creation: main attachment description. @@ -233,7 +233,6 @@ struct ImGui_ImplVulkanH_Window int Width; // Generally same as passed to ImGui_ImplVulkanH_CreateOrResizeWindow() int Height; VkSwapchainKHR Swapchain; - VkSurfaceKHR Surface; VkRenderPass RenderPass; VkPipeline Pipeline; // The window pipeline may uses a different VkRenderPass than the one passed in ImGui_ImplVulkan_InitInfo uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2cc2d915..6de32507 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -105,6 +105,10 @@ Breaking Changes: - BeginPopupContextItem("foo", 1); // Behavior unchanged (as a courtesy we legacy interpret 1 as ImGuiPopupFlags_MouseButtonRight, will assert if disabling legacy behaviors. - BeginPopupContextItem("foo", 0); // !! Behavior changed !! Was Left button. Now will defaults to Right button! --> Use ImGuiPopupFlags_MouseButtonLeft. - BeginPopupContextItem("foo", ImGuiPopupFlags_NoReopen); // !! Behavior changed !! Was Left button + flags. Now will defaults to Right button! --> Use ImGuiPopupFlags_MouseButtonLeft | xxx. +- Backends: + - Vulkan: optional ImGui_ImplVulkanH_DestroyWindow() helper used by our example + code does not call vkDestroySurfaceKHR(): because surface is created by caller + of ImGui_ImplVulkanH_CreateOrResizeWindow(), it is more consistent. (#9163) Other Changes: diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index ab259a3e..ccce94fb 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -212,11 +212,9 @@ static void SetupVulkan(ImVector instance_extensions) // Your real engine/app may not use them. static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height) { - wd->Surface = surface; - // Check for WSI support VkBool32 res; - vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, wd->Surface, &res); + vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, surface, &res); if (res != VK_TRUE) { fprintf(stderr, "Error no WSI support on physical device 0\n"); @@ -226,6 +224,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface // Select Surface Format const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM }; const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + wd->Surface = surface; wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_COUNTOF(requestSurfaceImageFormat), requestSurfaceColorSpace); // Select Present Mode @@ -256,9 +255,10 @@ static void CleanupVulkan() vkDestroyInstance(g_Instance, g_Allocator); } -static void CleanupVulkanWindow() +static void CleanupVulkanWindow(ImGui_ImplVulkanH_Window* wd) { - ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator); + ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, wd, g_Allocator); + vkDestroySurfaceKHR(g_Instance, wd->Surface, g_Allocator); } static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) @@ -532,7 +532,7 @@ int main(int, char**) ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); - CleanupVulkanWindow(); + CleanupVulkanWindow(&g_MainWindowData); CleanupVulkan(); glfwDestroyWindow(window); diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index 58f4f8e1..87a38ff9 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -203,11 +203,9 @@ static void SetupVulkan(ImVector instance_extensions) // Your real engine/app may not use them. static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height) { - wd->Surface = surface; - // Check for WSI support VkBool32 res; - vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, wd->Surface, &res); + vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, surface, &res); if (res != VK_TRUE) { fprintf(stderr, "Error no WSI support on physical device 0\n"); @@ -217,6 +215,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface // Select Surface Format const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM }; const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + wd->Surface = surface; wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_COUNTOF(requestSurfaceImageFormat), requestSurfaceColorSpace); // Select Present Mode @@ -247,9 +246,10 @@ static void CleanupVulkan() vkDestroyInstance(g_Instance, g_Allocator); } -static void CleanupVulkanWindow() +static void CleanupVulkanWindow(ImGui_ImplVulkanH_Window* wd) { - ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator); + ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, wd, g_Allocator); + vkDestroySurfaceKHR(g_Instance, wd->Surface, g_Allocator); } static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) @@ -547,7 +547,7 @@ int main(int, char**) ImGui_ImplSDL2_Shutdown(); ImGui::DestroyContext(); - CleanupVulkanWindow(); + CleanupVulkanWindow(&g_MainWindowData); CleanupVulkan(); SDL_DestroyWindow(window); diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index fa229693..38c48d3a 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -205,11 +205,9 @@ static void SetupVulkan(ImVector instance_extensions) // Your real engine/app may not use them. static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height) { - wd->Surface = surface; - // Check for WSI support VkBool32 res; - vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, wd->Surface, &res); + vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, surface, &res); if (res != VK_TRUE) { fprintf(stderr, "Error no WSI support on physical device 0\n"); @@ -219,6 +217,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface // Select Surface Format const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM }; const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + wd->Surface = surface; wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_COUNTOF(requestSurfaceImageFormat), requestSurfaceColorSpace); // Select Present Mode @@ -249,9 +248,10 @@ static void CleanupVulkan() vkDestroyInstance(g_Instance, g_Allocator); } -static void CleanupVulkanWindow() +static void CleanupVulkanWindow(ImGui_ImplVulkanH_Window* wd) { - ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator); + ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, wd, g_Allocator); + vkDestroySurfaceKHR(g_Instance, wd->Surface, g_Allocator); } static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) @@ -550,7 +550,7 @@ int main(int, char**) ImGui_ImplSDL3_Shutdown(); ImGui::DestroyContext(); - CleanupVulkanWindow(); + CleanupVulkanWindow(&g_MainWindowData); CleanupVulkan(); SDL_DestroyWindow(window); diff --git a/examples/example_win32_vulkan/main.cpp b/examples/example_win32_vulkan/main.cpp index b70cb9fc..75c5605c 100644 --- a/examples/example_win32_vulkan/main.cpp +++ b/examples/example_win32_vulkan/main.cpp @@ -201,11 +201,9 @@ static void SetupVulkan(ImVector instance_extensions) // Your real engine/app may not use them. static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height) { - wd->Surface = surface; - // Check for WSI support VkBool32 res; - vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, wd->Surface, &res); + vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, surface, &res); if (res != VK_TRUE) { fprintf(stderr, "Error no WSI support on physical device 0\n"); @@ -215,6 +213,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface // Select Surface Format const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM }; const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + wd->Surface = surface; wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_COUNTOF(requestSurfaceImageFormat), requestSurfaceColorSpace); // Select Present Mode @@ -245,9 +244,10 @@ static void CleanupVulkan() vkDestroyInstance(g_Instance, g_Allocator); } -static void CleanupVulkanWindow() +static void CleanupVulkanWindow(ImGui_ImplVulkanH_Window* wd) { - ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator); + ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, wd, g_Allocator); + vkDestroySurfaceKHR(g_Instance, wd->Surface, g_Allocator); } static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) @@ -516,7 +516,7 @@ int main(int, char**) ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); - CleanupVulkanWindow(); + CleanupVulkanWindow(&g_MainWindowData); CleanupVulkan(); ::DestroyWindow(hwnd); From d7598aa84fa0b803c3548d0982dc9af5ee2c4301 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 15 Jan 2026 16:07:07 +0100 Subject: [PATCH 24/25] Backends: SDL2, SDL3: changed GetClipboardText() handler to return NULL on error aka clipboard contents is not text. (#9168) Consistent with other backends. --- backends/imgui_impl_sdl2.cpp | 6 +++++- backends/imgui_impl_sdl3.cpp | 6 +++++- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 3 ++- imgui.h | 2 +- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 371b1dac..2049f117 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) +// 2026-01-15: Changed GetClipboardText() handler to return nullptr on error aka clipboard contents is not text. Consistent with other backends. (#9168) // 2025-09-24: Skip using the SDL_GetGlobalMouseState() state when one of our window is hovered, as the SDL_MOUSEMOTION data is reliable. Fix macOS notch mouse coordinates issue in fullscreen mode + better perf on X11. (#7919, #7786) // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. // 2025-09-15: Content Scales are always reported as 1.0 on Wayland. (#8921) @@ -178,7 +179,10 @@ static const char* ImGui_ImplSDL2_GetClipboardText(ImGuiContext*) ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); if (bd->ClipboardTextData) SDL_free(bd->ClipboardTextData); - bd->ClipboardTextData = SDL_GetClipboardText(); + if (SDL_HasClipboardText()) + bd->ClipboardTextData = SDL_GetClipboardText(); + else + bd->ClipboardTextData = nullptr; return bd->ClipboardTextData; } diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index ffd9f8a5..a1a3eeb8 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) +// 2026-01-15: Changed GetClipboardText() handler to return nullptr on error aka clipboard contents is not text. Consistent with other backends. (#9168) // 2025-11-05: Fixed an issue with missing characters events when an already active text field changes viewports. (#9054) // 2025-10-22: Fixed Platform_OpenInShellFn() return value (unused in core). // 2025-09-24: Skip using the SDL_GetGlobalMouseState() state when one of our window is hovered, as the SDL_EVENT_MOUSE_MOTION data is reliable. Fix macOS notch mouse coordinates issue in fullscreen mode + better perf on X11. (#7919, #7786) @@ -151,7 +152,10 @@ static const char* ImGui_ImplSDL3_GetClipboardText(ImGuiContext*) ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); if (bd->ClipboardTextData) SDL_free(bd->ClipboardTextData); - bd->ClipboardTextData = SDL_GetClipboardText(); + if (SDL_HasClipboardText()) + bd->ClipboardTextData = SDL_GetClipboardText(); + else + bd->ClipboardTextData = nullptr; return bd->ClipboardTextData; } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6de32507..61798aa8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -195,6 +195,8 @@ Other Changes: forcefully disable either. (#9109, #9116) - OpenGL3: Fixed embedded loader multiple init/shutdown cycles broken on some platforms. (#8792, #9112) + - SDL2, SDL3: changed GetClipboardText() handler to return NULL on error aka + clipboard contents is not text. Consistent with other backends. (#9168) - SDL_GPU3: macOS version can use MSL shaders in order to support macOS 10.14+ (vs Metallib shaders requiring macOS 14+). Requires application calling SDL_CreateGPUDevice() with SDL_GPU_SHADERFORMAT_MSL. (#9076) [@Niminem] diff --git a/imgui.cpp b/imgui.cpp index 105041d1..4743838c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5091,10 +5091,11 @@ void ImGui::DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr } } +// A conformant backend should return NULL on failure (e.g. clipboard data is not text). const char* ImGui::GetClipboardText() { ImGuiContext& g = *GImGui; - return g.PlatformIO.Platform_GetClipboardTextFn ? g.PlatformIO.Platform_GetClipboardTextFn(&g) : ""; + return g.PlatformIO.Platform_GetClipboardTextFn ? g.PlatformIO.Platform_GetClipboardTextFn(&g) : NULL; } void ImGui::SetClipboardText(const char* text) diff --git a/imgui.h b/imgui.h index 33c642b0..448221dc 100644 --- a/imgui.h +++ b/imgui.h @@ -3956,7 +3956,7 @@ struct ImGuiPlatformIO // Optional: Access OS clipboard // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) - const char* (*Platform_GetClipboardTextFn)(ImGuiContext* ctx); + const char* (*Platform_GetClipboardTextFn)(ImGuiContext* ctx); // Should return NULL on failure (e.g. clipboard data is not text). void (*Platform_SetClipboardTextFn)(ImGuiContext* ctx, const char* text); void* Platform_ClipboardUserData; From 21d3299e588b5c702dcca0f448b4f937af369b4a Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 15 Jan 2026 16:08:40 +0100 Subject: [PATCH 25/25] Backends: fixed reappearing uses to NULL to favor nullptr. --- backends/imgui_impl_allegro5.cpp | 2 +- backends/imgui_impl_allegro5.h | 2 +- backends/imgui_impl_dx10.h | 2 +- backends/imgui_impl_dx11.h | 2 +- backends/imgui_impl_dx12.cpp | 2 +- backends/imgui_impl_dx12.h | 2 +- backends/imgui_impl_dx9.h | 2 +- backends/imgui_impl_glfw.cpp | 4 ++-- backends/imgui_impl_metal.h | 4 ++-- backends/imgui_impl_opengl2.h | 2 +- backends/imgui_impl_opengl3.cpp | 2 +- backends/imgui_impl_opengl3.h | 2 +- backends/imgui_impl_sdl2.cpp | 2 +- backends/imgui_impl_sdl3.cpp | 4 ++-- backends/imgui_impl_sdlgpu3.h | 2 +- backends/imgui_impl_sdlrenderer2.h | 2 +- backends/imgui_impl_sdlrenderer3.h | 2 +- backends/imgui_impl_vulkan.cpp | 2 +- backends/imgui_impl_vulkan.h | 2 +- backends/imgui_impl_wgpu.h | 2 +- 20 files changed, 23 insertions(+), 23 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index bb6660d8..6ee88a18 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -524,7 +524,7 @@ void ImGui_ImplAllegro5_SetDisplay(ALLEGRO_DISPLAY* display) if (bd->VertexDecl) { al_destroy_vertex_decl(bd->VertexDecl); - bd->VertexDecl = NULL; + bd->VertexDecl = nullptr; } if (bd->Display && !bd->VertexDecl) diff --git a/backends/imgui_impl_allegro5.h b/backends/imgui_impl_allegro5.h index 62243043..135c4ff8 100644 --- a/backends/imgui_impl_allegro5.h +++ b/backends/imgui_impl_allegro5.h @@ -38,7 +38,7 @@ IMGUI_IMPL_API void ImGui_ImplAllegro5_SetDisplay(ALLEGRO_DISPLAY* display); IMGUI_IMPL_API bool ImGui_ImplAllegro5_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplAllegro5_InvalidateDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplAllegro5_UpdateTexture(ImTextureData* tex); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_dx10.h b/backends/imgui_impl_dx10.h index 38ecbdfe..9d7fb68a 100644 --- a/backends/imgui_impl_dx10.h +++ b/backends/imgui_impl_dx10.h @@ -32,7 +32,7 @@ IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplDX10_UpdateTexture(ImTextureData* tex); // [BETA] Selected render state data shared with callbacks. diff --git a/backends/imgui_impl_dx11.h b/backends/imgui_impl_dx11.h index c120bf09..1df4f369 100644 --- a/backends/imgui_impl_dx11.h +++ b/backends/imgui_impl_dx11.h @@ -34,7 +34,7 @@ IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplDX11_UpdateTexture(ImTextureData* tex); // [BETA] Selected render state data shared with callbacks. diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 14c0fc60..056d23a6 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -875,7 +875,7 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) init_info = &bd->InitInfo; bd->pd3dDevice = init_info->Device; - IM_ASSERT(init_info->CommandQueue != NULL); + IM_ASSERT(init_info->CommandQueue != nullptr); bd->pCommandQueue = init_info->CommandQueue; bd->RTVFormat = init_info->RTVFormat; bd->DSVFormat = init_info->DSVFormat; diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index 3bb66c1f..8d61dae7 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h @@ -64,7 +64,7 @@ IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex); // [BETA] Selected render state data shared with callbacks. diff --git a/backends/imgui_impl_dx9.h b/backends/imgui_impl_dx9.h index 600f0a75..021439b9 100644 --- a/backends/imgui_impl_dx9.h +++ b/backends/imgui_impl_dx9.h @@ -31,7 +31,7 @@ IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplDX9_UpdateTexture(ImTextureData* tex); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 82c512fe..f166b45d 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -251,10 +251,10 @@ static bool ImGui_ImplGlfw_IsWayland() 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 + if (strstr(version, "Wayland") == nullptr) // e.g. Ubuntu 22.04 ships with GLFW 3.3.6 compiled without Wayland return false; #ifdef GLFW_EXPOSE_NATIVE_X11 - if (glfwGetX11Display() != NULL) + if (glfwGetX11Display() != nullptr) return false; #endif return true; diff --git a/backends/imgui_impl_metal.h b/backends/imgui_impl_metal.h index 2a9a26a0..8af2c8b6 100644 --- a/backends/imgui_impl_metal.h +++ b/backends/imgui_impl_metal.h @@ -39,7 +39,7 @@ IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id device); IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex); #endif @@ -67,7 +67,7 @@ IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device); IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex); #endif diff --git a/backends/imgui_impl_opengl2.h b/backends/imgui_impl_opengl2.h index 014a03ac..65b0fe0b 100644 --- a/backends/imgui_impl_opengl2.h +++ b/backends/imgui_impl_opengl2.h @@ -37,7 +37,7 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 133b0ed2..6348b01b 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -41,7 +41,7 @@ // 2023-05-09: OpenGL: Support for glBindSampler() backup/restore on ES3. (#6375) // 2023-04-18: OpenGL: Restore front and back polygon mode separately when supported by context. (#6333) // 2023-03-23: OpenGL: Properly restoring "no shader program bound" if it was the case prior to running the rendering function. (#6267, #6220, #6224) -// 2023-03-15: OpenGL: Fixed GL loader crash when GL_VERSION returns NULL. (#6154, #4445, #3530) +// 2023-03-15: OpenGL: Fixed GL loader crash when GL_VERSION returns nullptr. (#6154, #4445, #3530) // 2023-03-06: OpenGL: Fixed restoration of a potentially deleted OpenGL program, by calling glIsProgram(). (#6220, #6224) // 2022-11-09: OpenGL: Reverted use of glBufferSubData(), too many corruptions issues + old issues seemingly can't be reproed with Intel drivers nowadays (revert 2021-12-15 and 2022-05-23 changes). // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. diff --git a/backends/imgui_impl_opengl3.h b/backends/imgui_impl_opengl3.h index b72b5c88..aabe04b0 100644 --- a/backends/imgui_impl_opengl3.h +++ b/backends/imgui_impl_opengl3.h @@ -40,7 +40,7 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex); // Configuration flags to add in your imconfig file: diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 2049f117..4fb9c4d9 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -684,7 +684,7 @@ static void ImGui_ImplSDL2_UpdateMouseData() // Note that SDL_GetGlobalMouseState() is in theory slow on X11, but this only runs on rather specific cases. If a problem we may provide a way to opt-out this feature. SDL_Window* hovered_window = SDL_GetMouseFocus(); const bool is_relative_mouse_mode = SDL_GetRelativeMouseMode() != 0; - if (hovered_window == NULL && bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) + if (hovered_window == nullptr && bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) { // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) int mouse_x, mouse_y; diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index a1a3eeb8..f8bacc51 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -191,7 +191,7 @@ static void ImGui_ImplSDL3_UpdateIme() SDL_StopTextInput(bd->ImeWindow); bd->ImeWindow = nullptr; } - if ((!bd->ImeDirty && bd->ImeWindow == window) || (window == NULL)) + if ((!bd->ImeDirty && bd->ImeWindow == window) || (window == nullptr)) return; // Start/update current input @@ -663,7 +663,7 @@ static void ImGui_ImplSDL3_UpdateMouseData() // Note that SDL_GetGlobalMouseState() is in theory slow on X11, but this only runs on rather specific cases. If a problem we may provide a way to opt-out this feature. SDL_Window* hovered_window = SDL_GetMouseFocus(); const bool is_relative_mouse_mode = SDL_GetWindowRelativeMouseMode(bd->Window); - if (hovered_window == NULL && bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) + if (hovered_window == nullptr && bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) { // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) float mouse_x, mouse_y; diff --git a/backends/imgui_impl_sdlgpu3.h b/backends/imgui_impl_sdlgpu3.h index cde9c5fe..12b6528f 100644 --- a/backends/imgui_impl_sdlgpu3.h +++ b/backends/imgui_impl_sdlgpu3.h @@ -48,7 +48,7 @@ IMGUI_IMPL_API void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, IMGUI_IMPL_API void ImGui_ImplSDLGPU3_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplSDLGPU3_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex); // [BETA] Selected render state data shared with callbacks. diff --git a/backends/imgui_impl_sdlrenderer2.h b/backends/imgui_impl_sdlrenderer2.h index a62e6092..860e9550 100644 --- a/backends/imgui_impl_sdlrenderer2.h +++ b/backends/imgui_impl_sdlrenderer2.h @@ -39,7 +39,7 @@ IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_d IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_UpdateTexture(ImTextureData* tex); // [BETA] Selected render state data shared with callbacks. diff --git a/backends/imgui_impl_sdlrenderer3.h b/backends/imgui_impl_sdlrenderer3.h index 618cc243..f5f53b9d 100644 --- a/backends/imgui_impl_sdlrenderer3.h +++ b/backends/imgui_impl_sdlrenderer3.h @@ -39,7 +39,7 @@ IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_d IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_UpdateTexture(ImTextureData* tex); // [BETA] Selected render state data shared with callbacks. diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index f01d2145..8f4bd5a6 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -1156,7 +1156,7 @@ void ImGui_ImplVulkan_CreateMainPipeline(const ImGui_ImplVulkan_PipelineInfo* pi #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING VkPipelineRenderingCreateInfoKHR* pipeline_rendering_create_info = &pipeline_info->PipelineRenderingCreateInfo; - if (v->UseDynamicRendering && pipeline_rendering_create_info->pColorAttachmentFormats != NULL) + if (v->UseDynamicRendering && pipeline_rendering_create_info->pColorAttachmentFormats != nullptr) { // Deep copy buffer to reduce error-rate for end user (#8282) ImVector formats; diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 0ebe1d42..4ad33b8f 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -142,7 +142,7 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_i // Else, the pipeline can be created, or re-created, using ImGui_ImplVulkan_CreateMainPipeline() before rendering. IMGUI_IMPL_API void ImGui_ImplVulkan_CreateMainPipeline(const ImGui_ImplVulkan_PipelineInfo* info); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex); // Register a texture (VkDescriptorSet == ImTextureID) diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index f17fe6c2..7ab3dd31 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -72,7 +72,7 @@ IMGUI_IMPL_API void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURen IMGUI_IMPL_API bool ImGui_ImplWGPU_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplWGPU_InvalidateDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplWGPU_UpdateTexture(ImTextureData* tex); // [BETA] Selected render state data shared with callbacks.