From c11128891ef1ae58ca6225ada94aee04c6505b98 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 21 Apr 2023 15:40:14 +0200 Subject: [PATCH] Backends: SDL2/SDL3: Update monitor list when receiving a display event. (#6348) --- backends/imgui_impl_sdl2.cpp | 23 +++++++++++++++++++---- backends/imgui_impl_sdl3.cpp | 21 +++++++++++++++++---- docs/CHANGELOG.txt | 4 ++++ 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index e58e0386c..fca4080d8 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -103,6 +103,7 @@ #define SDL_HAS_USABLE_DISPLAY_BOUNDS SDL_VERSION_ATLEAST(2,0,5) #define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4) #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) +#define SDL_HAS_DISPLAY_EVENT SDL_VERSION_ATLEAST(2,0,9) #if !SDL_HAS_VULKAN static const Uint32 SDL_WINDOW_VULKAN = 0x10000000; #endif @@ -122,6 +123,7 @@ struct ImGui_ImplSDL2_Data bool MouseCanUseGlobalState; bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state. bool UseVulkan; + bool WantUpdateMonitors; ImGui_ImplSDL2_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -364,6 +366,15 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) io.SetKeyEventNativeData(key, event->key.keysym.sym, event->key.keysym.scancode, event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions. return true; } +#if SDL_HAS_DISPLAY_EVENT + case SDL_DISPLAYEVENT: + { + // 2.0.26 has SDL_DISPLAYEVENT_CONNECTED/SDL_DISPLAYEVENT_DISCONNECTED/SDL_DISPLAYEVENT_ORIENTATION, + // so change of DPI/Scaling are not reflected in this event. (SDL3 has it) + bd->WantUpdateMonitors = true; + return true; + } +#endif case SDL_WINDOWEVENT: { // - 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. @@ -436,6 +447,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void #else bd->MouseCanReportHoveredViewport = false; #endif + bd->WantUpdateMonitors = true; io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText; @@ -490,9 +502,6 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0"); #endif - // Update monitors - ImGui_ImplSDL2_UpdateMonitors(); - // We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports. // We left the call to ImGui_ImplSDL2_InitPlatformInterface() outside of #ifdef to avoid unused-function warnings. if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) && (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports)) @@ -692,11 +701,13 @@ static void ImGui_ImplSDL2_UpdateGamepads() #undef MAP_ANALOG } -// FIXME-PLATFORM: SDL doesn't have an event to notify the application of display/monitor changes +// FIXME: Note that doesn't update with DPI/Scaling change only as SDL2 doesn't have an event for it (SDL3 has). static void ImGui_ImplSDL2_UpdateMonitors() { + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Monitors.resize(0); + bd->WantUpdateMonitors = false; int display_count = SDL_GetNumVideoDisplays(); for (int n = 0; n < display_count; n++) { @@ -743,6 +754,10 @@ void ImGui_ImplSDL2_NewFrame() if (w > 0 && h > 0) io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); + // Update monitors + if (bd->WantUpdateMonitors) + ImGui_ImplSDL2_UpdateMonitors(); + // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution) // (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644) static Uint64 frequency = SDL_GetPerformanceFrequency(); diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index c57eb0986..b5b59743c 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -64,6 +64,7 @@ struct ImGui_ImplSDL3_Data bool MouseCanUseGlobalState; bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state. bool UseVulkan; + bool WantUpdateMonitors; ImGui_ImplSDL3_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -300,6 +301,15 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) io.SetKeyEventNativeData(key, event->key.keysym.sym, event->key.keysym.scancode, event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions. return true; } + case SDL_EVENT_DISPLAY_ORIENTATION: + case SDL_EVENT_DISPLAY_CONNECTED: + case SDL_EVENT_DISPLAY_DISCONNECTED: + case SDL_EVENT_DISPLAY_MOVED: + case SDL_EVENT_DISPLAY_SCALE_CHANGED: + { + bd->WantUpdateMonitors = true; + return true; + } case SDL_EVENT_WINDOW_MOUSE_ENTER: { bd->MouseWindowID = event->window.windowID; @@ -375,6 +385,7 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void #else bd->MouseCanReportHoveredViewport = false; #endif + bd->WantUpdateMonitors = true; io.SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText; @@ -420,9 +431,6 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void // SDL 3.x : see https://github.com/libsdl-org/SDL/issues/6659 SDL_SetHint("SDL_BORDERLESS_WINDOWED_STYLE", "0"); - // Update monitors - ImGui_ImplSDL3_UpdateMonitors(); - // We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports. // We left the call to ImGui_ImplSDL3_InitPlatformInterface() outside of #ifdef to avoid unused-function warnings. if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) && (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports)) @@ -619,11 +627,12 @@ static void ImGui_ImplSDL3_UpdateGamepads() #undef MAP_ANALOG } -// FIXME-PLATFORM: SDL doesn't have an event to notify the application of display/monitor changes static void ImGui_ImplSDL3_UpdateMonitors() { + ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Monitors.resize(0); + bd->WantUpdateMonitors = false; int display_count; SDL_DisplayID* displays = SDL_GetDisplays(&display_count); @@ -665,6 +674,10 @@ void ImGui_ImplSDL3_NewFrame() if (w > 0 && h > 0) io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); + // Update monitors + if (bd->WantUpdateMonitors) + ImGui_ImplSDL3_UpdateMonitors(); + // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution) // (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644) static Uint64 frequency = SDL_GetPerformanceFrequency(); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 002bb5b7b..08f050dc3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -126,6 +126,10 @@ Docking+Viewports Branch: - Viewports: added void* ImGuiPlatformMonitor::PlatformHandle field (backend-dependant), for usage by user code. +- Backends: SDL2: Update monitor list when receiving a display event. (#6348) + Note however that SDL2 currently doesn't have an event for a DPI/Scaling change, + so monitor data won't be updated in this situation. +- Backends: SDL3: Update monitor list when receiving a display event. (#6348) -----------------------------------------------------------------------