From 531364d72896f41c973730c2fbc0478da4ba64c6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 1 Aug 2024 22:26:12 +0200 Subject: [PATCH 01/10] Window refresh policy: fixed child window of skiprefresh windows not displaying. (#7797) Amend d4495446d. (#3515, #4763, #7556, #5116 , #4076, #2749, #2268) --- imgui.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 94c59e7ea..edbf15069 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6531,6 +6531,17 @@ void ImGui::UpdateWindowSkipRefresh(ImGuiWindow* window) } } +static void SetWindowActiveForSkipRefresh(ImGuiWindow* window) +{ + window->Active = true; + for (ImGuiWindow* child : window->DC.ChildWindows) + if (!child->Hidden) + { + child->Active = child->SkipRefresh = true; + SetWindowActiveForSkipRefresh(child); + } +} + // When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing) // should be positioned behind that modal window, unless the window was created inside the modal begin-stack. // In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent. @@ -7233,7 +7244,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { // Skip refresh always mark active if (window->SkipRefresh) - window->Active = true; + SetWindowActiveForSkipRefresh(window); // Append SetCurrentWindow(window); From 6864a7f839ce78419d5db57a46c25c4216e9c712 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 1 Aug 2024 22:40:09 +0200 Subject: [PATCH 02/10] Window refresh policy: extend tests to any window in the begin stack. (#7797) --- imgui.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index edbf15069..d1da2886e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6522,10 +6522,12 @@ void ImGui::UpdateWindowSkipRefresh(ImGuiWindow* window) return; if (window->Hidden) // If was hidden (previous frame) return; - if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnHover) && g.HoveredWindow && window->RootWindow == g.HoveredWindow->RootWindow) - return; - if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnFocus) && g.NavWindow && window->RootWindow == g.NavWindow->RootWindow) - return; + if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnHover) && g.HoveredWindow) + if (window->RootWindow == g.HoveredWindow->RootWindow || IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, window)) + return; + if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnFocus) && g.NavWindow) + if (window->RootWindow == g.NavWindow->RootWindow || IsWindowWithinBeginStackOf(g.NavWindow->RootWindow, window)) + return; window->DrawList = NULL; window->SkipRefresh = true; } From 8cc6eee295871bc8852c12372860a50b950d3f56 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 3 Aug 2024 15:25:47 +0200 Subject: [PATCH 03/10] Fonts: amend assert when glyph range data seems incorrect. (#7856) --- imgui_draw.cpp | 5 +++-- misc/freetype/imgui_freetype.cpp | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 854ad4012..32cf64353 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2815,8 +2815,9 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) { // Check for valid range. This may also help detect *some* dangling pointers, because a common - // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent. - IM_ASSERT(src_range[0] <= src_range[1]); + // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent, + // or to forget to zero-terminate the glyph range array. + IM_ASSERT(src_range[0] <= src_range[1] && "Invalid range: is your glyph range array persistent? it is zero-terminated?"); src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); } dst_tmp.SrcCount++; diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 68e38ed95..d97605b25 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -480,8 +480,9 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) { // Check for valid range. This may also help detect *some* dangling pointers, because a common - // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent. - IM_ASSERT(src_range[0] <= src_range[1]); + // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent, + // or to forget to zero-terminate the glyph range array. + IM_ASSERT(src_range[0] <= src_range[1] && "Invalid range: is your glyph range array persistent? it is zero-terminated?"); src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); } dst_tmp.SrcCount++; From 4b654db9040851228857528b44e195e358868e9a Mon Sep 17 00:00:00 2001 From: Mark Jansen Date: Tue, 6 Aug 2024 20:27:23 +0200 Subject: [PATCH 04/10] CI: Build example_sdl2_sdlrenderer2 with msbuild (#7864) --- .github/workflows/build.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 48082d056..b223d2261 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -123,6 +123,11 @@ jobs: run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj /p:Platform=Win32 /p:Configuration=Release' if: github.event_name == 'workflow_run' + - name: Build Win32 example_sdl2_sdlrenderer2 + shell: cmd + run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj /p:Platform=Win32 /p:Configuration=Release' + if: github.event_name == 'workflow_run' + - name: Build Win32 example_sdl2_vulkan shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj /p:Platform=Win32 /p:Configuration=Release' @@ -168,6 +173,11 @@ jobs: shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release' + - name: Build x64 example_sdl2_sdlrenderer2 + shell: cmd + run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj /p:Platform=x64 /p:Configuration=Release' + if: github.event_name == 'workflow_run' + - name: Build x64 example_sdl2_vulkan shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release' From 3232070d3abaec531d75e060fab14a26cb36ab55 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 7 Aug 2024 12:47:03 +0200 Subject: [PATCH 05/10] Demo: Fixed truncation warning. (#7857) --- imgui_demo.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 2800e9518..264df8af4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -310,23 +310,24 @@ static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, Exampl static ExampleTreeNode* ExampleTree_CreateDemoTree() { static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" }; - char name_buf[32]; + const size_t NAME_MAX_LEN = sizeof(ExampleTreeNode::Name); + char name_buf[NAME_MAX_LEN]; int uid = 0; ExampleTreeNode* node_L0 = ExampleTree_CreateNode("", ++uid, NULL); const int root_items_multiplier = 2; for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * root_items_multiplier; idx_L0++) { - snprintf(name_buf, 32, "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier); + snprintf(name_buf, IM_ARRAYSIZE(name_buf), "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier); ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0); const int number_of_childs = (int)strlen(node_L1->Name); for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++) { - snprintf(name_buf, 32, "Child %d", idx_L1); + snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Child %d", idx_L1); ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1); node_L2->HasData = true; if (idx_L1 == 0) { - snprintf(name_buf, 32, "Sub-child %d", 0); + snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Sub-child %d", 0); ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2); node_L3->HasData = true; } From 45e7f7827a52462d83895d36c62d00e6eb33c266 Mon Sep 17 00:00:00 2001 From: lunarlattice <18731514+lunarlattice0@users.noreply.github.com> Date: Fri, 9 Aug 2024 03:27:38 -0700 Subject: [PATCH 06/10] Examples: SDL2+SDLRenderer: fixed return value. (#7876) --- examples/example_sdl2_sdlrenderer2/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example_sdl2_sdlrenderer2/main.cpp b/examples/example_sdl2_sdlrenderer2/main.cpp index b186b6268..31fa3f9bf 100644 --- a/examples/example_sdl2_sdlrenderer2/main.cpp +++ b/examples/example_sdl2_sdlrenderer2/main.cpp @@ -47,7 +47,7 @@ int main(int, char**) if (renderer == nullptr) { SDL_Log("Error creating SDL_Renderer!"); - return 0; + return -1; } //SDL_RendererInfo info; //SDL_GetRendererInfo(renderer, &info); From 29fadad1939ab62adcc5cd9339db7a784de90120 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 13 Aug 2024 14:30:16 +0200 Subject: [PATCH 07/10] TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) --- docs/CHANGELOG.txt | 1 + imgui_widgets.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a495cd5d3..386d330c8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,7 @@ Other changes: payload over an already open tree node would incorrectly select it. (#7850) - MultiSelect+TreeNode: default open behavior is OpenOnDoubleClick + OpenOnArrow when used in a multi-select context without any OpenOnXXX flags set. (#7850) +- TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not provide a way to do a portable sleep. (#7844) - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 11f1cdf60..d5c9fa077 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1425,6 +1425,9 @@ bool ImGui::TextLink(const char* label) bool pressed = ButtonBehavior(bb, id, &hovered, &held); RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_None); + if (hovered) + SetMouseCursor(ImGuiMouseCursor_Hand); + ImVec4 text_colf = g.Style.Colors[ImGuiCol_TextLink]; ImVec4 line_colf = text_colf; { From 591a18a9c4bf421de05a0eee7e85dea25f64209d Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 2 Aug 2024 00:05:51 +0200 Subject: [PATCH 08/10] Backends: SDL2, SDL3: ignore events of other SDL windows. (#7853) --- backends/imgui_impl_sdl2.cpp | 12 ++++++++++++ backends/imgui_impl_sdl3.cpp | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 15db0a843..2b115f360 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -321,6 +321,8 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) { case SDL_MOUSEMOTION: { + if (event->motion.windowID != SDL_GetWindowID(bd->Window)) + return false; ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); io.AddMousePosEvent(mouse_pos.x, mouse_pos.y); @@ -328,6 +330,8 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_MOUSEWHEEL: { + if (event->wheel.windowID != SDL_GetWindowID(bd->Window)) + return false; //IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY); #if SDL_VERSION_ATLEAST(2,0,18) // If this fails to compile on Emscripten: update to latest Emscripten! float wheel_x = -event->wheel.preciseX; @@ -346,6 +350,8 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: { + if (event->button.windowID != SDL_GetWindowID(bd->Window)) + return false; int mouse_button = -1; if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; } if (event->button.button == SDL_BUTTON_RIGHT) { mouse_button = 1; } @@ -361,12 +367,16 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_TEXTINPUT: { + if (event->text.windowID != SDL_GetWindowID(bd->Window)) + return false; io.AddInputCharactersUTF8(event->text.text); return true; } case SDL_KEYDOWN: case SDL_KEYUP: { + if (event->key.windowID != SDL_GetWindowID(bd->Window)) + return false; ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod); ImGuiKey key = ImGui_ImplSDL2_KeyEventToImGuiKey(event->key.keysym.sym, event->key.keysym.scancode); io.AddKeyEvent(key, (event->type == SDL_KEYDOWN)); @@ -375,6 +385,8 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_WINDOWEVENT: { + if (event->window.windowID != SDL_GetWindowID(bd->Window)) + return false; // - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER event on every mouse move, but the final ENTER tends to be right. // - However we won't get a correct LEAVE event for a captured window. // - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late, diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 05718d21c..a74a316d2 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -307,6 +307,8 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) { case SDL_EVENT_MOUSE_MOTION: { + if (event->motion.windowID != SDL_GetWindowID(bd->Window)) + return false; ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); io.AddMousePosEvent(mouse_pos.x, mouse_pos.y); @@ -314,6 +316,8 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_MOUSE_WHEEL: { + if (event->wheel.windowID != SDL_GetWindowID(bd->Window)) + return false; //IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY); float wheel_x = -event->wheel.x; float wheel_y = event->wheel.y; @@ -327,6 +331,8 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: { + if (event->button.windowID != SDL_GetWindowID(bd->Window)) + return false; int mouse_button = -1; if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; } if (event->button.button == SDL_BUTTON_RIGHT) { mouse_button = 1; } @@ -342,12 +348,16 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_TEXT_INPUT: { + if (event->text.windowID != SDL_GetWindowID(bd->Window)) + return false; io.AddInputCharactersUTF8(event->text.text); return true; } case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: { + if (event->key.windowID != SDL_GetWindowID(bd->Window)) + return false; //IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%d: key=%d, scancode=%d, mod=%X\n", (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP", event->key.key, event->key.scancode, event->key.mod); ImGui_ImplSDL3_UpdateKeyModifiers((SDL_Keymod)event->key.mod); ImGuiKey key = ImGui_ImplSDL3_KeyEventToImGuiKey(event->key.key, event->key.scancode); @@ -357,6 +367,8 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_WINDOW_MOUSE_ENTER: { + if (event->window.windowID != SDL_GetWindowID(bd->Window)) + return false; bd->MouseWindowID = event->window.windowID; bd->MousePendingLeaveFrame = 0; return true; @@ -367,13 +379,19 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) // FIXME: Unconfirmed whether this is still needed with SDL3. case SDL_EVENT_WINDOW_MOUSE_LEAVE: { + if (event->window.windowID != SDL_GetWindowID(bd->Window)) + return false; bd->MousePendingLeaveFrame = ImGui::GetFrameCount() + 1; return true; } case SDL_EVENT_WINDOW_FOCUS_GAINED: + if (event->window.windowID != SDL_GetWindowID(bd->Window)) + return false; io.AddFocusEvent(true); return true; case SDL_EVENT_WINDOW_FOCUS_LOST: + if (event->window.windowID != SDL_GetWindowID(bd->Window)) + return false; io.AddFocusEvent(false); return true; case SDL_EVENT_GAMEPAD_ADDED: From 1b61d55079a66692207562c4d8d711527954f514 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Aug 2024 13:57:08 +0200 Subject: [PATCH 09/10] Backends: SDL2, SDL3: ignore events of other SDL windows, amends + wrapping into a function as it'll be convenient for multi-viewport check. (#7853) + Misc typo fix. --- backends/imgui_impl_sdl2.cpp | 21 +++++++++++++++------ backends/imgui_impl_sdl3.cpp | 34 +++++++++++++++++++++------------- docs/CHANGELOG.txt | 1 + imgui.h | 2 +- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 2b115f360..9fff2ab56 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) +// 2024-08-19: ImGui_ImplSDL2_ProcessEvent() now ignores events intended for other SDL windows. (#7853) // 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions. // 2024-07-02: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() renaming in main library. // 2024-02-14: Inputs: Handle gamepad disconnection. Added ImGui_ImplSDL2_SetGamepadMode(). @@ -110,6 +111,7 @@ struct ImGui_ImplSDL2_Data { SDL_Window* Window; + Uint32 WindowID; SDL_Renderer* Renderer; Uint64 Time; char* ClipboardTextData; @@ -306,6 +308,12 @@ static void ImGui_ImplSDL2_UpdateKeyModifiers(SDL_Keymod sdl_key_mods) io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & KMOD_GUI) != 0); } +static ImGuiViewport* ImGui_ImplSDL2_GetViewportForWindowID(Uint32 window_id) +{ + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); + return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : NULL; +} + // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. // - 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. @@ -321,7 +329,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) { case SDL_MOUSEMOTION: { - if (event->motion.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->motion.windowID) == NULL) return false; ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); @@ -330,7 +338,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_MOUSEWHEEL: { - if (event->wheel.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->wheel.windowID) == NULL) return false; //IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY); #if SDL_VERSION_ATLEAST(2,0,18) // If this fails to compile on Emscripten: update to latest Emscripten! @@ -350,7 +358,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: { - if (event->button.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->button.windowID) == NULL) return false; int mouse_button = -1; if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; } @@ -367,7 +375,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_TEXTINPUT: { - if (event->text.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->text.windowID) == NULL) return false; io.AddInputCharactersUTF8(event->text.text); return true; @@ -375,7 +383,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) case SDL_KEYDOWN: case SDL_KEYUP: { - if (event->key.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID) == NULL) return false; ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod); ImGuiKey key = ImGui_ImplSDL2_KeyEventToImGuiKey(event->key.keysym.sym, event->key.keysym.scancode); @@ -385,7 +393,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_WINDOWEVENT: { - if (event->window.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->window.windowID) == NULL) return false; // - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER event on every mouse move, but the final ENTER tends to be right. // - However we won't get a correct LEAVE event for a captured window. @@ -445,6 +453,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) bd->Window = window; + bd->WindowID = SDL_GetWindowID(window); bd->Renderer = renderer; bd->MouseCanUseGlobalState = mouse_can_use_global_state; diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index a74a316d2..5a58c9688 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-08-19: ImGui_ImplSDL3_ProcessEvent() now ignores events intended for other SDL windows. (#7853) // 2024-07-22: Update for SDL3 api changes: SDL_GetGamepads() memory ownership change. (#7807) // 2024-07-18: Update for SDL3 api changes: SDL_GetClipboardText() memory ownership change. (#7801) // 2024-07-15: Update for SDL3 api changes: SDL_GetProperty() change to SDL_GetPointerProperty(). (#7794) @@ -80,6 +81,7 @@ struct ImGui_ImplSDL3_Data { SDL_Window* Window; + SDL_WindowID WindowID; SDL_Renderer* Renderer; Uint64 Time; char* ClipboardTextData; @@ -292,6 +294,13 @@ static void ImGui_ImplSDL3_UpdateKeyModifiers(SDL_Keymod sdl_key_mods) io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & SDL_KMOD_GUI) != 0); } + +static ImGuiViewport* ImGui_ImplSDL3_GetViewportForWindowID(SDL_WindowID window_id) +{ + ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); + return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : NULL; +} + // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. // - 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. @@ -307,7 +316,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) { case SDL_EVENT_MOUSE_MOTION: { - if (event->motion.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->motion.windowID) == NULL) return false; ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); @@ -316,7 +325,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_MOUSE_WHEEL: { - if (event->wheel.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->wheel.windowID) == NULL) return false; //IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY); float wheel_x = -event->wheel.x; @@ -331,7 +340,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: { - if (event->button.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->button.windowID) == NULL) return false; int mouse_button = -1; if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; } @@ -348,7 +357,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_TEXT_INPUT: { - if (event->text.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->text.windowID) == NULL) return false; io.AddInputCharactersUTF8(event->text.text); return true; @@ -356,7 +365,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: { - if (event->key.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->key.windowID) == NULL) return false; //IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%d: key=%d, scancode=%d, mod=%X\n", (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP", event->key.key, event->key.scancode, event->key.mod); ImGui_ImplSDL3_UpdateKeyModifiers((SDL_Keymod)event->key.mod); @@ -367,7 +376,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_WINDOW_MOUSE_ENTER: { - if (event->window.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == NULL) return false; bd->MouseWindowID = event->window.windowID; bd->MousePendingLeaveFrame = 0; @@ -379,21 +388,19 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) // FIXME: Unconfirmed whether this is still needed with SDL3. case SDL_EVENT_WINDOW_MOUSE_LEAVE: { - if (event->window.windowID != SDL_GetWindowID(bd->Window)) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == NULL) return false; bd->MousePendingLeaveFrame = ImGui::GetFrameCount() + 1; return true; } case SDL_EVENT_WINDOW_FOCUS_GAINED: - if (event->window.windowID != SDL_GetWindowID(bd->Window)) - return false; - io.AddFocusEvent(true); - return true; case SDL_EVENT_WINDOW_FOCUS_LOST: - if (event->window.windowID != SDL_GetWindowID(bd->Window)) + { + if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == NULL) return false; - io.AddFocusEvent(false); + io.AddFocusEvent(event->type == SDL_EVENT_WINDOW_FOCUS_GAINED); return true; + } case SDL_EVENT_GAMEPAD_ADDED: case SDL_EVENT_GAMEPAD_REMOVED: { @@ -441,6 +448,7 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) bd->Window = window; + bd->WindowID = SDL_GetWindowID(window); bd->Renderer = renderer; bd->MouseCanUseGlobalState = mouse_can_use_global_state; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 386d330c8..e272b19ec 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,7 @@ Other changes: - TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not provide a way to do a portable sleep. (#7844) +- Backends: SDL2, SDL3: ignore events of other SDL windows. (#7853) [@madebr, @ocornut] - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) diff --git a/imgui.h b/imgui.h index 6d4f51388..9080bb1b5 100644 --- a/imgui.h +++ b/imgui.h @@ -3385,7 +3385,7 @@ struct ImFontAtlas struct ImFont { // Members: Hot ~20/24 bytes (for CalcTextSize) - ImVector IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this this info, and are often bottleneck in large UI). + ImVector IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI). float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading) From 2d99052d1d43bd17a72bce0531c605b30aa6bc0b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Aug 2024 14:07:25 +0200 Subject: [PATCH 10/10] Backends: SDL2, SDL3: storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. (#7853) This will be used to support filtering of events with multi-viewports. --- backends/imgui_impl_sdl2.cpp | 3 ++- backends/imgui_impl_sdl3.cpp | 6 ++++-- docs/CHANGELOG.txt | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 9fff2ab56..c4724969d 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) +// 2024-08-19: Storing SDL's Uint32 WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. // 2024-08-19: ImGui_ImplSDL2_ProcessEvent() now ignores events intended for other SDL windows. (#7853) // 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions. // 2024-07-02: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() renaming in main library. @@ -483,7 +484,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void // 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 = (void*)window; + main_viewport->PlatformHandle = (void*)(intptr_t)bd->WindowID; main_viewport->PlatformHandleRaw = nullptr; SDL_SysWMinfo info; SDL_VERSION(&info.version); diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 5a58c9688..24627347b 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-08-19: Storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. // 2024-08-19: ImGui_ImplSDL3_ProcessEvent() now ignores events intended for other SDL windows. (#7853) // 2024-07-22: Update for SDL3 api changes: SDL_GetGamepads() memory ownership change. (#7807) // 2024-07-18: Update for SDL3 api changes: SDL_GetClipboardText() memory ownership change. (#7801) @@ -133,7 +134,8 @@ static void ImGui_ImplSDL3_SetClipboardText(void*, const char* text) static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) { ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); - SDL_Window* window = (SDL_Window*)viewport->PlatformHandle; + SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle; + SDL_Window* window = SDL_GetWindowFromID(window_id); if ((data->WantVisible == false || bd->ImeWindow != window) && bd->ImeWindow != NULL) { SDL_StopTextInput(bd->ImeWindow); @@ -413,7 +415,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) static void ImGui_ImplSDL3_SetupPlatformHandles(ImGuiViewport* viewport, SDL_Window* window) { - viewport->PlatformHandle = window; + viewport->PlatformHandle = (void*)(intptr_t)SDL_GetWindowID(window); viewport->PlatformHandleRaw = nullptr; #if defined(_WIN32) && !defined(__WINRT__) viewport->PlatformHandleRaw = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e272b19ec..24f6c640c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -51,6 +51,7 @@ Other changes: - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not provide a way to do a portable sleep. (#7844) - Backends: SDL2, SDL3: ignore events of other SDL windows. (#7853) [@madebr, @ocornut] +- Backends: SDL2, SDL3: storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop to handle minimization without burning CPU or GPU by running unthrottled code. (#7844)