diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index 796b0904..2b470acd 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -310,6 +310,24 @@ struct ImGuiPlatformDataGlfw ~ImGuiPlatformDataGlfw() { IM_ASSERT(Window == NULL); } }; +static void ImGui_ImplGlfw_WindowCloseCallback(GLFWwindow* window) +{ + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window)) + viewport->PlatformRequestClose = true; +} + +static void ImGui_ImplGlfw_WindowPosCallback(GLFWwindow* window, int, int) +{ + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window)) + viewport->PlatformRequestMove = true; +} + +static void ImGui_ImplGlfw_WindowSizeCallback(GLFWwindow* window, int, int) +{ + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window)) + viewport->PlatformRequestResize = true; +} + static void ImGui_ImplGlfw_CreateViewport(ImGuiViewport* viewport) { ImGuiPlatformDataGlfw* data = IM_NEW(ImGuiPlatformDataGlfw)(); @@ -324,6 +342,9 @@ static void ImGui_ImplGlfw_CreateViewport(ImGuiViewport* viewport) data->WindowOwned = true; viewport->PlatformHandle = (void*)data->Window; ImGui_ImplGlfw_InstallCallbacks(data->Window); + glfwSetWindowCloseCallback(data->Window, ImGui_ImplGlfw_WindowCloseCallback); + glfwSetWindowPosCallback(data->Window, ImGui_ImplGlfw_WindowPosCallback); + glfwSetWindowSizeCallback(data->Window, ImGui_ImplGlfw_WindowSizeCallback); } static void ImGui_ImplGlfw_DestroyViewport(ImGuiViewport* viewport) @@ -431,9 +452,6 @@ static void ImGui_ImplGlfw_RenderViewport(ImGuiViewport* viewport) ImGuiPlatformDataGlfw* data = (ImGuiPlatformDataGlfw*)viewport->PlatformUserData; if (g_ClientApi == GlfwClientApi_OpenGL) glfwMakeContextCurrent(data->Window); - - if (glfwWindowShouldClose(data->Window)) - viewport->PlatformRequestClose = true; } static void ImGui_ImplGlfw_SwapBuffers(ImGuiViewport* viewport) diff --git a/examples/imgui_impl_sdl2.cpp b/examples/imgui_impl_sdl2.cpp index 233bb021..496f2da2 100644 --- a/examples/imgui_impl_sdl2.cpp +++ b/examples/imgui_impl_sdl2.cpp @@ -100,6 +100,21 @@ bool ImGui_ImplSDL2_ProcessEvent(SDL_Event* event) io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0); return true; } + // Multi-viewport support + case SDL_WINDOWEVENT: + Uint8 window_event = event->window.event; + if (window_event == SDL_WINDOWEVENT_CLOSE || window_event == SDL_WINDOWEVENT_MOVED || window_event == SDL_WINDOWEVENT_RESIZED) + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)SDL_GetWindowFromID(event->window.windowID))) + { + if (window_event == SDL_WINDOWEVENT_CLOSE) + viewport->PlatformRequestClose = true; + if (window_event == SDL_WINDOWEVENT_MOVED) + viewport->PlatformRequestMove = true; + if (window_event == SDL_WINDOWEVENT_RESIZED) + viewport->PlatformRequestResize = true; + return true; + } + break; } return false; } @@ -288,7 +303,8 @@ static void ImGui_ImplSDL2_CreateViewport(ImGuiViewport* viewport) sdl_flags |= SDL_WINDOW_HIDDEN; sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0; sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE; - data->Window = SDL_CreateWindow("No Title Yet", 0, 0, (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags); + data->Window = SDL_CreateWindow("No Title Yet", + (int)viewport->PlatformOsDesktopPos.x, (int)viewport->PlatformOsDesktopPos.y, (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags); if (main_viewport_data->GLContext) data->GLContext = SDL_GL_CreateContext(data->Window); viewport->PlatformHandle = (void*)data->Window; @@ -328,7 +344,7 @@ static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport) ex_style &= ~WS_EX_APPWINDOW; ex_style |= WS_EX_TOOLWINDOW; ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style); - } + } // SDL hack: SDL always activate/focus windows :/ if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) @@ -336,7 +352,7 @@ static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport) ::ShowWindow(hwnd, SW_SHOWNA); return; } -} + } #endif SDL_ShowWindow(data->Window); diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp index c8283a18..e817ea1f 100644 --- a/examples/imgui_impl_vulkan.cpp +++ b/examples/imgui_impl_vulkan.cpp @@ -1108,8 +1108,9 @@ static void ImGui_ImplVulkan_DestroyViewport(ImGuiViewport* viewport) static void ImGui_ImplVulkan_ResizeViewport(ImGuiViewport* viewport, ImVec2 size) { ImGuiPlatformDataVulkan* data = (ImGuiPlatformDataVulkan*)viewport->RendererUserData; - ImGui_ImplVulkan_WindowData* wd = &data->WindowData; - ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, (int)size.x, (int)size.y); + if (data == NULL) // This is NULL for the main viewport (which is left to the user/app to handle) + return; + ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &data->WindowData, g_Allocator, (int)size.x, (int)size.y); } static void ImGui_ImplVulkan_RenderViewport(ImGuiViewport* viewport) diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index f8c40355..7361e9af 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -356,11 +356,10 @@ float ImGui_ImplWin32_GetDpiScaleForRect(int x1, int y1, int x2, int y2) struct ImGuiPlatformDataWin32 { HWND Hwnd; - bool ExternalResize; DWORD DwStyle; DWORD DwExStyle; - ImGuiPlatformDataWin32() { Hwnd = NULL; ExternalResize = false; DwStyle = DwExStyle = 0; } + ImGuiPlatformDataWin32() { Hwnd = NULL; DwStyle = DwExStyle = 0; } ~ImGuiPlatformDataWin32() { IM_ASSERT(Hwnd == NULL); } }; @@ -386,12 +385,11 @@ static void ImGui_ImplWin32_CreateViewport(ImGuiViewport* viewport) // Create window RECT rect = { (LONG)viewport->PlatformOsDesktopPos.x, (LONG)viewport->PlatformOsDesktopPos.y, (LONG)(viewport->PlatformOsDesktopPos.x + viewport->Size.x), (LONG)(viewport->PlatformOsDesktopPos.y + viewport->Size.y) }; ::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle); - data->ExternalResize = true; data->Hwnd = ::CreateWindowExA( data->DwExStyle, "ImGui Platform", "No Title Yet", data->DwStyle, // Style, class name, window name rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area g_hWnd, NULL, ::GetModuleHandle(NULL), NULL); // Parent window, Menu, Instance, Param - data->ExternalResize = false; + viewport->PlatformRequestResize = false; viewport->PlatformHandle = data->Hwnd; } @@ -417,12 +415,10 @@ static void ImGui_ImplWin32_ShowWindow(ImGuiViewport* viewport) { ImGuiPlatformDataWin32* data = (ImGuiPlatformDataWin32*)viewport->PlatformUserData; IM_ASSERT(data->Hwnd != 0); - data->ExternalResize = true; if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) ::ShowWindow(data->Hwnd, SW_SHOWNA); else ::ShowWindow(data->Hwnd, SW_SHOW); - data->ExternalResize = false; } static ImVec2 ImGui_ImplWin32_GetWindowPos(ImGuiViewport* viewport) @@ -456,11 +452,9 @@ static void ImGui_ImplWin32_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) { ImGuiPlatformDataWin32* data = (ImGuiPlatformDataWin32*)viewport->PlatformUserData; IM_ASSERT(data->Hwnd != 0); - data->ExternalResize = true; RECT rect = { 0, 0, (LONG)size.x, (LONG)size.y }; ::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle); // Client to Screen ::SetWindowPos(data->Hwnd, NULL, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); - data->ExternalResize = false; } static void ImGui_ImplWin32_SetWindowTitle(ImGuiViewport* viewport, const char* title) @@ -489,27 +483,22 @@ static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hWnd)) { - ImGuiIO& io = ImGui::GetIO(); - ImGuiPlatformDataWin32* data = (ImGuiPlatformDataWin32*)viewport->PlatformUserData; switch (msg) { case WM_CLOSE: viewport->PlatformRequestClose = true; return 0; case WM_MOVE: - viewport->PlatformOsDesktopPos = ImVec2((float)(short)LOWORD(lParam), (float)(short)HIWORD(lParam)); + viewport->PlatformRequestMove = true; + break; + case WM_SIZE: + viewport->PlatformRequestResize = true; break; case WM_NCHITTEST: // Let mouse pass-through the window, this is used while e.g. dragging a window, we creates a temporary overlay but want the cursor to aim behind our overlay. if (viewport->Flags & ImGuiViewportFlags_NoInputs) return HTTRANSPARENT; break; - case WM_SIZE: - if (!data->ExternalResize) - viewport->PlatformRequestResize = true; - if (io.RendererInterface.ResizeViewport) - io.RendererInterface.ResizeViewport(viewport, ImVec2((float)LOWORD(lParam), (float)HIWORD(lParam))); - break; } } diff --git a/imgui.cpp b/imgui.cpp index e818f38e..001a86c6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3384,6 +3384,12 @@ static void ImGui::UpdateViewports() ResizeViewportTranslateWindows(viewport->Idx + 1, g.Viewports.Size, dx, 0, NULL); } + // Apply Platform Size to ImGui Size if requested + // We do it here instead of UpdatePlatformWindows() to allow the platform back-end to set PlatformRequestResize early + // (e.g. in their own message handler before NewFrame) and not have a frame of lag with it. + if (viewport->PlatformRequestResize) + viewport->Size = g.IO.PlatformInterface.GetWindowSize(viewport); + // Update DPI Scale float new_dpi_scale; if (g.IO.PlatformInterface.GetWindowDpiScale) @@ -3478,17 +3484,31 @@ static void UpdatePlatformWindows() if ((viewport->Flags & ImGuiViewportFlags_MainViewport) || (viewport->LastFrameActive < g.FrameCount)) continue; IM_ASSERT(viewport->Window != NULL); - viewport->PlatformRequestClose = false; - // FIXME-PLATFORM + if (viewport->PlatformRequestMove) + viewport->PlatformOsDesktopPos = g.IO.PlatformInterface.GetWindowPos(viewport); + bool is_new_window = viewport->PlatformHandle == NULL && viewport->PlatformUserData == NULL && viewport->RendererUserData == NULL; if (is_new_window && viewport->PlatformHandle == NULL && viewport->PlatformUserData == NULL) + { g.IO.PlatformInterface.CreateViewport(viewport); + } if (is_new_window && viewport->RendererUserData == NULL && g.IO.RendererInterface.CreateViewport != NULL) + { g.IO.RendererInterface.CreateViewport(viewport); + viewport->RendererLastSize = viewport->Size; + } - g.IO.PlatformInterface.SetWindowPos(viewport, viewport->PlatformOsDesktopPos); - g.IO.PlatformInterface.SetWindowSize(viewport, viewport->Size); + // Update Pos/Size for Platform + if (!viewport->PlatformRequestMove) + g.IO.PlatformInterface.SetWindowPos(viewport, viewport->PlatformOsDesktopPos); + if (!viewport->PlatformRequestResize) + g.IO.PlatformInterface.SetWindowSize(viewport, viewport->Size); + + // Update Size for Renderer + if (g.IO.RendererInterface.ResizeViewport && (viewport->RendererLastSize.x != viewport->Size.x || viewport->RendererLastSize.y != viewport->Size.y)) + g.IO.RendererInterface.ResizeViewport(viewport, viewport->Size); + viewport->RendererLastSize = viewport->Size; // Update title bar const char* title_begin = viewport->Window->Name; @@ -3503,13 +3523,18 @@ static void UpdatePlatformWindows() ImGui::MemFree(title_displayed); } + // Show window. On startup ensure platform window don't get focus. if (is_new_window) { - // On startup ensure platform window don't get focus. if (g.FrameCount < 2) viewport->Flags |= ImGuiViewportFlags_NoFocusOnAppearing; g.IO.PlatformInterface.ShowWindow(viewport); } + + // Clear request flags + viewport->PlatformRequestClose = false; + viewport->PlatformRequestMove = false; + viewport->PlatformRequestResize = false; } } @@ -6013,10 +6038,11 @@ static void ImGui::UpdateWindowViewport(ImGuiWindow* window, bool window_pos_set window->Viewport = main_viewport; // When we own the viewport update its size - if (window->ID == window->Viewport->ID && !created_viewport) + if (window == window->Viewport->Window && !created_viewport) { window->Viewport->Flags |= ImGuiViewportFlags_NoDecoration; - window->Viewport->Size = window->Size; + if (!window->Viewport->PlatformRequestResize) + window->Viewport->Size = window->Size; window->Viewport->PlatformOsDesktopPos = ConvertViewportPosToOsDesktopPos(window->Pos, window->Viewport); window->Flags |= ImGuiWindowFlags_FullViewport; } @@ -6026,7 +6052,11 @@ static void ImGui::UpdateWindowViewport(ImGuiWindow* window, bool window_pos_set window->Flags |= ImGuiWindowFlags_NoTitleBar; if (window->Flags & ImGuiWindowFlags_FullViewport) + { SetWindowPos(window, window->Viewport->Pos, ImGuiCond_Always); + if (window->Viewport->PlatformRequestResize) + SetWindowSize(window, window->Viewport->Size, ImGuiCond_Always); + } window->ViewportId = window->Viewport->ID; } diff --git a/imgui_internal.h b/imgui_internal.h index 123c42b2..1d49b913 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -535,10 +535,12 @@ struct ImGuiViewport void* PlatformUserData; // void* to hold custom data structure for the platform (e.g. windowing info, render context) void* PlatformHandle; // void* for FindViewportByPlatformHandle(). (e.g. HWND, GlfwWindow*) bool PlatformRequestClose; // Platform window requested closure - bool PlatformRequestResize; // Platform window requested resize + bool PlatformRequestMove; // Platform window requested move (e.g. window was moved using OS windowing facility) + bool PlatformRequestResize; // Platform window requested resize (e.g. window was resize using OS windowing facility) void* RendererUserData; // void* to hold custom data structure for the renderer (e.g. framebuffer) + ImVec2 RendererLastSize; - ImGuiViewport(ImGuiID id, int idx) { ID = id; Idx = idx; Flags = 0; LastFrameActive = LastFrameAsRefViewport = -1; LastNameHash = 0; Window = NULL; DpiScale = 0.0f; PlatformUserData = PlatformHandle = NULL; PlatformRequestClose = PlatformRequestResize = false; RendererUserData = NULL; } + ImGuiViewport(ImGuiID id, int idx) { ID = id; Idx = idx; Flags = 0; LastFrameActive = LastFrameAsRefViewport = -1; LastNameHash = 0; Window = NULL; DpiScale = 0.0f; PlatformUserData = PlatformHandle = NULL; PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; RendererUserData = NULL; RendererLastSize = ImVec2(-1.0f,-1.0f); } ~ImGuiViewport() { IM_ASSERT(PlatformUserData == NULL && RendererUserData == NULL); } ImRect GetRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } float GetNextX() const { const float SPACING = 4.0f; return Pos.x + Size.x + SPACING; }