ImGui-dockingと交換

守矢諏訪子 <suwako@076.moe>、2026-06-26 04:33
コミット d917edd61860e582f371aedd95c8d5d01b98e3eb ・親 8ac5aaf ・ファイルを見る

104個のファイル、+7663 -849

@@ -11,6 +11,7 @@
1111 // [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
1212 // [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: Allegro5 cannot enable/disable LINEAR bitmap flags after creation.
1313 // [ ] Platform: Missing gamepad support.
14+// [ ] Renderer: Multi-viewport support (multiple windows).
1415
1516 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1617 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -11,6 +11,7 @@
1111 // [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
1212 // [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: Allegro5 cannot enable/disable LINEAR bitmap flags after creation.
1313 // [ ] Platform: Missing gamepad support.
14+// [ ] Renderer: Multi-viewport support (multiple windows).
1415
1516 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1617 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -8,6 +8,7 @@
88 // [ ] Platform: Clipboard support.
99 // [ ] Platform: Gamepad support.
1010 // [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
11+// [ ] Platform: Multi-viewport support (multiple windows). Not meaningful on Android.
1112 // Important:
1213 // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
1314 // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
@@ -8,6 +8,7 @@
88 // [ ] Platform: Clipboard support.
99 // [ ] Platform: Gamepad support.
1010 // [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
11+// [ ] Platform: Multi-viewport support (multiple windows). Not meaningful on Android.
1112 // Important:
1213 // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
1314 // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
@@ -5,6 +5,7 @@
55 // [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
66 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
77 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
8+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
89
910 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1011 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -16,6 +17,7 @@
1617
1718 // CHANGELOG
1819 // (minor and older changes stripped away, please see git history for details)
20+// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
1921 // 2026-04-23: DirectX10: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplDX10_RenderState. (#9378)
2022 // 2026-01-19: DirectX10: Added 'SamplerNearest' in ImGui_ImplDX10_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'.
2123 // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
@@ -99,6 +101,10 @@
99101 return ImGui::GetCurrentContext() ? (ImGui_ImplDX10_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
100102 }
101103
104+// Forward Declarations
105+static void ImGui_ImplDX10_InitMultiViewportSupport();
106+static void ImGui_ImplDX10_ShutdownMultiViewportSupport();
107+
102108 // Functions
103109 static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* device)
104110 {
@@ -613,6 +619,7 @@
613619 io.BackendRendererName = "imgui_impl_dx10";
614620 io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
615621 io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
622+ io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
616623
617624 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
618625 platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
@@ -635,6 +642,8 @@
635642 if (pDXGIAdapter) pDXGIAdapter->Release();
636643 bd->pd3dDevice->AddRef();
637644
645+ ImGui_ImplDX10_InitMultiViewportSupport();
646+
638647 return true;
639648 }
640649
@@ -645,13 +654,14 @@
645654 ImGuiIO& io = ImGui::GetIO();
646655 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
647656
657+ ImGui_ImplDX10_ShutdownMultiViewportSupport();
648658 ImGui_ImplDX10_InvalidateDeviceObjects();
649659 if (bd->pFactory) { bd->pFactory->Release(); }
650660 if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
651661
652662 io.BackendRendererName = nullptr;
653663 io.BackendRendererUserData = nullptr;
654- io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
664+ io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
655665 platform_io.ClearRendererHandlers();
656666 IM_DELETE(bd);
657667 }
@@ -664,6 +674,131 @@
664674 if (!bd->pVertexShader)
665675 if (!ImGui_ImplDX10_CreateDeviceObjects())
666676 IM_ASSERT(0 && "ImGui_ImplDX10_CreateDeviceObjects() failed!");
677+}
678+
679+//--------------------------------------------------------------------------------------------------------
680+// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
681+// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
682+// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
683+//--------------------------------------------------------------------------------------------------------
684+
685+// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
686+struct ImGui_ImplDX10_ViewportData
687+{
688+ IDXGISwapChain* SwapChain;
689+ ID3D10RenderTargetView* RTView;
690+
691+ ImGui_ImplDX10_ViewportData() { SwapChain = nullptr; RTView = nullptr; }
692+ ~ImGui_ImplDX10_ViewportData() { IM_ASSERT(SwapChain == nullptr && RTView == nullptr); }
693+};
694+
695+static void ImGui_ImplDX10_CreateWindow(ImGuiViewport* viewport)
696+{
697+ ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
698+ ImGui_ImplDX10_ViewportData* vd = IM_NEW(ImGui_ImplDX10_ViewportData)();
699+ viewport->RendererUserData = vd;
700+
701+ // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID).
702+ // Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND.
703+ HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
704+ IM_ASSERT(hwnd != 0);
705+
706+ // Create swap chain
707+ DXGI_SWAP_CHAIN_DESC sd;
708+ ZeroMemory(&sd, sizeof(sd));
709+ sd.BufferDesc.Width = (UINT)viewport->Size.x;
710+ sd.BufferDesc.Height = (UINT)viewport->Size.y;
711+ sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
712+ sd.SampleDesc.Count = 1;
713+ sd.SampleDesc.Quality = 0;
714+ sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
715+ sd.BufferCount = 1;
716+ sd.OutputWindow = hwnd;
717+ sd.Windowed = TRUE;
718+ sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
719+ sd.Flags = 0;
720+
721+ IM_ASSERT(vd->SwapChain == nullptr && vd->RTView == nullptr);
722+ bd->pFactory->CreateSwapChain(bd->pd3dDevice, &sd, &vd->SwapChain);
723+ bd->pFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES); // Disable e.g. Alt+Enter
724+
725+ // Create the render target
726+ if (vd->SwapChain)
727+ {
728+ ID3D10Texture2D* pBackBuffer;
729+ vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
730+ bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView);
731+ pBackBuffer->Release();
732+ }
733+}
734+
735+static void ImGui_ImplDX10_DestroyWindow(ImGuiViewport* viewport)
736+{
737+ // The main viewport (owned by the application) will always have RendererUserData == 0 here since we didn't create the data for it.
738+ if (ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData)
739+ {
740+ if (vd->SwapChain)
741+ vd->SwapChain->Release();
742+ vd->SwapChain = nullptr;
743+ if (vd->RTView)
744+ vd->RTView->Release();
745+ vd->RTView = nullptr;
746+ IM_DELETE(vd);
747+ }
748+ viewport->RendererUserData = nullptr;
749+}
750+
751+static void ImGui_ImplDX10_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
752+{
753+ ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
754+ ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData;
755+ if (vd->RTView)
756+ {
757+ vd->RTView->Release();
758+ vd->RTView = nullptr;
759+ }
760+ if (vd->SwapChain)
761+ {
762+ ID3D10Texture2D* pBackBuffer = nullptr;
763+ vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
764+ vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
765+ if (pBackBuffer == nullptr) { fprintf(stderr, "ImGui_ImplDX10_SetWindowSize() failed creating buffers.\n"); return; }
766+ bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView);
767+ pBackBuffer->Release();
768+ }
769+}
770+
771+static void ImGui_ImplDX10_RenderViewport(ImGuiViewport* viewport, void*)
772+{
773+ ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
774+ ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData;
775+ ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
776+ bd->pd3dDevice->OMSetRenderTargets(1, &vd->RTView, nullptr);
777+ if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
778+ bd->pd3dDevice->ClearRenderTargetView(vd->RTView, (float*)&clear_color);
779+ ImGui_ImplDX10_RenderDrawData(viewport->DrawData);
780+}
781+
782+static void ImGui_ImplDX10_SwapBuffers(ImGuiViewport* viewport, void*)
783+{
784+ ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData;
785+ if (vd->SwapChain)
786+ vd->SwapChain->Present(0, 0); // Present without vsync
787+}
788+
789+void ImGui_ImplDX10_InitMultiViewportSupport()
790+{
791+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
792+ platform_io.Renderer_CreateWindow = ImGui_ImplDX10_CreateWindow;
793+ platform_io.Renderer_DestroyWindow = ImGui_ImplDX10_DestroyWindow;
794+ platform_io.Renderer_SetWindowSize = ImGui_ImplDX10_SetWindowSize;
795+ platform_io.Renderer_RenderWindow = ImGui_ImplDX10_RenderViewport;
796+ platform_io.Renderer_SwapBuffers = ImGui_ImplDX10_SwapBuffers;
797+}
798+
799+void ImGui_ImplDX10_ShutdownMultiViewportSupport()
800+{
801+ ImGui::DestroyPlatformWindows();
667802 }
668803
669804 //-----------------------------------------------------------------------------
@@ -5,6 +5,7 @@
55 // [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
66 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
77 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
8+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
89
910 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1011 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -6,6 +6,7 @@
66 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
77 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
88 // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
9+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
910
1011 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1112 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -17,11 +18,13 @@
1718
1819 // CHANGELOG
1920 // (minor and older changes stripped away, please see git history for details)
21+// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
2022 // 2026-04-23: DirectX11: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplDX11_RenderState. (#9378)
2123 // 2026-01-19: DirectX11: Added 'SamplerNearest' in ImGui_ImplDX11_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'.
2224 // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
2325 // 2025-06-11: DirectX11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
2426 // 2025-05-07: DirectX11: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows).
27+// 2025-02-24: [Docking] Added undocumented ImGui_ImplDX11_SetSwapChainDescs() to configure swap chain creation for secondary viewports.
2528 // 2025-01-06: DirectX11: Expose VertexConstantBuffer in ImGui_ImplDX11_RenderState. Reset projection matrix in ImDrawCallback_ResetRenderState handler.
2629 // 2024-10-07: DirectX11: Changed default texture sampler to Clamp instead of Repeat/Wrap.
2730 // 2024-10-07: DirectX11: Expose selected render state in ImGui_ImplDX11_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks.
@@ -87,6 +90,7 @@
8790 int VertexBufferSize;
8891 int IndexBufferSize;
8992 ImGui_ImplDX11_RenderState* RenderState; // == (ImGui_ImplDX11_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState during rendering.
93+ ImVector<DXGI_SWAP_CHAIN_DESC> SwapChainDescsForViewports;
9094
9195 ImGui_ImplDX11_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
9296 };
@@ -103,6 +107,10 @@
103107 return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
104108 }
105109
110+// Forward Declarations
111+static void ImGui_ImplDX11_InitMultiViewportSupport();
112+static void ImGui_ImplDX11_ShutdownMultiViewportSupport();
113+
106114 // Functions
107115 static void ImGui_ImplDX11_SetupRenderState(const ImDrawData* draw_data, ID3D11DeviceContext* device_ctx)
108116 {
@@ -630,6 +638,7 @@
630638 io.BackendRendererName = "imgui_impl_dx11";
631639 io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
632640 io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
641+ io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
633642
634643 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
635644 platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
@@ -655,6 +664,8 @@
655664 bd->pd3dDevice->AddRef();
656665 bd->pd3dDeviceContext->AddRef();
657666
667+ ImGui_ImplDX11_InitMultiViewportSupport();
668+
658669 return true;
659670 }
660671
@@ -665,6 +676,7 @@
665676 ImGuiIO& io = ImGui::GetIO();
666677 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
667678
679+ ImGui_ImplDX11_ShutdownMultiViewportSupport();
668680 ImGui_ImplDX11_InvalidateDeviceObjects();
669681 if (bd->pFactory) { bd->pFactory->Release(); }
670682 if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
@@ -672,7 +684,7 @@
672684
673685 io.BackendRendererName = nullptr;
674686 io.BackendRendererUserData = nullptr;
675- io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
687+ io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
676688 platform_io.ClearRendererHandlers();
677689 IM_DELETE(bd);
678690 }
@@ -685,6 +697,152 @@
685697 if (!bd->pVertexShader)
686698 if (!ImGui_ImplDX11_CreateDeviceObjects())
687699 IM_ASSERT(0 && "ImGui_ImplDX11_CreateDeviceObjects() failed!");
700+}
701+
702+//--------------------------------------------------------------------------------------------------------
703+// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
704+// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
705+// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
706+//--------------------------------------------------------------------------------------------------------
707+
708+// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
709+struct ImGui_ImplDX11_ViewportData
710+{
711+ IDXGISwapChain* SwapChain;
712+ ID3D11RenderTargetView* RTView;
713+
714+ ImGui_ImplDX11_ViewportData() { SwapChain = nullptr; RTView = nullptr; }
715+ ~ImGui_ImplDX11_ViewportData() { IM_ASSERT(SwapChain == nullptr && RTView == nullptr); }
716+};
717+
718+// Multi-Viewports: configure templates used when creating swapchains for secondary viewports. Will try them in order.
719+// This is intentionally not declared in the .h file yet, so you will need to copy this declaration:
720+void ImGui_ImplDX11_SetSwapChainDescs(const DXGI_SWAP_CHAIN_DESC* desc_templates, int desc_templates_count);
721+void ImGui_ImplDX11_SetSwapChainDescs(const DXGI_SWAP_CHAIN_DESC* desc_templates, int desc_templates_count)
722+{
723+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
724+ bd->SwapChainDescsForViewports.resize(desc_templates_count);
725+ memcpy(bd->SwapChainDescsForViewports.Data, desc_templates, sizeof(DXGI_SWAP_CHAIN_DESC));
726+}
727+
728+static void ImGui_ImplDX11_CreateWindow(ImGuiViewport* viewport)
729+{
730+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
731+ ImGui_ImplDX11_ViewportData* vd = IM_NEW(ImGui_ImplDX11_ViewportData)();
732+ viewport->RendererUserData = vd;
733+
734+ // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID).
735+ // Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND.
736+ HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
737+ IM_ASSERT(hwnd != 0);
738+ IM_ASSERT(vd->SwapChain == nullptr && vd->RTView == nullptr);
739+
740+ // Create swap chain
741+ HRESULT hr = DXGI_ERROR_UNSUPPORTED;
742+ for (const DXGI_SWAP_CHAIN_DESC& sd_template : bd->SwapChainDescsForViewports)
743+ {
744+ IM_ASSERT(sd_template.BufferDesc.Width == 0 && sd_template.BufferDesc.Height == 0 && sd_template.OutputWindow == nullptr);
745+ DXGI_SWAP_CHAIN_DESC sd = sd_template;
746+ sd.BufferDesc.Width = (UINT)viewport->Size.x;
747+ sd.BufferDesc.Height = (UINT)viewport->Size.y;
748+ sd.OutputWindow = hwnd;
749+ hr = bd->pFactory->CreateSwapChain(bd->pd3dDevice, &sd, &vd->SwapChain);
750+ if (SUCCEEDED(hr))
751+ break;
752+ }
753+ IM_ASSERT(SUCCEEDED(hr));
754+ bd->pFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES); // Disable e.g. Alt+Enter
755+
756+ // Create the render target
757+ if (vd->SwapChain != nullptr)
758+ {
759+ ID3D11Texture2D* pBackBuffer;
760+ vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
761+ bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView);
762+ pBackBuffer->Release();
763+ }
764+}
765+
766+static void ImGui_ImplDX11_DestroyWindow(ImGuiViewport* viewport)
767+{
768+ // The main viewport (owned by the application) will always have RendererUserData == nullptr since we didn't create the data for it.
769+ if (ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData)
770+ {
771+ if (vd->SwapChain)
772+ vd->SwapChain->Release();
773+ vd->SwapChain = nullptr;
774+ if (vd->RTView)
775+ vd->RTView->Release();
776+ vd->RTView = nullptr;
777+ IM_DELETE(vd);
778+ }
779+ viewport->RendererUserData = nullptr;
780+}
781+
782+static void ImGui_ImplDX11_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
783+{
784+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
785+ ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData;
786+ if (vd->RTView)
787+ {
788+ vd->RTView->Release();
789+ vd->RTView = nullptr;
790+ }
791+ if (vd->SwapChain)
792+ {
793+ ID3D11Texture2D* pBackBuffer = nullptr;
794+ vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
795+ vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
796+ if (pBackBuffer == nullptr) { fprintf(stderr, "ImGui_ImplDX11_SetWindowSize() failed creating buffers.\n"); return; }
797+ bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView);
798+ pBackBuffer->Release();
799+ }
800+}
801+
802+static void ImGui_ImplDX11_RenderWindow(ImGuiViewport* viewport, void*)
803+{
804+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
805+ ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData;
806+ ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
807+ bd->pd3dDeviceContext->OMSetRenderTargets(1, &vd->RTView, nullptr);
808+ if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
809+ bd->pd3dDeviceContext->ClearRenderTargetView(vd->RTView, (float*)&clear_color);
810+ ImGui_ImplDX11_RenderDrawData(viewport->DrawData);
811+}
812+
813+static void ImGui_ImplDX11_SwapBuffers(ImGuiViewport* viewport, void*)
814+{
815+ ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData;
816+ if (vd->SwapChain)
817+ vd->SwapChain->Present(0, 0); // Present without vsync
818+}
819+
820+static void ImGui_ImplDX11_InitMultiViewportSupport()
821+{
822+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
823+ platform_io.Renderer_CreateWindow = ImGui_ImplDX11_CreateWindow;
824+ platform_io.Renderer_DestroyWindow = ImGui_ImplDX11_DestroyWindow;
825+ platform_io.Renderer_SetWindowSize = ImGui_ImplDX11_SetWindowSize;
826+ platform_io.Renderer_RenderWindow = ImGui_ImplDX11_RenderWindow;
827+ platform_io.Renderer_SwapBuffers = ImGui_ImplDX11_SwapBuffers;
828+
829+ // Default swapchain format
830+ DXGI_SWAP_CHAIN_DESC sd;
831+ ZeroMemory(&sd, sizeof(sd));
832+ sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
833+ sd.SampleDesc.Count = 1;
834+ sd.SampleDesc.Quality = 0;
835+ sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
836+ sd.BufferCount = 1;
837+ sd.Windowed = TRUE;
838+ sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
839+ sd.Flags = 0;
840+ ImGui_ImplDX11_SetSwapChainDescs(&sd, 1);
841+}
842+
843+static void ImGui_ImplDX11_ShutdownMultiViewportSupport()
844+{
845+ ImGui::DestroyPlatformWindows();
688846 }
689847
690848 //-----------------------------------------------------------------------------
@@ -6,6 +6,7 @@
66 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
77 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
88 // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
9+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
910
1011 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1112 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -6,6 +6,8 @@
66 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
77 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
88 // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
9+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
10+// FIXME: The transition from removing a viewport and moving the window in an existing hosted viewport tends to flicker.
911
1012 // The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification.
1113 // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
@@ -20,7 +22,9 @@
2022
2123 // CHANGELOG
2224 // (minor and older changes stripped away, please see git history for details)
25+// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
2326 // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
27+// 2025-10-23: [Docking] DirectX12: Fixed an issue in synchronization logic improving rendering throughput for secondary viewports. (#8961, #9025)
2428 // 2025-10-11: DirectX12: Reuse texture upload buffer and grow it only when necessary. (#9002)
2529 // 2025-09-29: DirectX12: Rework synchronization logic. (#8961)
2630 // 2025-09-29: DirectX12: Enable swapchain tearing to eliminate viewports framerate throttling. (#8965)
@@ -118,9 +122,6 @@
118122 UINT pTexUploadBufferSize;
119123 void* pTexUploadBufferMapped;
120124
121- ImGui_ImplDX12_RenderBuffers* pFrameResources;
122- UINT frameIndex;
123-
124125 ImGui_ImplDX12_Data() { memset((void*)this, 0, sizeof(*this)); }
125126 };
126127
@@ -140,11 +141,85 @@
140141 int VertexBufferSize;
141142 };
142143
144+// Buffers used for secondary viewports created by the multi-viewports systems
145+struct ImGui_ImplDX12_FrameContext
146+{
147+ UINT64 FenceValue;
148+ ID3D12CommandAllocator* CommandAllocator;
149+ ID3D12Resource* RenderTarget;
150+ D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetCpuDescriptors;
151+};
152+
153+// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
154+// Main viewport created by application will only use the Resources field.
155+// Secondary viewports created by this backend will use all the fields (including Window fields),
156+struct ImGui_ImplDX12_ViewportData
157+{
158+ // Window
159+ ID3D12CommandQueue* CommandQueue;
160+ ID3D12GraphicsCommandList* CommandList;
161+ ID3D12DescriptorHeap* RtvDescHeap;
162+ IDXGISwapChain3* SwapChain;
163+ HANDLE SwapChainWaitableObject;
164+ UINT NumFramesInFlight;
165+ ImGui_ImplDX12_FrameContext* FrameCtx;
166+
167+ // Render buffers
168+ UINT FrameIndex;
169+ ImGui_ImplDX12_RenderBuffers* FrameRenderBuffers;
170+
171+ ImGui_ImplDX12_ViewportData(UINT num_frames_in_flight)
172+ {
173+ CommandQueue = nullptr;
174+ CommandList = nullptr;
175+ RtvDescHeap = nullptr;
176+ SwapChain = nullptr;
177+ SwapChainWaitableObject = nullptr;
178+ NumFramesInFlight = num_frames_in_flight;
179+ FrameCtx = new ImGui_ImplDX12_FrameContext[NumFramesInFlight];
180+ FrameIndex = 0;
181+ FrameRenderBuffers = new ImGui_ImplDX12_RenderBuffers[NumFramesInFlight];
182+
183+ for (UINT i = 0; i < NumFramesInFlight; ++i)
184+ {
185+ FrameCtx[i].FenceValue = 0;
186+ FrameCtx[i].CommandAllocator = nullptr;
187+ FrameCtx[i].RenderTarget = nullptr;
188+
189+ // Create buffers with a default size (they will later be grown as needed)
190+ FrameRenderBuffers[i].IndexBuffer = nullptr;
191+ FrameRenderBuffers[i].VertexBuffer = nullptr;
192+ FrameRenderBuffers[i].VertexBufferSize = 5000;
193+ FrameRenderBuffers[i].IndexBufferSize = 10000;
194+ }
195+ }
196+ ~ImGui_ImplDX12_ViewportData()
197+ {
198+ IM_ASSERT(CommandQueue == nullptr && CommandList == nullptr);
199+ IM_ASSERT(RtvDescHeap == nullptr);
200+ IM_ASSERT(SwapChain == nullptr);
201+ IM_ASSERT(SwapChainWaitableObject == nullptr);
202+
203+ for (UINT i = 0; i < NumFramesInFlight; ++i)
204+ {
205+ IM_ASSERT(FrameCtx[i].CommandAllocator == nullptr && FrameCtx[i].RenderTarget == nullptr);
206+ IM_ASSERT(FrameRenderBuffers[i].IndexBuffer == nullptr && FrameRenderBuffers[i].VertexBuffer == nullptr);
207+ }
208+
209+ delete[] FrameCtx; FrameCtx = nullptr;
210+ delete[] FrameRenderBuffers; FrameRenderBuffers = nullptr;
211+ }
212+};
213+
143214 struct VERTEX_CONSTANT_BUFFER_DX12
144215 {
145216 float mvp[4][4];
146217 };
147218
219+// Forward Declarations
220+static void ImGui_ImplDX12_InitMultiViewportSupport();
221+static void ImGui_ImplDX12_ShutdownMultiViewportSupport();
222+
148223 // Functions
149224 static void ImGui_ImplDX12_SetupSamplerLinear(ID3D12GraphicsCommandList* command_list)
150225 {
@@ -240,8 +315,9 @@
240315
241316 // FIXME: We are assuming that this only gets called once per frame!
242317 ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
243- bd->frameIndex = bd->frameIndex + 1;
244- ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[bd->frameIndex % bd->numFramesInFlight];
318+ ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)draw_data->OwnerViewport->RendererUserData;
319+ ImGui_ImplDX12_RenderBuffers* fr = &vd->FrameRenderBuffers[vd->FrameIndex % bd->numFramesInFlight];
320+ vd->FrameIndex++;
245321
246322 // Create and grow vertex/index buffers if needed
247323 if (fr->VertexBuffer == nullptr || fr->VertexBufferSize < draw_data->TotalVtxCount)
@@ -842,6 +918,13 @@
842918 return true;
843919 }
844920
921+static void ImGui_ImplDX12_DestroyRenderBuffers(ImGui_ImplDX12_RenderBuffers* render_buffers)
922+{
923+ SafeRelease(render_buffers->IndexBuffer);
924+ SafeRelease(render_buffers->VertexBuffer);
925+ render_buffers->IndexBufferSize = render_buffers->VertexBufferSize = 0;
926+}
927+
845928 void ImGui_ImplDX12_InvalidateDeviceObjects()
846929 {
847930 ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
@@ -874,13 +957,6 @@
874957 for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
875958 if (tex->RefCount == 1)
876959 ImGui_ImplDX12_DestroyTexture(tex);
877-
878- for (UINT i = 0; i < bd->numFramesInFlight; i++)
879- {
880- ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
881- SafeRelease(fr->IndexBuffer);
882- SafeRelease(fr->VertexBuffer);
883- }
884960 }
885961
886962 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
@@ -929,7 +1005,16 @@
9291005 io.BackendRendererName = "imgui_impl_dx12";
9301006 io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
9311007 io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
1008+ io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
9321009
1010+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
1011+ ImGui_ImplDX12_InitMultiViewportSupport();
1012+
1013+ // Create a dummy ImGui_ImplDX12_ViewportData holder for the main viewport,
1014+ // Since this is created and managed by the application, we will only use the ->Resources[] fields.
1015+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
1016+ main_viewport->RendererUserData = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight);
1017+
9331018 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
9341019 platform_io.DrawCallback_ResetRenderState = ImGui_ImplDX12_DrawCallback_ResetRenderState;
9351020 platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplDX12_DrawCallback_SetSamplerLinear;
@@ -941,18 +1026,6 @@
9411026 #endif
9421027 IM_ASSERT(init_info->SrvDescriptorAllocFn != nullptr && init_info->SrvDescriptorFreeFn != nullptr);
9431028
944- // Create buffers with a default size (they will later be grown as needed)
945- bd->frameIndex = UINT_MAX;
946- bd->pFrameResources = new ImGui_ImplDX12_RenderBuffers[bd->numFramesInFlight];
947- for (int i = 0; i < (int)bd->numFramesInFlight; i++)
948- {
949- ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
950- fr->IndexBuffer = nullptr;
951- fr->VertexBuffer = nullptr;
952- fr->IndexBufferSize = 10000;
953- fr->VertexBufferSize = 5000;
954- }
955-
9561029 return true;
9571030 }
9581031
@@ -994,12 +1067,23 @@
9941067 ImGuiIO& io = ImGui::GetIO();
9951068 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
9961069
1070+ // Manually delete main viewport render resources in-case we haven't initialized for viewports
1071+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
1072+ if (ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)main_viewport->RendererUserData)
1073+ {
1074+ // We could just call ImGui_ImplDX12_DestroyWindow(main_viewport) as a convenience but that would be misleading since we only use data->Resources[]
1075+ for (UINT i = 0; i < bd->numFramesInFlight; i++)
1076+ ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]);
1077+ IM_DELETE(vd);
1078+ main_viewport->RendererUserData = nullptr;
1079+ }
1080+
1081+ ImGui_ImplDX12_ShutdownMultiViewportSupport();
9971082 ImGui_ImplDX12_InvalidateDeviceObjects();
998- delete[] bd->pFrameResources;
9991083
10001084 io.BackendRendererName = nullptr;
10011085 io.BackendRendererUserData = nullptr;
1002- io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
1086+ io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
10031087 platform_io.ClearRendererHandlers();
10041088 IM_DELETE(bd);
10051089 }
@@ -1012,6 +1096,254 @@
10121096 if (!bd->pPipelineStateLinear)
10131097 if (!ImGui_ImplDX12_CreateDeviceObjects())
10141098 IM_ASSERT(0 && "ImGui_ImplDX12_CreateDeviceObjects() failed!");
1099+}
1100+
1101+//--------------------------------------------------------------------------------------------------------
1102+// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
1103+// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
1104+// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
1105+//--------------------------------------------------------------------------------------------------------
1106+
1107+static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
1108+{
1109+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
1110+ ImGui_ImplDX12_ViewportData* vd = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight);
1111+ viewport->RendererUserData = vd;
1112+
1113+ // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID).
1114+ // Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND.
1115+ HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
1116+ IM_ASSERT(hwnd != 0);
1117+
1118+ // Use shared command queue from init info
1119+ vd->FrameIndex = 0;
1120+ vd->CommandQueue = bd->pCommandQueue;
1121+
1122+ // Create command allocator.
1123+ HRESULT res = S_OK;
1124+ for (UINT i = 0; i < bd->numFramesInFlight; ++i)
1125+ {
1126+ res = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&vd->FrameCtx[i].CommandAllocator));
1127+ IM_ASSERT(res == S_OK);
1128+ }
1129+
1130+ // Create command list.
1131+ res = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, vd->FrameCtx[0].CommandAllocator, nullptr, IID_PPV_ARGS(&vd->CommandList));
1132+ IM_ASSERT(res == S_OK);
1133+ vd->CommandList->Close();
1134+
1135+ // Create swap chain
1136+ // FIXME-VIEWPORT: May want to copy/inherit swap chain settings from the user/application.
1137+ DXGI_SWAP_CHAIN_DESC1 sd1;
1138+ ZeroMemory(&sd1, sizeof(sd1));
1139+ sd1.BufferCount = bd->numFramesInFlight;
1140+ sd1.Width = (UINT)viewport->Size.x;
1141+ sd1.Height = (UINT)viewport->Size.y;
1142+ sd1.Format = bd->RTVFormat;
1143+ sd1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
1144+ sd1.SampleDesc.Count = 1;
1145+ sd1.SampleDesc.Quality = 0;
1146+ sd1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
1147+ sd1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
1148+ sd1.Scaling = DXGI_SCALING_NONE;
1149+ sd1.Stereo = FALSE;
1150+ sd1.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
1151+
1152+ if (bd->tearingSupport)
1153+ sd1.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
1154+
1155+ IDXGISwapChain1* swap_chain = nullptr;
1156+ res = bd->pdxgiFactory->CreateSwapChainForHwnd(vd->CommandQueue, hwnd, &sd1, nullptr, nullptr, &swap_chain);
1157+ IM_ASSERT(res == S_OK);
1158+ res = bd->pdxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES); // Disable e.g. Alt+Enter
1159+ IM_ASSERT(res == S_OK);
1160+
1161+ // Or swapChain.As(&mSwapChain)
1162+ IM_ASSERT(vd->SwapChain == nullptr);
1163+ swap_chain->QueryInterface(IID_PPV_ARGS(&vd->SwapChain));
1164+ swap_chain->Release();
1165+
1166+ // Create the render targets and waitable object
1167+ if (vd->SwapChain)
1168+ {
1169+ D3D12_DESCRIPTOR_HEAP_DESC desc = {};
1170+ desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
1171+ desc.NumDescriptors = bd->numFramesInFlight;
1172+ desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
1173+ desc.NodeMask = 1;
1174+
1175+ HRESULT hr = bd->pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&vd->RtvDescHeap));
1176+ IM_ASSERT(hr == S_OK);
1177+
1178+ SIZE_T rtv_descriptor_size = bd->pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
1179+ D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = vd->RtvDescHeap->GetCPUDescriptorHandleForHeapStart();
1180+ for (UINT i = 0; i < bd->numFramesInFlight; i++)
1181+ {
1182+ vd->FrameCtx[i].RenderTargetCpuDescriptors = rtv_handle;
1183+ rtv_handle.ptr += rtv_descriptor_size;
1184+ }
1185+
1186+ ID3D12Resource* back_buffer;
1187+ for (UINT i = 0; i < bd->numFramesInFlight; i++)
1188+ {
1189+ IM_ASSERT(vd->FrameCtx[i].RenderTarget == nullptr);
1190+ vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
1191+ bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors);
1192+ vd->FrameCtx[i].RenderTarget = back_buffer;
1193+ }
1194+
1195+ hr = vd->SwapChain->SetMaximumFrameLatency(bd->numFramesInFlight);
1196+ IM_ASSERT(hr == S_OK);
1197+ vd->SwapChainWaitableObject = vd->SwapChain->GetFrameLatencyWaitableObject();
1198+ }
1199+
1200+ for (UINT i = 0; i < bd->numFramesInFlight; i++)
1201+ ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]);
1202+}
1203+
1204+static void ImGui_WaitForPendingOperations(ImGui_ImplDX12_ViewportData* vd)
1205+{
1206+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
1207+ HRESULT hr = vd->CommandQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue);
1208+ IM_ASSERT(hr == S_OK);
1209+
1210+ hr = bd->Fence->SetEventOnCompletion(bd->FenceLastSignaledValue, bd->FenceEvent);
1211+ IM_ASSERT(hr == S_OK);
1212+ ::WaitForSingleObject(bd->FenceEvent, INFINITE);
1213+}
1214+
1215+static ImGui_ImplDX12_FrameContext* ImGui_WaitForNextFrameContext(ImGui_ImplDX12_ViewportData* vd)
1216+{
1217+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
1218+ ImGui_ImplDX12_FrameContext* frame_context = &vd->FrameCtx[vd->FrameIndex % vd->NumFramesInFlight];
1219+ if (bd->Fence->GetCompletedValue() < frame_context->FenceValue)
1220+ {
1221+ HRESULT hr = bd->Fence->SetEventOnCompletion(frame_context->FenceValue, bd->FenceEvent);
1222+ IM_ASSERT(hr == S_OK);
1223+ HANDLE waitableObjects[] = { vd->SwapChainWaitableObject, bd->FenceEvent };
1224+ ::WaitForMultipleObjects(2, waitableObjects, TRUE, INFINITE);
1225+ }
1226+ else
1227+ {
1228+ ::WaitForSingleObject(vd->SwapChainWaitableObject, INFINITE);
1229+ }
1230+ return frame_context;
1231+}
1232+
1233+static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport)
1234+{
1235+ // The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it.
1236+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
1237+ if (ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData)
1238+ {
1239+ ImGui_WaitForPendingOperations(vd);
1240+
1241+ vd->CommandQueue = nullptr;
1242+ ::CloseHandle(vd->SwapChainWaitableObject);
1243+ vd->SwapChainWaitableObject = nullptr;
1244+ SafeRelease(vd->CommandList);
1245+ SafeRelease(vd->SwapChain);
1246+ SafeRelease(vd->RtvDescHeap);
1247+
1248+ for (UINT i = 0; i < bd->numFramesInFlight; i++)
1249+ {
1250+ SafeRelease(vd->FrameCtx[i].RenderTarget);
1251+ SafeRelease(vd->FrameCtx[i].CommandAllocator);
1252+ ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]);
1253+ }
1254+ IM_DELETE(vd);
1255+ }
1256+ viewport->RendererUserData = nullptr;
1257+}
1258+
1259+static void ImGui_ImplDX12_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
1260+{
1261+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
1262+ ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
1263+
1264+ ImGui_WaitForPendingOperations(vd);
1265+
1266+ for (UINT i = 0; i < bd->numFramesInFlight; i++)
1267+ SafeRelease(vd->FrameCtx[i].RenderTarget);
1268+
1269+ if (vd->SwapChain)
1270+ {
1271+ ID3D12Resource* back_buffer = nullptr;
1272+ DXGI_SWAP_CHAIN_DESC1 desc = {};
1273+ vd->SwapChain->GetDesc1(&desc);
1274+ vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, desc.Format, desc.Flags);
1275+ for (UINT i = 0; i < bd->numFramesInFlight; i++)
1276+ {
1277+ vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
1278+ bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors);
1279+ vd->FrameCtx[i].RenderTarget = back_buffer;
1280+ }
1281+ }
1282+}
1283+
1284+static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*)
1285+{
1286+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
1287+ ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
1288+
1289+ ImGui_ImplDX12_FrameContext* frame_context = ImGui_WaitForNextFrameContext(vd);
1290+ UINT back_buffer_idx = vd->SwapChain->GetCurrentBackBufferIndex();
1291+
1292+ const ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
1293+ D3D12_RESOURCE_BARRIER barrier = {};
1294+ barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
1295+ barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
1296+ barrier.Transition.pResource = vd->FrameCtx[back_buffer_idx].RenderTarget;
1297+ barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
1298+ barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
1299+ barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
1300+
1301+ // Draw
1302+ ID3D12GraphicsCommandList* cmd_list = vd->CommandList;
1303+
1304+ frame_context->CommandAllocator->Reset();
1305+ cmd_list->Reset(frame_context->CommandAllocator, nullptr);
1306+ cmd_list->ResourceBarrier(1, &barrier);
1307+ cmd_list->OMSetRenderTargets(1, &vd->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, FALSE, nullptr);
1308+ if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
1309+ cmd_list->ClearRenderTargetView(vd->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, (const float*)&clear_color, 0, nullptr);
1310+ cmd_list->SetDescriptorHeaps(1, &bd->pd3dSrvDescHeap);
1311+
1312+ ImGui_ImplDX12_RenderDrawData(viewport->DrawData, cmd_list);
1313+
1314+ barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
1315+ barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
1316+ cmd_list->ResourceBarrier(1, &barrier);
1317+ cmd_list->Close();
1318+
1319+ vd->CommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmd_list);
1320+
1321+ HRESULT hr = vd->CommandQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue);
1322+ IM_ASSERT(hr == S_OK);
1323+ frame_context->FenceValue = bd->FenceLastSignaledValue;
1324+}
1325+
1326+static void ImGui_ImplDX12_SwapBuffers(ImGuiViewport* viewport, void*)
1327+{
1328+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
1329+ ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
1330+
1331+ vd->SwapChain->Present(0, bd->tearingSupport ? DXGI_PRESENT_ALLOW_TEARING : 0);
1332+}
1333+
1334+void ImGui_ImplDX12_InitMultiViewportSupport()
1335+{
1336+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
1337+ platform_io.Renderer_CreateWindow = ImGui_ImplDX12_CreateWindow;
1338+ platform_io.Renderer_DestroyWindow = ImGui_ImplDX12_DestroyWindow;
1339+ platform_io.Renderer_SetWindowSize = ImGui_ImplDX12_SetWindowSize;
1340+ platform_io.Renderer_RenderWindow = ImGui_ImplDX12_RenderWindow;
1341+ platform_io.Renderer_SwapBuffers = ImGui_ImplDX12_SwapBuffers;
1342+}
1343+
1344+void ImGui_ImplDX12_ShutdownMultiViewportSupport()
1345+{
1346+ ImGui::DestroyPlatformWindows();
10151347 }
10161348
10171349 //-----------------------------------------------------------------------------
@@ -6,6 +6,7 @@
66 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
77 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
88 // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
9+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
910
1011 // The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification.
1112 // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
@@ -6,6 +6,7 @@
66 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
77 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
88 // [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9.
9+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
910
1011 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1112 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -17,6 +18,7 @@
1718
1819 // CHANGELOG
1920 // (minor and older changes stripped away, please see git history for details)
21+// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
2022 // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
2123 // 2026-03-19: Fixed issue in ImGui_ImplDX9_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310)
2224 // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
@@ -89,6 +91,12 @@
8991 return ImGui::GetCurrentContext() ? (ImGui_ImplDX9_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
9092 }
9193
94+// Forward Declarations
95+static void ImGui_ImplDX9_InitMultiViewportSupport();
96+static void ImGui_ImplDX9_ShutdownMultiViewportSupport();
97+static void ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows();
98+static void ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows();
99+
92100 // Functions
93101 static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
94102 {
@@ -302,6 +310,11 @@
302310 global_vtx_offset += draw_list->VtxBuffer.Size;
303311 }
304312
313+ // When using multi-viewports, it appears that there's an odd logic in DirectX9 which prevent subsequent windows
314+ // from rendering until the first window submits at least one draw call, even once. That's our workaround. (see #2560)
315+ if (global_vtx_offset == 0)
316+ bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 0, 0, 0);
317+
305318 // Restore the DX9 transform
306319 device->SetTransform(D3DTS_WORLD, &last_world);
307320 device->SetTransform(D3DTS_VIEW, &last_view);
@@ -415,6 +428,7 @@
415428 ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
416429 if (!bd || !bd->pd3dDevice)
417430 return false;
431+ ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows();
418432 return true;
419433 }
420434
@@ -433,6 +447,7 @@
433447 }
434448 if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
435449 if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
450+ ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows();
436451 }
437452
438453 void ImGui_ImplDX9_NewFrame()
@@ -442,7 +457,6 @@
442457 IM_UNUSED(bd);
443458 }
444459
445-
446460 bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
447461 {
448462 ImGuiIO& io = ImGui::GetIO();
@@ -455,6 +469,7 @@
455469 io.BackendRendererName = "imgui_impl_dx9";
456470 io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
457471 io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
472+ io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
458473
459474 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
460475 platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = 4096;
@@ -466,6 +481,8 @@
466481 bd->pd3dDevice->AddRef();
467482 bd->HasRgbaSupport = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8);
468483
484+ ImGui_ImplDX9_InitMultiViewportSupport();
485+
469486 return true;
470487 }
471488
@@ -476,14 +493,157 @@
476493 ImGuiIO& io = ImGui::GetIO();
477494 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
478495
496+ ImGui_ImplDX9_ShutdownMultiViewportSupport();
479497 ImGui_ImplDX9_InvalidateDeviceObjects();
480498 if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
481499
482500 io.BackendRendererName = nullptr;
483501 io.BackendRendererUserData = nullptr;
484- io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
502+ io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
485503 platform_io.ClearRendererHandlers();
486504 IM_DELETE(bd);
505+}
506+
507+//--------------------------------------------------------------------------------------------------------
508+// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
509+// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
510+// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
511+//--------------------------------------------------------------------------------------------------------
512+
513+// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
514+struct ImGui_ImplDX9_ViewportData
515+{
516+ IDirect3DSwapChain9* SwapChain;
517+ D3DPRESENT_PARAMETERS d3dpp;
518+
519+ ImGui_ImplDX9_ViewportData() { SwapChain = nullptr; ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS)); }
520+ ~ImGui_ImplDX9_ViewportData() { IM_ASSERT(SwapChain == nullptr); }
521+};
522+
523+static void ImGui_ImplDX9_CreateWindow(ImGuiViewport* viewport)
524+{
525+ ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
526+ ImGui_ImplDX9_ViewportData* vd = IM_NEW(ImGui_ImplDX9_ViewportData)();
527+ viewport->RendererUserData = vd;
528+
529+ // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID).
530+ // Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND.
531+ HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
532+ IM_ASSERT(hwnd != 0);
533+
534+ ZeroMemory(&vd->d3dpp, sizeof(D3DPRESENT_PARAMETERS));
535+ vd->d3dpp.Windowed = TRUE;
536+ vd->d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
537+ vd->d3dpp.BackBufferWidth = (UINT)viewport->Size.x;
538+ vd->d3dpp.BackBufferHeight = (UINT)viewport->Size.y;
539+ vd->d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
540+ vd->d3dpp.hDeviceWindow = hwnd;
541+ vd->d3dpp.EnableAutoDepthStencil = FALSE;
542+ vd->d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
543+ vd->d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Present without vsync
544+
545+ HRESULT hr = bd->pd3dDevice->CreateAdditionalSwapChain(&vd->d3dpp, &vd->SwapChain); IM_UNUSED(hr);
546+ IM_ASSERT(hr == D3D_OK);
547+ IM_ASSERT(vd->SwapChain != nullptr);
548+}
549+
550+static void ImGui_ImplDX9_DestroyWindow(ImGuiViewport* viewport)
551+{
552+ // The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it.
553+ if (ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData)
554+ {
555+ if (vd->SwapChain)
556+ vd->SwapChain->Release();
557+ vd->SwapChain = nullptr;
558+ ZeroMemory(&vd->d3dpp, sizeof(D3DPRESENT_PARAMETERS));
559+ IM_DELETE(vd);
560+ }
561+ viewport->RendererUserData = nullptr;
562+}
563+
564+static void ImGui_ImplDX9_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
565+{
566+ ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
567+ ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData;
568+ if (vd->SwapChain)
569+ {
570+ vd->SwapChain->Release();
571+ vd->SwapChain = nullptr;
572+ vd->d3dpp.BackBufferWidth = (UINT)size.x;
573+ vd->d3dpp.BackBufferHeight = (UINT)size.y;
574+ HRESULT hr = bd->pd3dDevice->CreateAdditionalSwapChain(&vd->d3dpp, &vd->SwapChain); IM_UNUSED(hr);
575+ IM_ASSERT(hr == D3D_OK);
576+ }
577+}
578+
579+static void ImGui_ImplDX9_RenderWindow(ImGuiViewport* viewport, void*)
580+{
581+ ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
582+ ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData;
583+ ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
584+
585+ LPDIRECT3DSURFACE9 render_target = nullptr;
586+ LPDIRECT3DSURFACE9 last_render_target = nullptr;
587+ LPDIRECT3DSURFACE9 last_depth_stencil = nullptr;
588+ vd->SwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &render_target);
589+ bd->pd3dDevice->GetRenderTarget(0, &last_render_target);
590+ bd->pd3dDevice->GetDepthStencilSurface(&last_depth_stencil);
591+ bd->pd3dDevice->SetRenderTarget(0, render_target);
592+ bd->pd3dDevice->SetDepthStencilSurface(nullptr);
593+
594+ if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
595+ {
596+ D3DCOLOR clear_col_dx = D3DCOLOR_RGBA((int)(clear_color.x*255.0f), (int)(clear_color.y*255.0f), (int)(clear_color.z*255.0f), (int)(clear_color.w*255.0f));
597+ bd->pd3dDevice->Clear(0, nullptr, D3DCLEAR_TARGET, clear_col_dx, 1.0f, 0);
598+ }
599+
600+ ImGui_ImplDX9_RenderDrawData(viewport->DrawData);
601+
602+ // Restore render target
603+ bd->pd3dDevice->SetRenderTarget(0, last_render_target);
604+ bd->pd3dDevice->SetDepthStencilSurface(last_depth_stencil);
605+ render_target->Release();
606+ last_render_target->Release();
607+ if (last_depth_stencil) last_depth_stencil->Release();
608+}
609+
610+static void ImGui_ImplDX9_SwapBuffers(ImGuiViewport* viewport, void*)
611+{
612+ ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData;
613+ HRESULT hr = vd->SwapChain->Present(nullptr, nullptr, vd->d3dpp.hDeviceWindow, nullptr, 0);
614+ // Let main application handle D3DERR_DEVICELOST by resetting the device.
615+ IM_ASSERT(SUCCEEDED(hr) || hr == D3DERR_DEVICELOST);
616+}
617+
618+static void ImGui_ImplDX9_InitMultiViewportSupport()
619+{
620+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
621+ platform_io.Renderer_CreateWindow = ImGui_ImplDX9_CreateWindow;
622+ platform_io.Renderer_DestroyWindow = ImGui_ImplDX9_DestroyWindow;
623+ platform_io.Renderer_SetWindowSize = ImGui_ImplDX9_SetWindowSize;
624+ platform_io.Renderer_RenderWindow = ImGui_ImplDX9_RenderWindow;
625+ platform_io.Renderer_SwapBuffers = ImGui_ImplDX9_SwapBuffers;
626+}
627+
628+static void ImGui_ImplDX9_ShutdownMultiViewportSupport()
629+{
630+ ImGui::DestroyPlatformWindows();
631+}
632+
633+static void ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows()
634+{
635+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
636+ for (int i = 1; i < platform_io.Viewports.Size; i++)
637+ if (!platform_io.Viewports[i]->RendererUserData)
638+ ImGui_ImplDX9_CreateWindow(platform_io.Viewports[i]);
639+}
640+
641+static void ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows()
642+{
643+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
644+ for (int i = 1; i < platform_io.Viewports.Size; i++)
645+ if (platform_io.Viewports[i]->RendererUserData)
646+ ImGui_ImplDX9_DestroyWindow(platform_io.Viewports[i]);
487647 }
488648
489649 //-----------------------------------------------------------------------------
@@ -6,6 +6,7 @@
66 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
77 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
88 // [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9.
9+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
910
1011 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1112 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -9,10 +9,12 @@
99 // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5]
1010 // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
1111 // [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'.
12+// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
1213 // [X] Multiple Dear ImGui contexts support.
1314 // Missing features or Issues:
1415 // [ ] 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.
1516 // [ ] Platform: Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors.
17+// [ ] Platform: Multi-viewport: Missing ImGuiBackendFlags_HasParentViewport support. The viewport->ParentViewportID field is ignored, and therefore io.ConfigViewportsNoDefaultParent has no effect either.
1618
1719 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1820 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -29,19 +31,27 @@
2931
3032 // CHANGELOG
3133 // (minor and older changes stripped away, please see git history for details)
34+// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
3235 // 2026-04-21: Added a Win32-specific implementation of ImGui_ImplGlfw_GetContentScaleXXXX functions for legacy GLFW 3.2.
3336 // 2026-03-25: Mouse cursor is properly restored if changed by user app/code while using glfwSetInputMode(..., GLFW_CURSOR_DISABLED) or ImGuiConfigFlags_NoMouseCursorChange. Amend change from 2025-12-10.
3437 // 2026-02-10: Try to set IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND automatically if corresponding headers are not accessible. (#9225)
38+// 2026-01-25: [Docking] Improve workarounds for cases where GLFW is unable to provide any reliable monitor info. Preserve existing monitor list when none of the new one is valid. (#9195, #7902, #5683)
39+// 2026-01-18: [Docking] Dynamically load X11 functions to avoid -lx11 linking requirement introduced on 2025-09-10.
3540 // 2025-12-12: Added IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND to forcefully disable either.
3641 // 2025-12-10: Avoid repeated glfwSetCursor()/glfwSetInputMode() calls when unnecessary. Lowers overhead for very high framerates (e.g. 10k+ FPS).
3742 // 2025-11-06: Lower minimum requirement to GLFW 3.0. Though a recent version e.g GLFW 3.4 is highly recommended.
3843 // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown.
3944 // 2025-09-15: Content Scales are always reported as 1.0 on Wayland. FramebufferScale are always reported as 1.0 on X11. (#8920, #8921)
45+// 2025-09-10: [Docking] Improve multi-viewport behavior in tiling WMs on X11 via the ImGui_ImplGlfw_SetWindowFloating() function. Note: using GLFW backend on Linux/BSD etc. requires linking with -lX11. (#8884, #8474, #8289)
4046 // 2025-07-08: Made ImGui_ImplGlfw_GetContentScaleForWindow(), ImGui_ImplGlfw_GetContentScaleForMonitor() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733)
4147 // 2025-06-18: Added support for multiple Dear ImGui contexts. (#8676, #8239, #8069)
4248 // 2025-06-11: Added ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) and ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) helper to facilitate making DPI-aware apps.
49+// 2025-05-15: [Docking] Add Platform_GetWindowFramebufferScale() handler, to allow varying Retina display density on multiple monitors.
50+// 2025-04-26: [Docking] Disable multi-viewports under Wayland. (#8587)
4351 // 2025-03-10: Map GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 into ImGuiKey_Oem102.
4452 // 2025-03-03: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled.
53+// 2025-02-21: [Docking] Update monitors and work areas information every frame, as the later may change regardless of monitor changes. (#8415)
54+// 2024-11-05: [Docking] Added Linux workaround for spurious mouse up events emitted while dragging and creating new viewport. (#3158, #7733, #7922)
4555 // 2024-08-22: Moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
4656 // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
4757 // - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn
@@ -58,6 +68,7 @@
5868 // 2023-03-16: Inputs: Fixed key modifiers handling on secondary viewports (docking branch). Broken on 2023/01/04. (#6248, #6034)
5969 // 2023-03-14: Emscripten: Avoid using glfwGetError() and glfwGetGamepadState() which are not correctly implemented in Emscripten emulation. (#6240)
6070 // 2023-02-03: Emscripten: Registering custom low-level mouse wheel handler to get more accurate scrolling impulses on Emscripten. (#4019, #6096)
71+// 2023-01-18: Handle unsupported glfwGetVideoMode() call on e.g. Emscripten.
6172 // 2023-01-04: Inputs: Fixed mods state on Linux when using Alt-GR text input (e.g. German keyboard layout), could lead to broken text input. Revert a 2022/01/17 change were we resumed using mods provided by GLFW, turns out they were faulty.
6273 // 2022-11-22: Perform a dummy glfwGetError() read to cancel missing names with glfwGetKeyName(). (#5908)
6374 // 2022-10-18: Perform a dummy glfwGetError() read to cancel missing mouse cursors errors. Using GLFW_VERSION_COMBINED directly. (#5785)
@@ -110,6 +121,8 @@
110121 #pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
111122 #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.
112123 #pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is.
124+#elif defined(__GNUC__)
125+#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe
113126 #endif
114127
115128 #if defined(__has_include)
@@ -147,10 +160,13 @@
147160 #elif GLFW_HAS_X11
148161 #ifndef GLFW_EXPOSE_NATIVE_X11 // for glfwGetX11Display(), glfwGetX11Window() on Freedesktop (Linux, BSD, etc.)
149162 #define GLFW_EXPOSE_NATIVE_X11
163+#include <X11/Xatom.h>
164+#include <dlfcn.h> // for dlopen()
150165 #endif
151166 #include <GLFW/glfw3native.h>
152-#endif
153167 #undef Status // X11 headers are leaking this.
168+#endif
169+
154170 #ifndef _WIN32
155171 #include <unistd.h> // for usleep()
156172 #endif
@@ -169,12 +185,29 @@
169185 // We gather version tests as define in order to easily see which features are version-dependent.
170186 #define GLFW_VERSION_COMBINED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION)
171187 #define GLFW_HAS_CREATECURSOR (GLFW_VERSION_COMBINED >= 3100) // 3.1+ glfwCreateCursor()
188+#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_COMBINED >= 3200) // 3.2+ GLFW_FLOATING
189+#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_COMBINED >= 3300) // 3.3+ GLFW_HOVERED
190+#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwSetWindowOpacity
172191 #define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetMonitorContentScale
192+#if defined(__EMSCRIPTEN__) || defined(__SWITCH__) // no Vulkan support in GLFW for Emscripten or homebrew Nintendo Switch
193+#define GLFW_HAS_VULKAN (0)
194+#else
195+#define GLFW_HAS_VULKAN (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwCreateWindowSurface
196+#endif
197+#define GLFW_HAS_FOCUS_WINDOW (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwFocusWindow
198+#define GLFW_HAS_FOCUS_ON_SHOW (GLFW_VERSION_COMBINED >= 3300) // 3.3+ GLFW_FOCUS_ON_SHOW
199+#define GLFW_HAS_MONITOR_WORK_AREA (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetMonitorWorkarea
200+#define GLFW_HAS_OSX_WINDOW_POS_FIX (GLFW_VERSION_COMBINED >= 3301) // 3.3.1+ Fixed: Resizing window repositions it on MacOS #1553
173201 #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?
174202 #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
175203 #else
176204 #define GLFW_HAS_NEW_CURSORS (0)
177205 #endif
206+#ifdef GLFW_MOUSE_PASSTHROUGH // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2020-07-17 (passthrough)
207+#define GLFW_HAS_MOUSE_PASSTHROUGH (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_MOUSE_PASSTHROUGH
208+#else
209+#define GLFW_HAS_MOUSE_PASSTHROUGH (0)
210+#endif
178211 #define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetGamepadState() new api
179212 #define GLFW_HAS_GETKEYNAME (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwGetKeyName()
180213 #define GLFW_HAS_GETERROR (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetError()
@@ -197,6 +230,13 @@
197230 GlfwClientApi_Unknown, // Anything else fits here.
198231 };
199232
233+#if GLFW_HAS_X11
234+typedef Atom (*PFN_XInternAtom)(Display*, const char* ,Bool);
235+typedef int (*PFN_XChangeProperty)(Display*, Window, Atom, Atom, int, int, const unsigned char*, int);
236+typedef int (*PFN_XChangeWindowAttributes)(Display*, Window, unsigned long, XSetWindowAttributes*);
237+typedef int (*PFN_XFlush)(Display*);
238+#endif
239+
200240 // GLFW data
201241 struct ImGui_ImplGlfw_Data
202242 {
@@ -209,7 +249,10 @@
209249 GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT];
210250 GLFWcursor* LastMouseCursor;
211251 #endif
252+ bool MouseIgnoreButtonUpWaitForFocusLoss;
253+ bool MouseIgnoreButtonUp;
212254 ImVec2 LastValidMousePos;
255+ GLFWwindow* KeyOwnerWindows[GLFW_KEY_LAST];
213256 bool IsWayland;
214257 bool InstalledCallbacks;
215258 bool CallbacksChainForAllWindows;
@@ -231,6 +274,15 @@
231274 WNDPROC PrevWndProc;
232275 #endif
233276
277+#if GLFW_HAS_X11
278+ // Module and function pointers loaded at initialization to avoid linking statically with X11.
279+ void* X11Module;
280+ PFN_XInternAtom XInternAtom;
281+ PFN_XChangeProperty XChangeProperty;
282+ PFN_XChangeWindowAttributes XChangeWindowAttributes;
283+ PFN_XFlush XFlush;
284+#endif
285+
234286 ImGui_ImplGlfw_Data() { memset((void*)this, 0, sizeof(*this)); }
235287 };
236288
@@ -254,6 +306,11 @@
254306 return (ImGui_ImplGlfw_Data*)ImGui::GetIO(ctx).BackendPlatformUserData;
255307 }
256308
309+// Forward Declarations
310+static void ImGui_ImplGlfw_UpdateMonitors();
311+static void ImGui_ImplGlfw_InitMultiViewportSupport();
312+static void ImGui_ImplGlfw_ShutdownMultiViewportSupport();
313+
257314 // Functions
258315 static bool ImGui_ImplGlfw_IsWayland()
259316 {
@@ -424,6 +481,10 @@
424481 if (bd->PrevUserCallbackMousebutton != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window))
425482 bd->PrevUserCallbackMousebutton(window, button, action, mods);
426483
484+ // Workaround for Linux: ignore mouse up events which are following an focus loss following a viewport creation
485+ if (bd->MouseIgnoreButtonUp && action == GLFW_RELEASE)
486+ return;
487+
427488 ImGuiIO& io = ImGui::GetIO(bd->Context);
428489 ImGui_ImplGlfw_UpdateKeyModifiers(io, window);
429490 if (button >= 0 && button < ImGuiMouseButton_COUNT)
@@ -491,6 +552,9 @@
491552 ImGuiIO& io = ImGui::GetIO(bd->Context);
492553 ImGui_ImplGlfw_UpdateKeyModifiers(io, window);
493554
555+ if (keycode >= 0 && keycode < IM_COUNTOF(bd->KeyOwnerWindows))
556+ bd->KeyOwnerWindows[keycode] = (action == GLFW_PRESS) ? window : nullptr;
557+
494558 keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode);
495559
496560 ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode, scancode);
@@ -504,6 +568,10 @@
504568 if (bd->PrevUserCallbackWindowFocus != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window))
505569 bd->PrevUserCallbackWindowFocus(window, focused);
506570
571+ // Workaround for Linux: when losing focus with MouseIgnoreButtonUpWaitForFocusLoss set, we will temporarily ignore subsequent Mouse Up events
572+ bd->MouseIgnoreButtonUp = (bd->MouseIgnoreButtonUpWaitForFocusLoss && focused == 0);
573+ bd->MouseIgnoreButtonUpWaitForFocusLoss = false;
574+
507575 ImGuiIO& io = ImGui::GetIO(bd->Context);
508576 io.AddFocusEvent(focused != 0);
509577 }
@@ -515,6 +583,13 @@
515583 bd->PrevUserCallbackCursorPos(window, x, y);
516584
517585 ImGuiIO& io = ImGui::GetIO(bd->Context);
586+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
587+ {
588+ int window_x, window_y;
589+ glfwGetWindowPos(window, &window_x, &window_y);
590+ x += window_x;
591+ y += window_y;
592+ }
518593 io.AddMousePosEvent((float)x, (float)y);
519594 bd->LastValidMousePos = ImVec2((float)x, (float)y);
520595 }
@@ -553,7 +628,7 @@
553628
554629 void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
555630 {
556- // Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too.
631+ // This function is technically part of the API even if we stopped using the callback, so leaving it around.
557632 }
558633
559634 #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
@@ -576,35 +651,7 @@
576651 #endif
577652
578653 #ifdef _WIN32
579-// GLFW doesn't allow to distinguish Mouse vs TouchScreen vs Pen.
580-// Add support for Win32 (based on imgui_impl_win32), because we rely on _TouchScreen info to trickle inputs differently.
581-static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo()
582-{
583- LPARAM extra_info = ::GetMessageExtraInfo();
584- if ((extra_info & 0xFFFFFF80) == 0xFF515700)
585- return ImGuiMouseSource_Pen;
586- if ((extra_info & 0xFFFFFF80) == 0xFF515780)
587- return ImGuiMouseSource_TouchScreen;
588- return ImGuiMouseSource_Mouse;
589-}
590-static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
591-{
592- ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)::GetPropA(hWnd, "IMGUI_BACKEND_DATA");
593- ImGuiIO& io = ImGui::GetIO(bd->Context);
594-
595- switch (msg)
596- {
597- case WM_MOUSEMOVE: case WM_NCMOUSEMOVE:
598- case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_LBUTTONUP:
599- case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_RBUTTONUP:
600- case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_MBUTTONUP:
601- case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: case WM_XBUTTONUP:
602- io.AddMouseSourceEvent(GetMouseSourceFromMessageExtraInfo());
603- break;
604- default: break;
605- }
606- return ::CallWindowProcW(bd->PrevWndProc, hWnd, msg, wParam, lParam);
607-}
654+static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
608655 #endif
609656
610657 void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
@@ -684,6 +731,20 @@
684731 #endif
685732 io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
686733
734+ bool has_viewports = false;
735+#ifndef __EMSCRIPTEN__
736+ has_viewports = true;
737+#if GLFW_HAS_GETPLATFORM
738+ if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND)
739+ has_viewports = false;
740+#endif
741+ if (has_viewports)
742+ io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
743+#endif
744+#if GLFW_HAS_MOUSE_PASSTHROUGH || GLFW_HAS_WINDOW_HOVERED
745+ io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional)
746+#endif
747+
687748 bd->Context = ImGui::GetCurrentContext();
688749 bd->Window = window;
689750 bd->Time = 0.0;
@@ -735,6 +796,11 @@
735796 if (install_callbacks)
736797 ImGui_ImplGlfw_InstallCallbacks(window);
737798
799+ // Update monitor a first time during init
800+ // (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784)
801+ ImGui_ImplGlfw_UpdateMonitors();
802+ glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
803+
738804 // Set platform dependent data in viewport
739805 ImGuiViewport* main_viewport = ImGui::GetMainViewport();
740806 main_viewport->PlatformHandle = (void*)bd->Window;
@@ -745,6 +811,8 @@
745811 #else
746812 IM_UNUSED(main_viewport);
747813 #endif
814+ if (has_viewports)
815+ ImGui_ImplGlfw_InitMultiViewportSupport();
748816
749817 // Windows: register a WndProc hook so we can intercept some messages.
750818 #ifdef _WIN32
@@ -755,6 +823,26 @@
755823 ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc);
756824 #endif
757825
826+#if GLFW_HAS_X11
827+ if (!bd->IsWayland)
828+ {
829+ // Load X11 module dynamically. Copied from the way that GLFW does it in x11_init.c
830+#if defined(__CYGWIN__)
831+ const char* x11_module_path = "libX11-6.so";
832+#elif defined(__OpenBSD__) || defined(__NetBSD__)
833+ const char* x11_module_path = "libX11.so";
834+#else
835+ const char* x11_module_path = "libX11.so.6";
836+#endif
837+ bd->X11Module = dlopen(x11_module_path, RTLD_LAZY | RTLD_LOCAL);
838+ bd->XInternAtom = (PFN_XInternAtom)dlsym(bd->X11Module, "XInternAtom");
839+ bd->XChangeProperty = (PFN_XChangeProperty)dlsym(bd->X11Module, "XChangeProperty");
840+ bd->XChangeWindowAttributes = (PFN_XChangeWindowAttributes)dlsym(bd->X11Module, "XChangeWindowAttributes");
841+ bd->XFlush = (PFN_XFlush)dlsym(bd->X11Module, "XFlush");
842+ IM_ASSERT(bd->XInternAtom != nullptr && bd->XChangeProperty != nullptr && bd->XChangeWindowAttributes != nullptr && bd->XFlush != nullptr);
843+ }
844+#endif
845+
758846 // Emscripten: the same application can run on various platforms, so we detect the Apple platform at runtime
759847 // to override io.ConfigMacOSXBehaviors from its default (which is always false in Emscripten).
760848 #ifdef __EMSCRIPTEN__
@@ -799,6 +887,7 @@
799887 ImGuiIO& io = ImGui::GetIO();
800888 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
801889
890+ ImGui_ImplGlfw_ShutdownMultiViewportSupport();
802891 if (bd->InstalledCallbacks)
803892 ImGui_ImplGlfw_RestoreCallbacks(bd->Window);
804893 #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
@@ -817,9 +906,14 @@
817906 bd->PrevWndProc = nullptr;
818907 #endif
819908
909+#if GLFW_HAS_X11
910+ if (bd->X11Module != nullptr)
911+ dlclose(bd->X11Module);
912+#endif
913+
820914 io.BackendPlatformName = nullptr;
821915 io.BackendPlatformUserData = nullptr;
822- io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
916+ io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport);
823917 platform_io.ClearPlatformHandlers();
824918 ImGui_ImplGlfw_ContextMap_Remove(bd->Window);
825919 IM_DELETE(bd);
@@ -829,10 +923,15 @@
829923 {
830924 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
831925 ImGuiIO& io = ImGui::GetIO();
926+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
832927
833- // (those braces are here to reduce diff with multi-viewports support in 'docking' branch)
928+ ImGuiID mouse_viewport_id = 0;
929+ const ImVec2 mouse_pos_prev = io.MousePos;
930+ for (int n = 0; n < platform_io.Viewports.Size; n++)
834931 {
835- GLFWwindow* window = bd->Window;
932+ ImGuiViewport* viewport = platform_io.Viewports[n];
933+ GLFWwindow* window = (GLFWwindow*)viewport->PlatformHandle;
934+
836935 #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
837936 const bool is_window_focused = true;
838937 #else
@@ -841,19 +940,54 @@
841940 if (is_window_focused)
842941 {
843942 // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
943+ // When multi-viewports are enabled, all Dear ImGui positions are same as OS positions.
844944 if (io.WantSetMousePos)
845- glfwSetCursorPos(window, (double)io.MousePos.x, (double)io.MousePos.y);
945+ glfwSetCursorPos(window, (double)(mouse_pos_prev.x - viewport->Pos.x), (double)(mouse_pos_prev.y - viewport->Pos.y));
846946
847947 // (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured)
848948 if (bd->MouseWindow == nullptr)
849949 {
850950 double mouse_x, mouse_y;
851951 glfwGetCursorPos(window, &mouse_x, &mouse_y);
952+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
953+ {
954+ // 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)
955+ // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
956+ int window_x, window_y;
957+ glfwGetWindowPos(window, &window_x, &window_y);
958+ mouse_x += window_x;
959+ mouse_y += window_y;
960+ }
852961 bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y);
853962 io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
854963 }
855964 }
965+
966+ // (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
967+ // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic.
968+ // - [X] GLFW >= 3.3 backend ON WINDOWS ONLY does correctly ignore viewports with the _NoInputs flag (since we implement hit via our WndProc hook)
969+ // On other platforms we rely on the library fallbacking to its own search when reporting a viewport with _NoInputs flag.
970+ // - [!] GLFW <= 3.2 backend CANNOT correctly ignore viewports with the _NoInputs flag, and CANNOT reported Hovered Viewport because of mouse capture.
971+ // Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window
972+ // for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported
973+ // by the backend, and use its flawed heuristic to guess the viewport behind.
974+ // - [X] GLFW backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target).
975+ // FIXME: This is currently only correct on Win32. See what we do below with the WM_NCHITTEST, missing an equivalent for other systems.
976+ // See https://github.com/glfw/glfw/issues/1236 if you want to help in making this a GLFW feature.
977+#if GLFW_HAS_MOUSE_PASSTHROUGH
978+ const bool window_no_input = (viewport->Flags & ImGuiViewportFlags_NoInputs) != 0;
979+ glfwSetWindowAttrib(window, GLFW_MOUSE_PASSTHROUGH, window_no_input);
980+#endif
981+#if GLFW_HAS_MOUSE_PASSTHROUGH || GLFW_HAS_WINDOW_HOVERED
982+ if (glfwGetWindowAttrib(window, GLFW_HOVERED))
983+ mouse_viewport_id = viewport->ID;
984+#else
985+ // We cannot use bd->MouseWindow maintained from CursorEnter/Leave callbacks, because it is locked to the window capturing mouse.
986+#endif
856987 }
988+
989+ if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)
990+ io.AddMouseViewportEvent(mouse_viewport_id);
857991 }
858992
859993 static void ImGui_ImplGlfw_UpdateMouseCursor()
@@ -867,9 +1001,10 @@
8671001 }
8681002
8691003 ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
870- // (those braces are here to reduce diff with multi-viewports support in 'docking' branch)
1004+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
1005+ for (int n = 0; n < platform_io.Viewports.Size; n++)
8711006 {
872- GLFWwindow* window = bd->Window;
1007+ GLFWwindow* window = (GLFWwindow*)platform_io.Viewports[n]->PlatformHandle;
8731008 if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
8741009 {
8751010 if (bd->LastMouseCursor != nullptr)
@@ -949,6 +1084,49 @@
9491084 #undef MAP_ANALOG
9501085 }
9511086
1087+static void ImGui_ImplGlfw_UpdateMonitors()
1088+{
1089+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
1090+ int monitors_count = 0;
1091+ GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count);
1092+
1093+ bool updated_monitors = false;
1094+ for (int n = 0; n < monitors_count; n++)
1095+ {
1096+ ImGuiPlatformMonitor monitor;
1097+ int x, y;
1098+ glfwGetMonitorPos(glfw_monitors[n], &x, &y);
1099+ const GLFWvidmode* vid_mode = glfwGetVideoMode(glfw_monitors[n]);
1100+ if (vid_mode == nullptr)
1101+ continue; // Failed to get Video mode (e.g. Emscripten does not support this function)
1102+ if (vid_mode->width <= 0 || vid_mode->height <= 0)
1103+ continue; // Failed to query suitable monitor info (#9195)
1104+ monitor.MainPos = monitor.WorkPos = ImVec2((float)x, (float)y);
1105+ monitor.MainSize = monitor.WorkSize = ImVec2((float)vid_mode->width, (float)vid_mode->height);
1106+#if GLFW_HAS_MONITOR_WORK_AREA
1107+ int w, h;
1108+ glfwGetMonitorWorkarea(glfw_monitors[n], &x, &y, &w, &h);
1109+ if (w > 0 && h > 0) // Workaround a small GLFW issue reporting zero on monitor changes: https://github.com/glfw/glfw/pull/1761
1110+ {
1111+ monitor.WorkPos = ImVec2((float)x, (float)y);
1112+ monitor.WorkSize = ImVec2((float)w, (float)h);
1113+ }
1114+#endif
1115+ float scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfw_monitors[n]);
1116+ if (scale == 0.0f)
1117+ continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0 (#7902)
1118+ monitor.DpiScale = scale;
1119+ monitor.PlatformHandle = (void*)glfw_monitors[n]; // [...] GLFW doc states: "guaranteed to be valid only until the monitor configuration changes"
1120+
1121+ // Preserve existing monitor list until a valid one is added.
1122+ // Happens on macOS sleeping (#5683) and seemingly occasionally on Windows (#9195)
1123+ if (!updated_monitors)
1124+ platform_io.Monitors.resize(0);
1125+ updated_monitors = true;
1126+ platform_io.Monitors.push_back(monitor);
1127+ }
1128+}
1129+
9521130 // For GFLW 3.2 + Windows: include a simplified non-monitor aware version of ImGui_ImplWin32_GetDpiScaleForMonitor().
9531131 // This is merely a band-aid to make using GLFW 3.2 a little bit nicer, but prefer to use GLFW 3.3+ or the full correct functions from the Win32 backend.
9541132 #if !GLFW_HAS_PER_MONITOR_DPI && defined(_WIN32) && !defined(NOGDI)
@@ -1022,6 +1200,7 @@
10221200
10231201 // Setup main viewport size (every frame to accommodate for window resizing)
10241202 ImGui_ImplGlfw_GetWindowSizeAndFramebufferScale(bd->Window, &io.DisplaySize, &io.DisplayFramebufferScale);
1203+ ImGui_ImplGlfw_UpdateMonitors();
10251204
10261205 // Setup time step
10271206 // (Accept glfwGetTime() not returning a monotonically increasing value. Seems to happens on disconnecting peripherals and probably on VMs and Emscripten, see #6491, #6189, #6114, #3644)
@@ -1031,6 +1210,7 @@
10311210 io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
10321211 bd->Time = current_time;
10331212
1213+ bd->MouseIgnoreButtonUp = false;
10341214 ImGui_ImplGlfw_UpdateMouseData();
10351215 ImGui_ImplGlfw_UpdateMouseCursor();
10361216
@@ -1099,6 +1279,444 @@
10991279 emscripten_glfw_make_canvas_resizable(window, "window", nullptr);
11001280 }
11011281 #endif // #ifdef EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3
1282+
1283+
1284+//--------------------------------------------------------------------------------------------------------
1285+// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
1286+// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
1287+// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
1288+//--------------------------------------------------------------------------------------------------------
1289+
1290+// Helper structure we store in the void* PlatformUserData field of each ImGuiViewport to easily retrieve our backend data.
1291+struct ImGui_ImplGlfw_ViewportData
1292+{
1293+ GLFWwindow* Window; // Stored in ImGuiViewport::PlatformHandle
1294+ bool WindowOwned;
1295+ int IgnoreWindowPosEventFrame;
1296+ int IgnoreWindowSizeEventFrame;
1297+#ifdef _WIN32
1298+ WNDPROC PrevWndProc;
1299+#endif
1300+
1301+ ImGui_ImplGlfw_ViewportData() { memset((void*)this, 0, sizeof(*this)); IgnoreWindowSizeEventFrame = IgnoreWindowPosEventFrame = -1; }
1302+ ~ImGui_ImplGlfw_ViewportData() { IM_ASSERT(Window == nullptr); }
1303+};
1304+
1305+static void ImGui_ImplGlfw_WindowCloseCallback(GLFWwindow* window)
1306+{
1307+ if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
1308+ viewport->PlatformRequestClose = true;
1309+}
1310+
1311+// GLFW may dispatch window pos/size events after calling glfwSetWindowPos()/glfwSetWindowSize().
1312+// However: depending on the platform the callback may be invoked at different time:
1313+// - on Windows it appears to be called within the glfwSetWindowPos()/glfwSetWindowSize() call
1314+// - on Linux it is queued and invoked during glfwPollEvents()
1315+// Because the event doesn't always fire on glfwSetWindowXXX() we use a frame counter tag to only
1316+// ignore recent glfwSetWindowXXX() calls.
1317+static void ImGui_ImplGlfw_WindowPosCallback(GLFWwindow* window, int, int)
1318+{
1319+ if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
1320+ {
1321+ if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
1322+ {
1323+ bool ignore_event = (ImGui::GetFrameCount() <= vd->IgnoreWindowPosEventFrame + 1);
1324+ //data->IgnoreWindowPosEventFrame = -1;
1325+ if (ignore_event)
1326+ return;
1327+ }
1328+ viewport->PlatformRequestMove = true;
1329+ }
1330+}
1331+
1332+static void ImGui_ImplGlfw_WindowSizeCallback(GLFWwindow* window, int, int)
1333+{
1334+ if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
1335+ {
1336+ if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
1337+ {
1338+ bool ignore_event = (ImGui::GetFrameCount() <= vd->IgnoreWindowSizeEventFrame + 1);
1339+ //data->IgnoreWindowSizeEventFrame = -1;
1340+ if (ignore_event)
1341+ return;
1342+ }
1343+ viewport->PlatformRequestResize = true;
1344+ }
1345+}
1346+
1347+#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__EMSCRIPTEN__) && GLFW_HAS_GETPLATFORM
1348+#define IMGUI_GLFW_HAS_SETWINDOWFLOATING
1349+static void ImGui_ImplGlfw_SetWindowFloating(ImGui_ImplGlfw_Data* bd, GLFWwindow* window)
1350+{
1351+#ifdef GLFW_EXPOSE_NATIVE_X11
1352+ if (glfwGetPlatform() == GLFW_PLATFORM_X11)
1353+ {
1354+ Display* display = glfwGetX11Display();
1355+ Window xwindow = glfwGetX11Window(window);
1356+ Atom wm_type = bd->XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
1357+ Atom wm_type_dialog = bd->XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
1358+ bd->XChangeProperty(display, xwindow, wm_type, XA_ATOM, 32, PropModeReplace, (unsigned char*)&wm_type_dialog, 1);
1359+ XSetWindowAttributes attrs;
1360+ attrs.override_redirect = False;
1361+ bd->XChangeWindowAttributes(display, xwindow, CWOverrideRedirect, &attrs);
1362+ bd->XFlush(display);
1363+ }
1364+#endif // GLFW_EXPOSE_NATIVE_X11
1365+#ifdef GLFW_EXPOSE_NATIVE_WAYLAND
1366+ // FIXME: Help needed, see #8884, #8474 for discussions about this.
1367+#endif // GLFW_EXPOSE_NATIVE_X11
1368+}
1369+#endif // IMGUI_GLFW_HAS_SETWINDOWFLOATING
1370+
1371+static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport)
1372+{
1373+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
1374+ ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)();
1375+ viewport->PlatformUserData = vd;
1376+
1377+ // Workaround for Linux: ignore mouse up events corresponding to losing focus of the previously focused window (#7733, #3158, #7922)
1378+#ifdef __linux__
1379+ bd->MouseIgnoreButtonUpWaitForFocusLoss = true;
1380+#endif
1381+
1382+ // GLFW 3.2 unfortunately always set focus on glfwCreateWindow() if GLFW_VISIBLE is set, regardless of GLFW_FOCUSED
1383+ // With GLFW 3.3, the hint GLFW_FOCUS_ON_SHOW fixes this problem
1384+ glfwWindowHint(GLFW_VISIBLE, false);
1385+ glfwWindowHint(GLFW_FOCUSED, false);
1386+#if GLFW_HAS_FOCUS_ON_SHOW
1387+ glfwWindowHint(GLFW_FOCUS_ON_SHOW, false);
1388+#endif
1389+ glfwWindowHint(GLFW_DECORATED, (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? false : true);
1390+#if GLFW_HAS_WINDOW_TOPMOST
1391+ glfwWindowHint(GLFW_FLOATING, (viewport->Flags & ImGuiViewportFlags_TopMost) ? true : false);
1392+#endif
1393+ GLFWwindow* share_window = (bd->ClientApi == GlfwClientApi_OpenGL) ? bd->Window : nullptr;
1394+ vd->Window = glfwCreateWindow((int)viewport->Size.x, (int)viewport->Size.y, "No Title Yet", nullptr, share_window);
1395+ vd->WindowOwned = true;
1396+ ImGui_ImplGlfw_ContextMap_Add(vd->Window, bd->Context);
1397+ viewport->PlatformHandle = (void*)vd->Window;
1398+#ifdef IMGUI_GLFW_HAS_SETWINDOWFLOATING
1399+ ImGui_ImplGlfw_SetWindowFloating(bd, vd->Window);
1400+#endif
1401+#ifdef _WIN32
1402+ viewport->PlatformHandleRaw = glfwGetWin32Window(vd->Window);
1403+ ::SetPropA((HWND)viewport->PlatformHandleRaw, "IMGUI_BACKEND_DATA", bd);
1404+#elif defined(__APPLE__)
1405+ viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(vd->Window);
1406+#endif
1407+ glfwSetWindowPos(vd->Window, (int)viewport->Pos.x, (int)viewport->Pos.y);
1408+
1409+ // Install GLFW callbacks for secondary viewports
1410+ glfwSetWindowFocusCallback(vd->Window, ImGui_ImplGlfw_WindowFocusCallback);
1411+ glfwSetCursorEnterCallback(vd->Window, ImGui_ImplGlfw_CursorEnterCallback);
1412+ glfwSetCursorPosCallback(vd->Window, ImGui_ImplGlfw_CursorPosCallback);
1413+ glfwSetMouseButtonCallback(vd->Window, ImGui_ImplGlfw_MouseButtonCallback);
1414+ glfwSetScrollCallback(vd->Window, ImGui_ImplGlfw_ScrollCallback);
1415+ glfwSetKeyCallback(vd->Window, ImGui_ImplGlfw_KeyCallback);
1416+ glfwSetCharCallback(vd->Window, ImGui_ImplGlfw_CharCallback);
1417+ glfwSetWindowCloseCallback(vd->Window, ImGui_ImplGlfw_WindowCloseCallback);
1418+ glfwSetWindowPosCallback(vd->Window, ImGui_ImplGlfw_WindowPosCallback);
1419+ glfwSetWindowSizeCallback(vd->Window, ImGui_ImplGlfw_WindowSizeCallback);
1420+ if (bd->ClientApi == GlfwClientApi_OpenGL)
1421+ {
1422+ glfwMakeContextCurrent(vd->Window);
1423+ glfwSwapInterval(0);
1424+ }
1425+}
1426+
1427+static void ImGui_ImplGlfw_DestroyWindow(ImGuiViewport* viewport)
1428+{
1429+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
1430+ if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
1431+ {
1432+ if (vd->WindowOwned)
1433+ {
1434+#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)
1435+ HWND hwnd = (HWND)viewport->PlatformHandleRaw;
1436+ ::RemovePropA(hwnd, "IMGUI_VIEWPORT");
1437+#endif
1438+
1439+ // Release any keys that were pressed in the window being destroyed and are still held down,
1440+ // because we will not receive any release events after window is destroyed.
1441+ for (int i = 0; i < IM_COUNTOF(bd->KeyOwnerWindows); i++)
1442+ if (bd->KeyOwnerWindows[i] == vd->Window)
1443+ ImGui_ImplGlfw_KeyCallback(vd->Window, i, 0, GLFW_RELEASE, 0); // Later params are only used for main viewport, on which this function is never called.
1444+
1445+ ImGui_ImplGlfw_ContextMap_Remove(vd->Window);
1446+ glfwDestroyWindow(vd->Window);
1447+ }
1448+ vd->Window = nullptr;
1449+ IM_DELETE(vd);
1450+ }
1451+ viewport->PlatformUserData = viewport->PlatformHandle = nullptr;
1452+}
1453+
1454+static void ImGui_ImplGlfw_ShowWindow(ImGuiViewport* viewport)
1455+{
1456+ ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
1457+
1458+#if defined(_WIN32)
1459+ // GLFW hack: Hide icon from task bar
1460+ HWND hwnd = (HWND)viewport->PlatformHandleRaw;
1461+ if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon)
1462+ {
1463+ LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
1464+ ex_style &= ~WS_EX_APPWINDOW;
1465+ ex_style |= WS_EX_TOOLWINDOW;
1466+ ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
1467+ }
1468+
1469+ // GLFW hack: install WndProc for mouse source event and WM_NCHITTEST message handler.
1470+ ::SetPropA(hwnd, "IMGUI_VIEWPORT", viewport);
1471+ vd->PrevWndProc = (WNDPROC)::GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
1472+ ::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc);
1473+
1474+#if !GLFW_HAS_FOCUS_ON_SHOW
1475+ // GLFW hack: GLFW 3.2 has a bug where glfwShowWindow() also activates/focus the window.
1476+ // The fix was pushed to GLFW repository on 2018/01/09 and should be included in GLFW 3.3 via a GLFW_FOCUS_ON_SHOW window attribute.
1477+ // See https://github.com/glfw/glfw/issues/1189
1478+ // FIXME-VIEWPORT: Implement same work-around for Linux/OSX in the meanwhile.
1479+ if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
1480+ {
1481+ ::ShowWindow(hwnd, SW_SHOWNA);
1482+ return;
1483+ }
1484+#endif
1485+#endif
1486+
1487+ glfwShowWindow(vd->Window);
1488+}
1489+
1490+static ImVec2 ImGui_ImplGlfw_GetWindowPos(ImGuiViewport* viewport)
1491+{
1492+ ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
1493+ int x = 0, y = 0;
1494+ glfwGetWindowPos(vd->Window, &x, &y);
1495+ return ImVec2((float)x, (float)y);
1496+}
1497+
1498+static void ImGui_ImplGlfw_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
1499+{
1500+ ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
1501+ vd->IgnoreWindowPosEventFrame = ImGui::GetFrameCount();
1502+ glfwSetWindowPos(vd->Window, (int)pos.x, (int)pos.y);
1503+}
1504+
1505+static ImVec2 ImGui_ImplGlfw_GetWindowSize(ImGuiViewport* viewport)
1506+{
1507+ ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
1508+ int w = 0, h = 0;
1509+ glfwGetWindowSize(vd->Window, &w, &h);
1510+ return ImVec2((float)w, (float)h);
1511+}
1512+
1513+static void ImGui_ImplGlfw_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
1514+{
1515+ ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
1516+#if defined(__APPLE__) && !GLFW_HAS_OSX_WINDOW_POS_FIX
1517+ // Native OS windows are positioned from the bottom-left corner on macOS, whereas on other platforms they are
1518+ // positioned from the upper-left corner. GLFW makes an effort to convert macOS style coordinates, however it
1519+ // doesn't handle it when changing size. We are manually moving the window in order for changes of size to be based
1520+ // on the upper-left corner.
1521+ int x, y, width, height;
1522+ glfwGetWindowPos(vd->Window, &x, &y);
1523+ glfwGetWindowSize(vd->Window, &width, &height);
1524+ glfwSetWindowPos(vd->Window, x, y - height + size.y);
1525+#endif
1526+ vd->IgnoreWindowSizeEventFrame = ImGui::GetFrameCount();
1527+ glfwSetWindowSize(vd->Window, (int)size.x, (int)size.y);
1528+}
1529+
1530+static ImVec2 ImGui_ImplGlfw_GetWindowFramebufferScale(ImGuiViewport* viewport)
1531+{
1532+ ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
1533+ ImVec2 framebuffer_scale;
1534+ ImGui_ImplGlfw_GetWindowSizeAndFramebufferScale(vd->Window, nullptr, &framebuffer_scale);
1535+ return framebuffer_scale;
1536+}
1537+
1538+static void ImGui_ImplGlfw_SetWindowTitle(ImGuiViewport* viewport, const char* title)
1539+{
1540+ ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
1541+ glfwSetWindowTitle(vd->Window, title);
1542+}
1543+
1544+static void ImGui_ImplGlfw_SetWindowFocus(ImGuiViewport* viewport)
1545+{
1546+#if GLFW_HAS_FOCUS_WINDOW
1547+ ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
1548+ glfwFocusWindow(vd->Window);
1549+#else
1550+ // FIXME: What are the effect of not having this function? At the moment imgui doesn't actually call SetWindowFocus - we set that up ahead, will answer that question later.
1551+ (void)viewport;
1552+#endif
1553+}
1554+
1555+static bool ImGui_ImplGlfw_GetWindowFocus(ImGuiViewport* viewport)
1556+{
1557+ ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
1558+ return glfwGetWindowAttrib(vd->Window, GLFW_FOCUSED) != 0;
1559+}
1560+
1561+static bool ImGui_ImplGlfw_GetWindowMinimized(ImGuiViewport* viewport)
1562+{
1563+ ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
1564+ return glfwGetWindowAttrib(vd->Window, GLFW_ICONIFIED) != 0;
1565+}
1566+
1567+#if GLFW_HAS_WINDOW_ALPHA
1568+static void ImGui_ImplGlfw_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
1569+{
1570+ ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
1571+ glfwSetWindowOpacity(vd->Window, alpha);
1572+}
1573+#endif
1574+
1575+static void ImGui_ImplGlfw_RenderWindow(ImGuiViewport* viewport, void*)
1576+{
1577+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
1578+ ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
1579+ if (bd->ClientApi == GlfwClientApi_OpenGL)
1580+ glfwMakeContextCurrent(vd->Window);
1581+}
1582+
1583+static void ImGui_ImplGlfw_SwapBuffers(ImGuiViewport* viewport, void*)
1584+{
1585+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
1586+ ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
1587+ if (bd->ClientApi == GlfwClientApi_OpenGL)
1588+ {
1589+ glfwMakeContextCurrent(vd->Window);
1590+ glfwSwapBuffers(vd->Window);
1591+ }
1592+}
1593+
1594+//--------------------------------------------------------------------------------------------------------
1595+// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface)
1596+//--------------------------------------------------------------------------------------------------------
1597+
1598+// Avoid including <vulkan.h> so we can build without it
1599+#if GLFW_HAS_VULKAN
1600+#ifndef VULKAN_H_
1601+#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
1602+#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
1603+#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
1604+#else
1605+#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
1606+#endif
1607+VK_DEFINE_HANDLE(VkInstance)
1608+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR)
1609+struct VkAllocationCallbacks;
1610+enum VkResult { VK_RESULT_MAX_ENUM = 0x7FFFFFFF };
1611+#endif // VULKAN_H_
1612+extern "C" { extern GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); }
1613+static int ImGui_ImplGlfw_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface)
1614+{
1615+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
1616+ ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
1617+ IM_UNUSED(bd);
1618+ IM_ASSERT(bd->ClientApi == GlfwClientApi_Vulkan);
1619+ VkResult err = glfwCreateWindowSurface((VkInstance)vk_instance, vd->Window, (const VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface);
1620+ return (int)err;
1621+}
1622+#endif // GLFW_HAS_VULKAN
1623+
1624+static void ImGui_ImplGlfw_InitMultiViewportSupport()
1625+{
1626+ // Register platform interface (will be coupled with a renderer interface)
1627+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
1628+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
1629+ platform_io.Platform_CreateWindow = ImGui_ImplGlfw_CreateWindow;
1630+ platform_io.Platform_DestroyWindow = ImGui_ImplGlfw_DestroyWindow;
1631+ platform_io.Platform_ShowWindow = ImGui_ImplGlfw_ShowWindow;
1632+ platform_io.Platform_SetWindowPos = ImGui_ImplGlfw_SetWindowPos;
1633+ platform_io.Platform_GetWindowPos = ImGui_ImplGlfw_GetWindowPos;
1634+ platform_io.Platform_SetWindowSize = ImGui_ImplGlfw_SetWindowSize;
1635+ platform_io.Platform_GetWindowSize = ImGui_ImplGlfw_GetWindowSize;
1636+ platform_io.Platform_GetWindowFramebufferScale = ImGui_ImplGlfw_GetWindowFramebufferScale;
1637+ platform_io.Platform_SetWindowFocus = ImGui_ImplGlfw_SetWindowFocus;
1638+ platform_io.Platform_GetWindowFocus = ImGui_ImplGlfw_GetWindowFocus;
1639+ platform_io.Platform_GetWindowMinimized = ImGui_ImplGlfw_GetWindowMinimized;
1640+ platform_io.Platform_SetWindowTitle = ImGui_ImplGlfw_SetWindowTitle;
1641+ platform_io.Platform_RenderWindow = ImGui_ImplGlfw_RenderWindow;
1642+ platform_io.Platform_SwapBuffers = ImGui_ImplGlfw_SwapBuffers;
1643+#if GLFW_HAS_WINDOW_ALPHA
1644+ platform_io.Platform_SetWindowAlpha = ImGui_ImplGlfw_SetWindowAlpha;
1645+#endif
1646+#if GLFW_HAS_VULKAN
1647+ platform_io.Platform_CreateVkSurface = ImGui_ImplGlfw_CreateVkSurface;
1648+#endif
1649+
1650+ // Register main window handle (which is owned by the main application, not by us)
1651+ // This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
1652+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
1653+ ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)();
1654+ vd->Window = bd->Window;
1655+ vd->WindowOwned = false;
1656+ main_viewport->PlatformUserData = vd;
1657+ main_viewport->PlatformHandle = (void*)bd->Window;
1658+}
1659+
1660+static void ImGui_ImplGlfw_ShutdownMultiViewportSupport()
1661+{
1662+ ImGui::DestroyPlatformWindows();
1663+}
1664+
1665+//-----------------------------------------------------------------------------
1666+
1667+// WndProc hook (declared here because we will need access to ImGui_ImplGlfw_ViewportData)
1668+#ifdef _WIN32
1669+static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo()
1670+{
1671+ LPARAM extra_info = ::GetMessageExtraInfo();
1672+ if ((extra_info & 0xFFFFFF80) == 0xFF515700)
1673+ return ImGuiMouseSource_Pen;
1674+ if ((extra_info & 0xFFFFFF80) == 0xFF515780)
1675+ return ImGuiMouseSource_TouchScreen;
1676+ return ImGuiMouseSource_Mouse;
1677+}
1678+static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1679+{
1680+ ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)::GetPropA(hWnd, "IMGUI_BACKEND_DATA");
1681+ ImGuiIO& io = ImGui::GetIO(bd->Context);
1682+
1683+ WNDPROC prev_wndproc = bd->PrevWndProc;
1684+ ImGuiViewport* viewport = (ImGuiViewport*)::GetPropA(hWnd, "IMGUI_VIEWPORT");
1685+ if (viewport != NULL)
1686+ if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
1687+ prev_wndproc = vd->PrevWndProc;
1688+
1689+ switch (msg)
1690+ {
1691+ // GLFW doesn't allow to distinguish Mouse vs TouchScreen vs Pen.
1692+ // Add support for Win32 (based on imgui_impl_win32), because we rely on _TouchScreen info to trickle inputs differently.
1693+ case WM_MOUSEMOVE: case WM_NCMOUSEMOVE:
1694+ case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_LBUTTONUP:
1695+ case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_RBUTTONUP:
1696+ case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_MBUTTONUP:
1697+ case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: case WM_XBUTTONUP:
1698+ io.AddMouseSourceEvent(GetMouseSourceFromMessageExtraInfo());
1699+ break;
1700+
1701+ // We have submitted https://github.com/glfw/glfw/pull/1568 to allow GLFW to support "transparent inputs".
1702+ // In the meanwhile we implement custom per-platform workarounds here (FIXME-VIEWPORT: Implement same work-around for Linux/OSX!)
1703+#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED
1704+ case WM_NCHITTEST:
1705+ {
1706+ // Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() properly (which is OPTIONAL).
1707+ // The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
1708+ // If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
1709+ // your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
1710+ if (viewport && (viewport->Flags & ImGuiViewportFlags_NoInputs))
1711+ return HTTRANSPARENT;
1712+ break;
1713+ }
1714+#endif
1715+ default: break;
1716+ }
1717+ return ::CallWindowProcW(prev_wndproc, hWnd, msg, wParam, lParam);
1718+}
1719+#endif // #ifdef _WIN32
11021720
11031721 //-----------------------------------------------------------------------------
11041722
@@ -9,10 +9,12 @@
99 // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5]
1010 // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
1111 // [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'.
12+// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
1213 // [X] Multiple Dear ImGui contexts support.
1314 // Missing features or Issues:
1415 // [ ] 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.
1516 // [ ] Platform: Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors.
17+// [ ] Platform: Multi-viewport: Missing ImGuiBackendFlags_HasParentViewport support. The viewport->ParentViewportID field is ignored, and therefore io.ConfigViewportsNoDefaultParent has no effect either.
1618
1719 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1820 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -13,6 +13,7 @@
1313 // [ ] Platform: Missing mouse cursor shape/visibility support.
1414 // [ ] Platform: Missing clipboard support (not supported by Glut).
1515 // [ ] Platform: Missing gamepad support.
16+// [ ] Platform: Missing multi-viewport support (multiple windows).
1617
1718 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1819 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -13,6 +13,7 @@
1313 // [ ] Platform: Missing mouse cursor shape/visibility support.
1414 // [ ] Platform: Missing clipboard support (not supported by Glut).
1515 // [ ] Platform: Missing gamepad support.
16+// [ ] Platform: Missing multi-viewport support (multiple windows).
1617
1718 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1819 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -5,6 +5,7 @@
55 // [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
66 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
77 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
8+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
89
910 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1011 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -5,6 +5,7 @@
55 // [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
66 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
77 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
8+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
89
910 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1011 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -16,6 +17,7 @@
1617
1718 // CHANGELOG
1819 // (minor and older changes stripped away, please see git history for details)
20+// 2026-XX-XX: Metal: Added support for multiple windows via the ImGuiPlatformIO interface.
1921 // 2026-04-28: Added support for standard draw callbacks (in platform_io): DrawCallback_SetSamplerLinear and DrawCallback_SetSamplerNearest. (#9378, #9381)
2022 // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others are not yet supported). (#9378)
2123 // 2026-04-14: Metal: use a dedicated bufferCacheLock to avoid crashing when bufferCache is replaced by a new object while being used for @synchronize(). (#9367)
@@ -48,6 +50,12 @@
4850 #import <time.h>
4951 #import <Metal/Metal.h>
5052
53+// Forward Declarations
54+static void ImGui_ImplMetal_InitMultiViewportSupport();
55+static void ImGui_ImplMetal_ShutdownMultiViewportSupport();
56+static void ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows();
57+static void ImGui_ImplMetal_InvalidateDeviceObjectsForPlatformWindows();
58+
5159 #pragma mark - Support classes
5260
5361 // A wrapper around a MTLBuffer object that knows the last time it was reused
@@ -398,6 +406,8 @@
398406 samplerDescriptor.magFilter = MTLSamplerMinMagFilterNearest;
399407 samplerDescriptor.mipFilter = MTLSamplerMipFilterNearest;
400408 bd->SharedMetalContext.samplerStateNearest = [device newSamplerStateWithDescriptor:samplerDescriptor];
409+
410+ ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows();
401411 #ifdef IMGUI_IMPL_METAL_CPP
402412 [samplerDescriptor release];
403413 [depthStencilDescriptor release];
@@ -415,6 +425,7 @@
415425 if (tex->RefCount == 1)
416426 ImGui_ImplMetal_DestroyTexture(tex);
417427
428+ ImGui_ImplMetal_InvalidateDeviceObjectsForPlatformWindows();
418429 [bd->SharedMetalContext.renderPipelineStateCache removeAllObjects];
419430 bd->SharedMetalContext.samplerStateLinear = nil;
420431 bd->SharedMetalContext.samplerStateNearest = nil;
@@ -431,6 +442,7 @@
431442 io.BackendRendererName = "imgui_impl_metal";
432443 io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
433444 io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
445+ io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
434446
435447 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
436448 platform_io.DrawCallback_ResetRenderState = ImGui_ImplMetal_DrawCallback_ResetRenderState;
@@ -440,6 +452,8 @@
440452 bd->SharedMetalContext = [[MetalContext alloc] init];
441453 bd->SharedMetalContext.device = device;
442454
455+ ImGui_ImplMetal_InitMultiViewportSupport();
456+
443457 return true;
444458 }
445459
@@ -451,13 +465,158 @@
451465 ImGuiIO& io = ImGui::GetIO();
452466 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
453467
468+ ImGui_ImplMetal_ShutdownMultiViewportSupport();
454469 ImGui_ImplMetal_DestroyDeviceObjects();
455470 ImGui_ImplMetal_DestroyBackendData();
456471
457472 io.BackendRendererName = nullptr;
458473 io.BackendRendererUserData = nullptr;
459- io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
474+ io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
460475 platform_io.ClearRendererHandlers();
476+}
477+
478+#pragma mark - Multi-viewport support
479+
480+#import <QuartzCore/CAMetalLayer.h>
481+
482+#if TARGET_OS_OSX
483+#import <Cocoa/Cocoa.h>
484+#endif
485+
486+//--------------------------------------------------------------------------------------------------------
487+// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
488+// This is an _advanced_ and _optional_ feature, allowing the back-end to create and handle multiple viewports simultaneously.
489+// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
490+//--------------------------------------------------------------------------------------------------------
491+
492+struct ImGuiViewportDataMetal
493+{
494+ CAMetalLayer* MetalLayer;
495+ id<MTLCommandQueue> CommandQueue;
496+ MTLRenderPassDescriptor* RenderPassDescriptor;
497+ void* Handle = nullptr;
498+ bool FirstFrame = true;
499+};
500+
501+static void ImGui_ImplMetal_CreateWindow(ImGuiViewport* viewport)
502+{
503+ ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
504+ ImGuiViewportDataMetal* data = IM_NEW(ImGuiViewportDataMetal)();
505+ viewport->RendererUserData = data;
506+
507+ // PlatformHandleRaw should always be a NSWindow*, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
508+ // Some back-ends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the NSWindow*.
509+ void* handle = viewport->PlatformHandleRaw ? viewport->PlatformHandleRaw : viewport->PlatformHandle;
510+ IM_ASSERT(handle != nullptr);
511+
512+ id<MTLDevice> device = bd->SharedMetalContext.device;
513+ CAMetalLayer* layer = [CAMetalLayer layer];
514+ layer.device = device;
515+ layer.framebufferOnly = YES;
516+ layer.pixelFormat = bd->SharedMetalContext.framebufferDescriptor.colorPixelFormat;
517+#if TARGET_OS_OSX
518+ NSWindow* window = (__bridge NSWindow*)handle;
519+ NSView* view = window.contentView;
520+ view.layer = layer;
521+ view.wantsLayer = YES;
522+#endif
523+ data->MetalLayer = layer;
524+ data->CommandQueue = [device newCommandQueue];
525+ data->RenderPassDescriptor = [[MTLRenderPassDescriptor alloc] init];
526+ data->Handle = handle;
527+}
528+
529+static void ImGui_ImplMetal_DestroyWindow(ImGuiViewport* viewport)
530+{
531+ // The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it.
532+ if (ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)viewport->RendererUserData)
533+ IM_DELETE(data);
534+ viewport->RendererUserData = nullptr;
535+}
536+
537+inline static CGSize MakeScaledSize(CGSize size, CGFloat scale)
538+{
539+ return CGSizeMake(size.width * scale, size.height * scale);
540+}
541+
542+static void ImGui_ImplMetal_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
543+{
544+ ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)viewport->RendererUserData;
545+ data->MetalLayer.drawableSize = MakeScaledSize(CGSizeMake(size.x, size.y), viewport->DpiScale);
546+}
547+
548+static void ImGui_ImplMetal_RenderWindow(ImGuiViewport* viewport, void*)
549+{
550+ ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)viewport->RendererUserData;
551+
552+#if TARGET_OS_OSX
553+ void* handle = viewport->PlatformHandleRaw ? viewport->PlatformHandleRaw : viewport->PlatformHandle;
554+ NSWindow* window = (__bridge NSWindow*)handle;
555+
556+ // Always render the first frame, regardless of occlusionState, to avoid an initial flicker
557+ if ((window.occlusionState & NSWindowOcclusionStateVisible) == 0 && !data->FirstFrame)
558+ {
559+ // Do not render windows which are completely occluded. Calling -[CAMetalLayer nextDrawable] will hang for
560+ // approximately 1 second if the Metal layer is completely occluded.
561+ return;
562+ }
563+ data->FirstFrame = false;
564+
565+ float fb_scale = (float)window.backingScaleFactor;
566+ if (data->MetalLayer.contentsScale != fb_scale)
567+ {
568+ data->MetalLayer.contentsScale = fb_scale;
569+ data->MetalLayer.drawableSize = MakeScaledSize(window.frame.size, fb_scale);
570+ }
571+#endif
572+
573+ id <CAMetalDrawable> drawable = [data->MetalLayer nextDrawable];
574+ if (drawable == nil)
575+ return;
576+
577+ MTLRenderPassDescriptor* renderPassDescriptor = data->RenderPassDescriptor;
578+ renderPassDescriptor.colorAttachments[0].texture = drawable.texture;
579+ renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 0);
580+ if ((viewport->Flags & ImGuiViewportFlags_NoRendererClear) == 0)
581+ renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
582+
583+ id <MTLCommandBuffer> commandBuffer = [data->CommandQueue commandBuffer];
584+ id <MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
585+ ImGui_ImplMetal_RenderDrawData(viewport->DrawData, commandBuffer, renderEncoder);
586+ [renderEncoder endEncoding];
587+
588+ [commandBuffer presentDrawable:drawable];
589+ [commandBuffer commit];
590+}
591+
592+static void ImGui_ImplMetal_InitMultiViewportSupport()
593+{
594+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
595+ platform_io.Renderer_CreateWindow = ImGui_ImplMetal_CreateWindow;
596+ platform_io.Renderer_DestroyWindow = ImGui_ImplMetal_DestroyWindow;
597+ platform_io.Renderer_SetWindowSize = ImGui_ImplMetal_SetWindowSize;
598+ platform_io.Renderer_RenderWindow = ImGui_ImplMetal_RenderWindow;
599+}
600+
601+static void ImGui_ImplMetal_ShutdownMultiViewportSupport()
602+{
603+ ImGui::DestroyPlatformWindows();
604+}
605+
606+static void ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows()
607+{
608+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
609+ for (int i = 1; i < platform_io.Viewports.Size; i++)
610+ if (!platform_io.Viewports[i]->RendererUserData)
611+ ImGui_ImplMetal_CreateWindow(platform_io.Viewports[i]);
612+}
613+
614+static void ImGui_ImplMetal_InvalidateDeviceObjectsForPlatformWindows()
615+{
616+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
617+ for (int i = 1; i < platform_io.Viewports.Size; i++)
618+ if (platform_io.Viewports[i]->RendererUserData)
619+ ImGui_ImplMetal_DestroyWindow(platform_io.Viewports[i]);
461620 }
462621
463622 #pragma mark - MetalBuffer implementation
@@ -4,6 +4,7 @@
44 // Implemented features:
55 // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
66 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
7+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
78 // Missing features or Issues:
89 // [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
910 // [ ] Renderer: Use of DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest is emulated by poking to glTexParameter(), as legacy OpenGL doesn't have glBindSampler().
@@ -26,6 +27,7 @@
2627
2728 // CHANGELOG
2829 // (minor and older changes stripped away, please see git history for details)
30+// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
2931 // 2026-04-23: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
3032 // 2026-03-12: OpenGL: Fixed invalid assert in ImGui_ImplOpenGL3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295)
3133 // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
@@ -101,6 +103,10 @@
101103 return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
102104 }
103105
106+// Forward Declarations
107+static void ImGui_ImplOpenGL2_InitMultiViewportSupport();
108+static void ImGui_ImplOpenGL2_ShutdownMultiViewportSupport();
109+
104110 // Functions
105111 void ImGui_ImplOpenGL2_NewFrame()
106112 {
@@ -346,7 +352,10 @@
346352 io.BackendRendererUserData = (void*)bd;
347353 io.BackendRendererName = "imgui_impl_opengl2";
348354 io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
355+ io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
349356
357+ ImGui_ImplOpenGL2_InitMultiViewportSupport();
358+
350359 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
351360 platform_io.DrawCallback_ResetRenderState = ImGui_ImplOpenGL2_DrawCallback_ResetRenderState;
352361 platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplOpenGL2_DrawCallback_SetSamplerLinear;
@@ -362,13 +371,42 @@
362371 ImGuiIO& io = ImGui::GetIO();
363372 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
364373
374+ ImGui_ImplOpenGL2_ShutdownMultiViewportSupport();
365375 ImGui_ImplOpenGL2_DestroyDeviceObjects();
366376
367377 io.BackendRendererName = nullptr;
368378 io.BackendRendererUserData = nullptr;
369- io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasTextures);
379+ io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
370380 platform_io.ClearRendererHandlers();
371381 IM_DELETE(bd);
382+}
383+
384+//--------------------------------------------------------------------------------------------------------
385+// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
386+// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
387+// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
388+//--------------------------------------------------------------------------------------------------------
389+
390+static void ImGui_ImplOpenGL2_RenderWindow(ImGuiViewport* viewport, void*)
391+{
392+ if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
393+ {
394+ ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
395+ glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
396+ glClear(GL_COLOR_BUFFER_BIT);
397+ }
398+ ImGui_ImplOpenGL2_RenderDrawData(viewport->DrawData);
399+}
400+
401+static void ImGui_ImplOpenGL2_InitMultiViewportSupport()
402+{
403+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
404+ platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL2_RenderWindow;
405+}
406+
407+static void ImGui_ImplOpenGL2_ShutdownMultiViewportSupport()
408+{
409+ ImGui::DestroyPlatformWindows();
372410 }
373411
374412 //-----------------------------------------------------------------------------
@@ -4,6 +4,7 @@
44 // Implemented features:
55 // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
66 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
7+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
78 // Missing features or Issues:
89 // [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
910 // [ ] Renderer: Use of DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest is emulated by poking to glTexParameter(), as legacy OpenGL doesn't have glBindSampler().
@@ -7,6 +7,7 @@
77 // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
88 // [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!]
99 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
10+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
1011
1112 // About WebGL/ES:
1213 // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
@@ -23,7 +24,11 @@
2324
2425 // CHANGELOG
2526 // (minor and older changes stripped away, please see git history for details)
27+// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
28+// 2026-06-17: OpenGL: Expose selected render state in ImGui_ImplOpenGL3_RenderState, Allowing to dynamically select between use of glBindSampler() and glTexParameter(). You can access in 'void* platform_io.Renderer_RenderState' during rendering.
29+// 2026-06-03: OpenGL: GLSL version detection assume GLSL 410 when GL context is 4.1. Fixes an issue running on macOS with Wine. (#9427, #6577)
2630 // 2026-04-23: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
31+// (Breaking): this change prioritize using glBindSampler() when available, which would override glTexParameter() settings you may have set on custom textures.
2732 // 2026-03-12: OpenGL: Fixed invalid assert in ImGui_ImplOpenGL3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295)
2833 // 2025-12-11: OpenGL: Fixed embedded loader multiple init/shutdown cycles broken on some platforms. (#8792, #9112)
2934 // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
@@ -253,8 +258,6 @@
253258 bool HasBindSampler;
254259 bool HasClipOrigin;
255260 bool UseBufferSubData;
256- bool UseTexParameterToSetSampler;
257- GLuint NextSampler; // Used if !HasBindSampler && UseTexParameterToSetSampler.
258261 #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
259262 GLuint TexSamplers[2]; // Used if HasBindSimpler. (0=linear, 1=nearest)
260263 #endif
@@ -271,6 +274,10 @@
271274 return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
272275 }
273276
277+// Forward Declarations
278+static void ImGui_ImplOpenGL3_InitMultiViewportSupport();
279+static void ImGui_ImplOpenGL3_ShutdownMultiViewportSupport();
280+
274281 // OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only)
275282 #ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
276283 struct ImGui_ImplOpenGL3_VtxAttribState
@@ -330,7 +337,7 @@
330337 IM_ASSERT(0 && "ImGui_ImplOpenGL3_CreateDeviceObjects() failed!");
331338 }
332339
333-static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
340+static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, ImGui_ImplOpenGL3_RenderState* render_state, int fb_width, int fb_height, GLuint vertex_array_object)
334341 {
335342 ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
336343
@@ -384,8 +391,11 @@
384391 glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
385392
386393 #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
387- if (bd->HasBindSampler)
388- glBindSampler(0, bd->TexSamplers[0]); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise.
394+ if (render_state->UseBindSampler)
395+ {
396+ render_state->CurrentSampler = bd->TexSamplers[0];
397+ glBindSampler(0, render_state->CurrentSampler); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise.
398+ }
389399 #endif
390400
391401 (void)vertex_array_object;
@@ -406,13 +416,42 @@
406416
407417 // Draw callbacks
408418 static void ImGui_ImplOpenGL3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
419+static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*)
420+{
421+ ImGui_ImplOpenGL3_RenderState* render_state = ImGui_ImplOpenGL3_GetRenderState();
409422 #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
410-static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->HasBindSampler) { glBindSampler(0, bd->TexSamplers[0]); } else { bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_LINEAR; } }
411-static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->HasBindSampler) { glBindSampler(0, bd->TexSamplers[1]); } else { bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_NEAREST; } }
412-#else
413-static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_LINEAR; }
414-static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_NEAREST; }
423+ ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
424+ if (bd->HasBindSampler)
425+ {
426+ render_state->CurrentSampler = bd->TexSamplers[0];
427+ render_state->UseTexParameterFilter = false;
428+ glBindSampler(0, render_state->CurrentSampler);
429+ }
430+ else
415431 #endif
432+ {
433+ render_state->UseTexParameterFilter = true;
434+ render_state->CurrentTexParameterFilter = GL_LINEAR;
435+ }
436+}
437+static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*)
438+{
439+ ImGui_ImplOpenGL3_RenderState* render_state = ImGui_ImplOpenGL3_GetRenderState();
440+#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
441+ ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
442+ if (bd->HasBindSampler)
443+ {
444+ render_state->CurrentSampler = bd->TexSamplers[1];
445+ render_state->UseTexParameterFilter = false;
446+ glBindSampler(0, render_state->CurrentSampler);
447+ }
448+ else
449+#endif
450+ {
451+ render_state->UseTexParameterFilter = true;
452+ render_state->CurrentTexParameterFilter = GL_NEAREST;
453+ }
454+}
416455
417456 // OpenGL3 Render function.
418457 // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
@@ -482,8 +521,18 @@
482521 #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
483522 GL_CALL(glGenVertexArrays(1, &vertex_array_object));
484523 #endif
485- ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
486524
525+ // Setup render state structure (for callbacks and custom texture bindings)
526+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
527+ ImGui_ImplOpenGL3_RenderState render_state;
528+ render_state.UseBindSampler = bd->HasBindSampler;
529+ render_state.UseTexParameterFilter = false;
530+ render_state.CurrentSampler = 0;
531+ render_state.CurrentTexParameterFilter = 0;
532+ platform_io.Renderer_RenderState = &render_state;
533+
534+ ImGui_ImplOpenGL3_SetupRenderState(draw_data, &render_state, fb_width, fb_height, vertex_array_object);
535+
487536 // Will project scissor/clipping rectangles into framebuffer space
488537 ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
489538 ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
@@ -529,7 +578,7 @@
529578 {
530579 // User callback, registered via ImDrawList::AddCallback()
531580 if (pcmd->UserCallback == ImGui_ImplOpenGL3_DrawCallback_ResetRenderState)
532- ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
581+ ImGui_ImplOpenGL3_SetupRenderState(draw_data, &render_state, fb_width, fb_height, vertex_array_object);
533582 else
534583 pcmd->UserCallback(draw_list, pcmd);
535584 }
@@ -548,11 +597,11 @@
548597 GL_CALL(glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()));
549598
550599 // Emulate sampler change (even though it is technically part of texture data)
551- // As a sort of hack/workaround, we only start writing using glTextParameter() if sampler is ever changed explicitly.
552- if (!bd->HasBindSampler && bd->UseTexParameterToSetSampler)
600+ // As a sort of hack/workaround, we only start writing using glTexParameter() if sampler is ever changed explicitly.
601+ if (render_state.UseTexParameterFilter)
553602 {
554- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bd->NextSampler);
555- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bd->NextSampler);
603+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, render_state.CurrentTexParameterFilter);
604+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, render_state.CurrentTexParameterFilter);
556605 }
557606
558607 #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
@@ -564,6 +613,7 @@
564613 }
565614 }
566615 }
616+ platform_io.Renderer_RenderState = nullptr;
567617
568618 // Destroy the temporary VAO
569619 #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
@@ -1030,6 +1080,7 @@
10301080 io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
10311081 #endif
10321082 io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
1083+ io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
10331084
10341085 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
10351086 platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = (int)bd->MaxTextureSize;
@@ -1048,7 +1099,10 @@
10481099 #elif defined(__APPLE__)
10491100 glsl_version = "#version 150";
10501101 #else
1051- glsl_version = "#version 130";
1102+ if (bd->GlVersion >= 410)
1103+ glsl_version = "#version 410";
1104+ else
1105+ glsl_version = "#version 130";
10521106 #endif
10531107 }
10541108 IM_ASSERT((int)strlen(glsl_version) + 2 < IM_COUNTOF(bd->GlslVersionString));
@@ -1079,6 +1133,8 @@
10791133 }
10801134 #endif
10811135
1136+ ImGui_ImplOpenGL3_InitMultiViewportSupport();
1137+
10821138 return true;
10831139 }
10841140
@@ -1089,15 +1145,44 @@
10891145 ImGuiIO& io = ImGui::GetIO();
10901146 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
10911147
1148+ ImGui_ImplOpenGL3_ShutdownMultiViewportSupport();
10921149 ImGui_ImplOpenGL3_DestroyDeviceObjects();
10931150
10941151 io.BackendRendererName = nullptr;
10951152 io.BackendRendererUserData = nullptr;
1096- io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
1153+ io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
10971154 platform_io.ClearRendererHandlers();
10981155 IM_DELETE(bd);
10991156
11001157 ImGui_ImplOpenGL3_ShutdownLoader();
1158+}
1159+
1160+//--------------------------------------------------------------------------------------------------------
1161+// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
1162+// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
1163+// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
1164+//--------------------------------------------------------------------------------------------------------
1165+
1166+static void ImGui_ImplOpenGL3_RenderWindow(ImGuiViewport* viewport, void*)
1167+{
1168+ if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
1169+ {
1170+ ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
1171+ glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
1172+ glClear(GL_COLOR_BUFFER_BIT);
1173+ }
1174+ ImGui_ImplOpenGL3_RenderDrawData(viewport->DrawData);
1175+}
1176+
1177+static void ImGui_ImplOpenGL3_InitMultiViewportSupport()
1178+{
1179+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
1180+ platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL3_RenderWindow;
1181+}
1182+
1183+static void ImGui_ImplOpenGL3_ShutdownMultiViewportSupport()
1184+{
1185+ ImGui::DestroyPlatformWindows();
11011186 }
11021187
11031188 //-----------------------------------------------------------------------------
@@ -7,6 +7,7 @@
77 // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
88 // [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!]
99 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
10+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
1011
1112 // About WebGL/ES:
1213 // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
@@ -64,5 +65,18 @@
6465 #endif
6566
6667 #endif
68+
69+// [BETA] Selected render state data shared with callbacks.
70+// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplOpenGL3_RenderDrawData() call.
71+// (Please open an issue if you feel you need access to more data)
72+struct ImGui_ImplOpenGL3_RenderState
73+{
74+ bool UseBindSampler;
75+ bool UseTexParameterFilter;
76+ unsigned int CurrentSampler; // (GLuint) Used if UseBindSampler == true, otherwise always 0
77+ unsigned int CurrentTexParameterFilter; // (GLuint) Used if UseTexParameterToSetSampler == true
78+};
79+
80+static inline ImGui_ImplOpenGL3_RenderState* ImGui_ImplOpenGL3_GetRenderState() { return (ImGui_ImplOpenGL3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; }
6781
6882 #endif // #ifndef IMGUI_DISABLE
@@ -10,6 +10,10 @@
1010 // [X] Platform: Gamepad support.
1111 // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
1212 // [X] Platform: IME support.
13+// [x] Platform: Multi-viewport / platform windows.
14+// Missing features or Issues:
15+// [ ] Platform: Multi-viewport: Window size not correctly reported when enabling io.ConfigViewportsNoDecoration
16+// [ ] Platform: Multi-viewport: Missing ImGuiBackendFlags_HasParentViewport support. The viewport->ParentViewportID field is ignored, and therefore io.ConfigViewportsNoDefaultParent has no effect either.
1317
1418 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1519 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -10,6 +10,10 @@
1010 // [X] Platform: Gamepad support.
1111 // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
1212 // [X] Platform: IME support.
13+// [x] Platform: Multi-viewport / platform windows.
14+// Missing features or Issues:
15+// [ ] Platform: Multi-viewport: Window size not correctly reported when enabling io.ConfigViewportsNoDecoration
16+// [ ] Platform: Multi-viewport: Missing ImGuiBackendFlags_HasParentViewport support. The viewport->ParentViewportID field is ignored, and therefore io.ConfigViewportsNoDefaultParent has no effect either.
1317
1418 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1519 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -29,9 +33,12 @@
2933
3034 // CHANGELOG
3135 // (minor and older changes stripped away, please see git history for details)
36+// 2026-XX-XX: Added support for multiple windows via the ImGuiPlatformIO interface.
3237 // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown.
38+// 2025-07-08: [Docking] Fixed multi-viewport handling broken on 2025-06-02. (#8644, #8777)
3339 // 2025-06-27: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support.
3440 // 2025-06-12: ImGui_ImplOSX_HandleEvent() only process event for window containing our view. (#8644)
41+// 2025-05-15: [Docking] Add Platform_GetWindowFramebufferScale() handler, to allow varying Retina display density on multiple monitors.
3542 // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set.
3643 // 2025-01-20: Removed notification observer when shutting down. (#8331)
3744 // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
@@ -101,6 +108,9 @@
101108 static inline CFTimeInterval GetMachAbsoluteTimeInSeconds() { return (CFTimeInterval)(double)(clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1e9); }
102109
103110 // Forward Declarations
111+static void ImGui_ImplOSX_InitMultiViewportSupport();
112+static void ImGui_ImplOSX_ShutdownMultiViewportSupport();
113+static void ImGui_ImplOSX_UpdateMonitors();
104114 static void ImGui_ImplOSX_AddTrackingArea(NSView* _Nonnull view);
105115 static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view);
106116
@@ -148,7 +158,21 @@
148158 NSWindow* window = view.window;
149159 if (!window)
150160 return;
161+
162+ ImGuiIO& io = ImGui::GetIO();
163+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
151164 {
165+ NSRect frame = window.frame;
166+ NSRect contentRect = window.contentLayoutRect;
167+ if (window.styleMask & NSWindowStyleMaskFullSizeContentView) // No title bar windows should be considered.
168+ contentRect = frame;
169+
170+ NSRect firstScreenFrame = NSScreen.screens[0].frame;
171+ _imeRect = NSMakeRect(_posX, _posY, 0, 0);
172+ _imeRect.origin.y = firstScreenFrame.size.height - _imeRect.size.height - _imeRect.origin.y; // Opposite of ConvertNSRect()
173+ }
174+ else
175+ {
152176 NSRect contentRect = [window contentRectForFrameRect:window.frame];
153177 NSRect rect = NSMakeRect(_posX, contentRect.size.height - _posY, 0, 0);
154178 _imeRect = [window convertRectToScreen:rect];
@@ -247,6 +271,7 @@
247271
248272 - (void)onApplicationBecomeActive:(NSNotification*)aNotification;
249273 - (void)onApplicationBecomeInactive:(NSNotification*)aNotification;
274+- (void)displaysDidChange:(NSNotification*)aNotification;
250275
251276 @end
252277
@@ -264,6 +289,11 @@
264289 io.AddFocusEvent(false);
265290 }
266291
292+- (void)displaysDidChange:(NSNotification*)aNotification
293+{
294+ ImGui_ImplOSX_UpdateMonitors();
295+}
296+
267297 @end
268298
269299 // Functions
@@ -418,11 +448,15 @@
418448 io.BackendPlatformName = "imgui_impl_osx";
419449 io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
420450 //io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
451+ io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
452+ //io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional)
421453
422454 bd->Observer = [ImGuiObserver new];
423455 bd->Window = view.window ?: NSApp.orderedWindows.firstObject;
424456 ImGuiViewport* main_viewport = ImGui::GetMainViewport();
425457 main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (__bridge_retained void*)bd->Window;
458+ ImGui_ImplOSX_UpdateMonitors();
459+ ImGui_ImplOSX_InitMultiViewportSupport();
426460
427461 // Load cursors. Some of them are undocumented.
428462 bd->MouseCursorHidden = false;
@@ -514,14 +548,14 @@
514548 bd->Monitor = nullptr;
515549 }
516550
551+ ImGui_ImplOSX_ShutdownMultiViewportSupport();
517552 ImGui_ImplOSX_DestroyBackendData();
518-
519553 ImGuiIO& io = ImGui::GetIO();
520554 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
521555
522556 io.BackendPlatformName = nullptr;
523557 io.BackendPlatformUserData = nullptr;
524- io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasGamepad);
558+ io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports);
525559 platform_io.ClearPlatformHandlers();
526560 }
527561
@@ -672,10 +706,10 @@
672706 static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
673707 {
674708 // Only process events from the window containing ImGui view
675- if (event.window != view.window)
709+ if (!ImGui::FindViewportByPlatformHandle((__bridge void*)event.window))
676710 return false;
677- ImGuiIO& io = ImGui::GetIO();
678711
712+ ImGuiIO& io = ImGui::GetIO();
679713 if (event.type == NSEventTypeLeftMouseDown || event.type == NSEventTypeRightMouseDown || event.type == NSEventTypeOtherMouseDown)
680714 {
681715 int button = (int)[event buttonNumber];
@@ -700,14 +734,23 @@
700734
701735 if (event.type == NSEventTypeMouseMoved || event.type == NSEventTypeLeftMouseDragged || event.type == NSEventTypeRightMouseDragged || event.type == NSEventTypeOtherMouseDragged)
702736 {
703- NSPoint mousePoint = event.locationInWindow;
704- if (event.window == nil)
705- mousePoint = [[view window] convertPointFromScreen:mousePoint];
706- mousePoint = [view convertPoint:mousePoint fromView:nil];
707- if ([view isFlipped])
708- mousePoint = NSMakePoint(mousePoint.x, mousePoint.y);
737+ NSPoint mousePoint;
738+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
739+ {
740+ mousePoint = NSEvent.mouseLocation;
741+ mousePoint.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - mousePoint.y; // Normalize y coordinate to top-left of main display.
742+ }
709743 else
710- mousePoint = NSMakePoint(mousePoint.x, view.bounds.size.height - mousePoint.y);
744+ {
745+ mousePoint = event.locationInWindow;
746+ if (event.window == nil)
747+ mousePoint = [[view window] convertPointFromScreen:mousePoint];
748+ mousePoint = [view convertPoint:mousePoint fromView:nil]; // Convert to local coordinates of view
749+ if ([view isFlipped])
750+ mousePoint = NSMakePoint(mousePoint.x, mousePoint.y);
751+ else
752+ mousePoint = NSMakePoint(mousePoint.x, view.bounds.size.height - mousePoint.y);
753+ }
711754 io.AddMouseSourceEvent(GetMouseSource(event));
712755 io.AddMousePosEvent((float)mousePoint.x, (float)mousePoint.y);
713756 return io.WantCaptureMouse;
@@ -831,6 +874,300 @@
831874 ImGui_ImplOSX_HandleEvent(event, view);
832875 return event;
833876 }];
877+}
878+
879+//--------------------------------------------------------------------------------------------------------
880+// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
881+// This is an _advanced_ and _optional_ feature, allowing the back-end to create and handle multiple viewports simultaneously.
882+// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
883+//--------------------------------------------------------------------------------------------------------
884+
885+struct ImGui_ImplOSX_ViewportData
886+{
887+ NSWindow* Window;
888+ bool WindowOwned;
889+
890+ ImGui_ImplOSX_ViewportData() { WindowOwned = false; }
891+ ~ImGui_ImplOSX_ViewportData() { IM_ASSERT(Window == nil); }
892+};
893+
894+@interface ImGui_ImplOSX_Window: NSWindow
895+@end
896+
897+@implementation ImGui_ImplOSX_Window
898+
899+- (BOOL)canBecomeKeyWindow
900+{
901+ return YES;
902+}
903+
904+@end
905+
906+static void ConvertNSRect(NSRect* r)
907+{
908+ NSRect firstScreenFrame = NSScreen.screens[0].frame;
909+ IM_ASSERT(firstScreenFrame.origin.x == 0 && firstScreenFrame.origin.y == 0);
910+ r->origin.y = firstScreenFrame.size.height - r->origin.y - r->size.height;
911+}
912+
913+static void ImGui_ImplOSX_CreateWindow(ImGuiViewport* viewport)
914+{
915+ ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
916+ ImGui_ImplOSX_ViewportData* vd = IM_NEW(ImGui_ImplOSX_ViewportData)();
917+ viewport->PlatformUserData = vd;
918+
919+ NSScreen* screen = bd->Window.screen;
920+ NSRect rect = NSMakeRect(viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y);
921+ ConvertNSRect(&rect);
922+
923+ NSWindowStyleMask styleMask = 0;
924+ if (viewport->Flags & ImGuiViewportFlags_NoDecoration)
925+ styleMask |= NSWindowStyleMaskBorderless;
926+ else
927+ styleMask |= NSWindowStyleMaskTitled | NSWindowStyleMaskResizable | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
928+
929+ NSWindow* window = [[ImGui_ImplOSX_Window alloc] initWithContentRect:rect
930+ styleMask:styleMask
931+ backing:NSBackingStoreBuffered
932+ defer:YES
933+ screen:screen];
934+ if (viewport->Flags & ImGuiViewportFlags_TopMost)
935+ [window setLevel:NSFloatingWindowLevel];
936+
937+ window.title = @"Untitled";
938+ window.opaque = YES;
939+
940+ KeyEventResponder* view = [[KeyEventResponder alloc] initWithFrame:rect];
941+ if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6 && ceil(NSAppKitVersionNumber) < NSAppKitVersionNumber10_15)
942+ [view setWantsBestResolutionOpenGLSurface:YES];
943+
944+ window.contentView = view;
945+
946+ vd->Window = window;
947+ vd->WindowOwned = true;
948+ viewport->PlatformRequestResize = false;
949+ viewport->PlatformHandle = viewport->PlatformHandleRaw = (__bridge_retained void*)window;
950+}
951+
952+static void ImGui_ImplOSX_DestroyWindow(ImGuiViewport* viewport)
953+{
954+ if (ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData)
955+ {
956+ NSWindow* window = vd->Window;
957+ if (window != nil && vd->WindowOwned)
958+ {
959+ window.contentView = nil;
960+ window.contentViewController = nil;
961+ [window orderOut:nil];
962+ }
963+ vd->Window = nil;
964+ IM_DELETE(vd);
965+ }
966+ viewport->PlatformUserData = viewport->PlatformHandle = viewport->PlatformHandleRaw = nullptr;
967+}
968+
969+static void ImGui_ImplOSX_ShowWindow(ImGuiViewport* viewport)
970+{
971+ ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
972+ IM_ASSERT(vd->Window != 0);
973+
974+ if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
975+ [vd->Window orderFront:nil];
976+ else
977+ [vd->Window makeKeyAndOrderFront:nil];
978+
979+ [vd->Window setIsVisible:YES];
980+}
981+
982+static ImVec2 ImGui_ImplOSX_GetWindowPos(ImGuiViewport* viewport)
983+{
984+ ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
985+ IM_ASSERT(vd->Window != 0);
986+
987+ NSWindow* window = vd->Window;
988+ NSRect frame = window.frame;
989+ NSRect contentRect = window.contentLayoutRect;
990+ if (window.styleMask & NSWindowStyleMaskFullSizeContentView) // No title bar windows should be considered.
991+ contentRect = frame;
992+
993+ NSRect firstScreenFrame = NSScreen.screens[0].frame;
994+ return ImVec2(frame.origin.x, firstScreenFrame.size.height - frame.origin.y - contentRect.size.height);
995+}
996+
997+static void ImGui_ImplOSX_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
998+{
999+ ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
1000+ IM_ASSERT(vd->Window != 0);
1001+
1002+ NSWindow* window = vd->Window;
1003+ NSSize size = window.frame.size;
1004+
1005+ NSRect r = NSMakeRect(pos.x, pos.y, size.width, size.height);
1006+ ConvertNSRect(&r);
1007+ [window setFrameOrigin:r.origin];
1008+}
1009+
1010+static ImVec2 ImGui_ImplOSX_GetWindowSize(ImGuiViewport* viewport)
1011+{
1012+ ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
1013+ IM_ASSERT(vd->Window != 0);
1014+
1015+ NSWindow* window = vd->Window;
1016+ NSSize size = window.contentLayoutRect.size;
1017+ return ImVec2(size.width, size.height);
1018+}
1019+
1020+static void ImGui_ImplOSX_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
1021+{
1022+ ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
1023+ IM_ASSERT(vd->Window != 0);
1024+
1025+ NSWindow* window = vd->Window;
1026+ NSRect rect = window.frame;
1027+ rect.origin.y -= (size.y - rect.size.height);
1028+ rect.size.width = size.x;
1029+ rect.size.height = size.y;
1030+ [window setFrame:rect display:YES];
1031+}
1032+
1033+static ImVec2 ImGui_ImplOSX_GetWindowFramebufferScale(ImGuiViewport* viewport)
1034+{
1035+ ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
1036+ NSWindow* window = vd->Window;
1037+ const float fb_scale = (float)[window backingScaleFactor];
1038+ return ImVec2(fb_scale, fb_scale);
1039+}
1040+
1041+static void ImGui_ImplOSX_SetWindowFocus(ImGuiViewport* viewport)
1042+{
1043+ ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
1044+ ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
1045+ IM_ASSERT(vd->Window != 0);
1046+ [vd->Window makeKeyAndOrderFront:bd->Window];
1047+}
1048+
1049+static bool ImGui_ImplOSX_GetWindowFocus(ImGuiViewport* viewport)
1050+{
1051+ ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
1052+ IM_ASSERT(vd->Window != 0);
1053+
1054+ return vd->Window.isKeyWindow;
1055+}
1056+
1057+static bool ImGui_ImplOSX_GetWindowMinimized(ImGuiViewport* viewport)
1058+{
1059+ ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
1060+ IM_ASSERT(vd->Window != 0);
1061+
1062+ return vd->Window.isMiniaturized;
1063+}
1064+
1065+static void ImGui_ImplOSX_SetWindowTitle(ImGuiViewport* viewport, const char* title)
1066+{
1067+ ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
1068+ IM_ASSERT(vd->Window != 0);
1069+
1070+ vd->Window.title = [NSString stringWithUTF8String:title];
1071+}
1072+
1073+static void ImGui_ImplOSX_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
1074+{
1075+ ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
1076+ IM_ASSERT(vd->Window != 0);
1077+ IM_ASSERT(alpha >= 0.0f && alpha <= 1.0f);
1078+
1079+ vd->Window.alphaValue = alpha;
1080+}
1081+
1082+static float ImGui_ImplOSX_GetWindowDpiScale(ImGuiViewport* viewport)
1083+{
1084+ ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
1085+ IM_ASSERT(vd->Window != 0);
1086+
1087+ return vd->Window.backingScaleFactor;
1088+}
1089+
1090+static void ImGui_ImplOSX_UpdateMonitors()
1091+{
1092+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
1093+ platform_io.Monitors.resize(0);
1094+
1095+ NSRect firstScreenFrame = NSScreen.screens[0].frame;
1096+ IM_ASSERT(firstScreenFrame.origin.x == 0 && firstScreenFrame.origin.y == 0);
1097+
1098+ for (NSScreen* screen in NSScreen.screens)
1099+ {
1100+ NSRect frame = screen.frame;
1101+ NSRect visibleFrame = screen.visibleFrame;
1102+ ConvertNSRect(&frame);
1103+ ConvertNSRect(&visibleFrame);
1104+
1105+ ImGuiPlatformMonitor imgui_monitor;
1106+ imgui_monitor.MainPos = ImVec2(frame.origin.x, frame.origin.y);
1107+ imgui_monitor.MainSize = ImVec2(frame.size.width, frame.size.height);
1108+ imgui_monitor.WorkPos = ImVec2(visibleFrame.origin.x, visibleFrame.origin.y);
1109+ imgui_monitor.WorkSize = ImVec2(visibleFrame.size.width, visibleFrame.size.height);
1110+ imgui_monitor.DpiScale = screen.backingScaleFactor;
1111+ imgui_monitor.PlatformHandle = (__bridge_retained void*)screen;
1112+
1113+ platform_io.Monitors.push_back(imgui_monitor);
1114+ }
1115+}
1116+
1117+static void ImGui_ImplOSX_InitMultiViewportSupport()
1118+{
1119+ ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
1120+
1121+ // Register platform interface (will be coupled with a renderer interface)
1122+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
1123+ platform_io.Platform_CreateWindow = ImGui_ImplOSX_CreateWindow;
1124+ platform_io.Platform_DestroyWindow = ImGui_ImplOSX_DestroyWindow;
1125+ platform_io.Platform_ShowWindow = ImGui_ImplOSX_ShowWindow;
1126+ platform_io.Platform_SetWindowPos = ImGui_ImplOSX_SetWindowPos;
1127+ platform_io.Platform_GetWindowPos = ImGui_ImplOSX_GetWindowPos;
1128+ platform_io.Platform_SetWindowSize = ImGui_ImplOSX_SetWindowSize;
1129+ platform_io.Platform_GetWindowSize = ImGui_ImplOSX_GetWindowSize;
1130+ platform_io.Platform_GetWindowFramebufferScale = ImGui_ImplOSX_GetWindowFramebufferScale;
1131+ platform_io.Platform_SetWindowFocus = ImGui_ImplOSX_SetWindowFocus;
1132+ platform_io.Platform_GetWindowFocus = ImGui_ImplOSX_GetWindowFocus;
1133+ platform_io.Platform_GetWindowMinimized = ImGui_ImplOSX_GetWindowMinimized;
1134+ platform_io.Platform_SetWindowTitle = ImGui_ImplOSX_SetWindowTitle;
1135+ platform_io.Platform_SetWindowAlpha = ImGui_ImplOSX_SetWindowAlpha;
1136+ platform_io.Platform_GetWindowDpiScale = ImGui_ImplOSX_GetWindowDpiScale; // FIXME-DPI
1137+
1138+ // Register main window handle (which is owned by the main application, not by us)
1139+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
1140+ ImGui_ImplOSX_ViewportData* vd = IM_NEW(ImGui_ImplOSX_ViewportData)();
1141+ vd->Window = bd->Window;
1142+ vd->WindowOwned = false;
1143+ main_viewport->PlatformUserData = vd;
1144+ main_viewport->PlatformHandle = (__bridge void*)bd->Window;
1145+
1146+ [NSNotificationCenter.defaultCenter addObserver:bd->Observer
1147+ selector:@selector(displaysDidChange:)
1148+ name:NSApplicationDidChangeScreenParametersNotification
1149+ object:nil];
1150+}
1151+
1152+static void ImGui_ImplOSX_ShutdownMultiViewportSupport()
1153+{
1154+ ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
1155+ [NSNotificationCenter.defaultCenter removeObserver:bd->Observer
1156+ name:NSApplicationDidChangeScreenParametersNotification
1157+ object:nil];
1158+ bd->Observer = nullptr;
1159+ bd->Window = nullptr;
1160+ if (bd->Monitor != nullptr)
1161+ {
1162+ [NSEvent removeMonitor:bd->Monitor];
1163+ bd->Monitor = nullptr;
1164+ }
1165+
1166+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
1167+ ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)main_viewport->PlatformUserData;
1168+ IM_DELETE(vd);
1169+ main_viewport->PlatformUserData = nullptr;
1170+ ImGui::DestroyPlatformWindows();
8341171 }
8351172
8361173 //-----------------------------------------------------------------------------
@@ -10,6 +10,10 @@
1010 // [X] Platform: Gamepad support.
1111 // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
1212 // [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
13+// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
14+// Missing features or Issues:
15+// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
16+// [ ] Platform: Multi-viewport: Missing ImGuiBackendFlags_HasParentViewport support. The viewport->ParentViewportID field is ignored, and therefore io.ConfigViewportsNoDefaultParent has no effect either.
1317
1418 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1519 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -21,7 +25,9 @@
2125
2226 // CHANGELOG
2327 // (minor and older changes stripped away, please see git history for details)
28+// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
2429 // 2026-04-16: Made ImGui_ImplSDL2_GetContentScaleForWindow(), ImGui_ImplSDL2_GetContentScaleForDisplay() helpers return a minimum of 1.0f, as some Linux setup seems to report <1.0f value and this breaks scaling border size. (#9369)
30+// 2026-03-09: [Docking] Fixed an issue dated 2025/04/09 (1.92 WIP) where a refactor+merge caused ImGuiBackendFlags_HasMouseHoveredViewport to never be set, causing foreign windows to be ignored when deciding of hovered viewport. (#9284)
2531 // 2026-02-13: Inputs: systems other than X11 are back to starting mouse capture on mouse down (reverts 2025-02-26 change). Only X11 requires waiting for a drag by default (not ideal, but a better default for X11 users). Added ImGui_ImplSDL2_SetMouseCaptureMode() for X11 debugger users. (#3650, #6410, #9235)
2632 // 2026-01-15: Changed GetClipboardText() handler to return nullptr on error aka clipboard contents is not text. Consistent with other backends. (#9168)
2733 // 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)
@@ -29,11 +35,15 @@
2935 // 2025-09-15: Content Scales are always reported as 1.0 on Wayland. (#8921)
3036 // 2025-07-08: Made ImGui_ImplSDL2_GetContentScaleForWindow(), ImGui_ImplSDL2_GetContentScaleForDisplay() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733)
3137 // 2025-06-11: Added ImGui_ImplSDL2_GetContentScaleForWindow(SDL_Window* window) and ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index) helper to facilitate making DPI-aware apps.
38+// 2025-05-15: [Docking] Add Platform_GetWindowFramebufferScale() handler, to allow varying Retina display density on multiple monitors.
39+// 2025-04-09: [Docking] Revert update monitors and work areas information every frame. Only do it on Windows. (#8415, #8558)
3240 // 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561)
3341 // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set.
3442 // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468)
3543 // 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g. Linux debuggers not claiming capture back. (#6410, #3650)
44+// 2025-02-25: [Docking] Revert to use SDL_GetDisplayBounds() for WorkPos/WorkRect if SDL_GetDisplayUsableBounds() failed.
3645 // 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode.
46+// 2025-02-21: [Docking] Update monitors and work areas information every frame, as the later may change regardless of monitor changes. (#8415)
3747 // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support.
3848 // 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler.
3949 // 2025-01-20: Made ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode_Manual) accept an empty array.
@@ -74,7 +84,7 @@
7484 // 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
7585 // 2021-08-17: Calling io.AddFocusEvent() on SDL_WINDOWEVENT_FOCUS_GAINED/SDL_WINDOWEVENT_FOCUS_LOST.
7686 // 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using SDL_GetMouseFocus() + SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, requires SDL 2.0.5+)
77-// 2021-06-29: *BREAKING CHANGE* Removed 'SDL_Window* window' parameter to ImGui_ImplSDL2_NewFrame() which was unnecessary.
87+// 2021-06:29: *BREAKING CHANGE* Removed 'SDL_Window* window' parameter to ImGui_ImplSDL2_NewFrame() which was unnecessary.
7888 // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
7989 // 2021-03-22: Rework global mouse pos availability check listing supported platforms explicitly, effectively fixing mouse access on Raspberry Pi. (#2837, #3950)
8090 // 2020-05-25: Misc: Report a zero display-size when window is minimized, to be consistent with other backends.
@@ -116,6 +126,7 @@
116126 #endif
117127
118128 // SDL
129+// (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended)
119130 #include <SDL.h>
120131 #include <SDL_syswm.h>
121132 #include <stdio.h> // for snprintf()
@@ -132,11 +143,18 @@
132143 #else
133144 #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0
134145 #endif
146+#define SDL_HAS_WINDOW_ALPHA SDL_VERSION_ATLEAST(2,0,5)
147+#define SDL_HAS_ALWAYS_ON_TOP SDL_VERSION_ATLEAST(2,0,5)
148+#define SDL_HAS_USABLE_DISPLAY_BOUNDS SDL_VERSION_ATLEAST(2,0,5)
135149 #define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4)
136150 #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
151+#define SDL_HAS_DISPLAY_EVENT SDL_VERSION_ATLEAST(2,0,9)
137152 #define SDL_HAS_OPEN_URL SDL_VERSION_ATLEAST(2,0,14)
153+#define SDL_HAS_SHOW_WINDOW_ACTIVATION_HINT SDL_VERSION_ATLEAST(2,0,18)
138154 #if SDL_HAS_VULKAN
139155 #include <SDL_vulkan.h>
156+#else
157+static const Uint32 SDL_WINDOW_VULKAN = 0x10000000;
140158 #endif
141159
142160 // SDL Data
@@ -148,6 +166,8 @@
148166 Uint64 Time;
149167 char* ClipboardTextData;
150168 char BackendPlatformName[48];
169+ bool UseVulkan;
170+ bool WantUpdateMonitors;
151171
152172 // Mouse handling
153173 Uint32 MouseWindowID;
@@ -156,6 +176,7 @@
156176 SDL_Cursor* MouseLastCursor;
157177 int MouseLastLeaveFrame;
158178 bool MouseCanUseGlobalState;
179+ bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state.
159180 ImGui_ImplSDL2_MouseCaptureMode MouseCaptureMode;
160181
161182 // Gamepad handling
@@ -175,6 +196,11 @@
175196 return ImGui::GetCurrentContext() ? (ImGui_ImplSDL2_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr;
176197 }
177198
199+// Forward Declarations
200+static void ImGui_ImplSDL2_UpdateMonitors();
201+static void ImGui_ImplSDL2_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context);
202+static void ImGui_ImplSDL2_ShutdownMultiViewportSupport();
203+
178204 // Functions
179205 static const char* ImGui_ImplSDL2_GetClipboardText(ImGuiContext*)
180206 {
@@ -194,13 +220,13 @@
194220 }
195221
196222 // Note: native IME will only display if user calls SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1") _before_ SDL_CreateWindow().
197-static void ImGui_ImplSDL2_PlatformSetImeData(ImGuiContext*, ImGuiViewport*, ImGuiPlatformImeData* data)
223+static void ImGui_ImplSDL2_PlatformSetImeData(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data)
198224 {
199225 if (data->WantVisible)
200226 {
201227 SDL_Rect r;
202- r.x = (int)data->InputPos.x;
203- r.y = (int)data->InputPos.y;
228+ r.x = (int)(data->InputPos.x - viewport->Pos.x);
229+ r.y = (int)(data->InputPos.y - viewport->Pos.y);
204230 r.w = 1;
205231 r.h = (int)data->InputLineHeight;
206232 SDL_SetTextInputRect(&r);
@@ -366,8 +392,7 @@
366392
367393 static ImGuiViewport* ImGui_ImplSDL2_GetViewportForWindowID(Uint32 window_id)
368394 {
369- ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
370- return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : nullptr;
395+ return ImGui::FindViewportByPlatformHandle((void*)(intptr_t)window_id);
371396 }
372397
373398 // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
@@ -387,6 +412,13 @@
387412 if (ImGui_ImplSDL2_GetViewportForWindowID(event->motion.windowID) == nullptr)
388413 return false;
389414 ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y);
415+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
416+ {
417+ int window_x, window_y;
418+ SDL_GetWindowPosition(SDL_GetWindowFromID(event->motion.windowID), &window_x, &window_y);
419+ mouse_pos.x += window_x;
420+ mouse_pos.y += window_y;
421+ }
390422 io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse);
391423 io.AddMousePosEvent(mouse_pos.x, mouse_pos.y);
392424 return true;
@@ -438,20 +470,32 @@
438470 case SDL_KEYDOWN:
439471 case SDL_KEYUP:
440472 {
441- if (ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID) == nullptr)
473+ ImGuiViewport* viewport = ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID);
474+ if (viewport == nullptr)
442475 return false;
476+ //IMGUI_DEBUG_LOG("SDL_KEY%s : key=0x%08X ('%s'), scancode=%d ('%s'), mod=%X, windowID=%d, viewport=%08X\n",
477+ // (event->type == SDL_KEYDOWN) ? "DOWN" : "UP ", event->key.keysym.sym, SDL_GetKeyName(event->key.keysym.sym), event->key.keysym.scancode, SDL_GetScancodeName(event->key.keysym.scancode), event->key.keysym.mod, event->key.windowID, viewport ? viewport->ID : 0);
443478 ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod);
444- //IMGUI_DEBUG_LOG("SDL_KEY_%s : key=%d ('%s'), scancode=%d ('%s'), mod=%X\n",
445- // (event->type == SDL_KEYDOWN) ? "DOWN" : "UP ", event->key.keysym.sym, SDL_GetKeyName(event->key.keysym.sym), event->key.keysym.scancode, SDL_GetScancodeName(event->key.keysym.scancode), event->key.keysym.mod);
446479 ImGuiKey key = ImGui_ImplSDL2_KeyEventToImGuiKey(event->key.keysym.sym, event->key.keysym.scancode);
447480 io.AddKeyEvent(key, (event->type == SDL_KEYDOWN));
448481 io.SetKeyEventNativeData(key, (int)event->key.keysym.sym, (int)event->key.keysym.scancode, (int)event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
449482 return true;
450483 }
484+#if SDL_HAS_DISPLAY_EVENT
485+ case SDL_DISPLAYEVENT:
486+ {
487+ // 2.0.26 has SDL_DISPLAYEVENT_CONNECTED/SDL_DISPLAYEVENT_DISCONNECTED/SDL_DISPLAYEVENT_ORIENTATION,
488+ // so change of DPI/Scaling are not reflected in this event. (SDL3 has it)
489+ bd->WantUpdateMonitors = true;
490+ return true;
491+ }
492+#endif
451493 case SDL_WINDOWEVENT:
452494 {
453- if (ImGui_ImplSDL2_GetViewportForWindowID(event->window.windowID) == nullptr)
495+ ImGuiViewport* viewport = ImGui_ImplSDL2_GetViewportForWindowID(event->window.windowID);
496+ if (viewport == NULL)
454497 return false;
498+
455499 // - 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.
456500 // - However we won't get a correct LEAVE event for a captured window.
457501 // - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late,
@@ -465,10 +509,18 @@
465509 }
466510 if (window_event == SDL_WINDOWEVENT_LEAVE)
467511 bd->MouseLastLeaveFrame = ImGui::GetFrameCount() + 1;
512+ //if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED) { IMGUI_DEBUG_LOG("SDL_WINDOWEVENT_FOCUS_GAINED: windowId %d, viewport: %08X\n", event->window.windowID, viewport ? viewport->ID : 0); }
513+ //if (window_event == SDL_WINDOWEVENT_FOCUS_LOST) { IMGUI_DEBUG_LOG("SDL_WINDOWEVENT_FOCUS_LOST: windowId %d, viewport: %08X\n", event->window.windowID, viewport ? viewport->ID : 0); }
468514 if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED)
469515 io.AddFocusEvent(true);
470516 if (window_event == SDL_WINDOWEVENT_FOCUS_LOST)
471517 io.AddFocusEvent(false);
518+ if (window_event == SDL_WINDOWEVENT_CLOSE)
519+ viewport->PlatformRequestClose = true;
520+ if (window_event == SDL_WINDOWEVENT_MOVED)
521+ viewport->PlatformRequestMove = true;
522+ if (window_event == SDL_WINDOWEVENT_RESIZED)
523+ viewport->PlatformRequestResize = true;
472524 return true;
473525 }
474526 case SDL_CONTROLLERDEVICEADDED:
@@ -508,6 +560,7 @@
508560 io.BackendPlatformName = bd->BackendPlatformName;
509561 io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
510562 io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
563+ // (ImGuiBackendFlags_PlatformHasViewports may be set just below)
511564
512565 bd->Window = window;
513566 bd->WindowID = SDL_GetWindowID(window);
@@ -527,7 +580,17 @@
527580 bd->MouseCaptureMode = (strcmp(item, "x11") == 0) ? ImGui_ImplSDL2_MouseCaptureMode_EnabledAfterDrag : ImGui_ImplSDL2_MouseCaptureMode_Enabled;
528581 }
529582 #endif
583+ if (bd->MouseCanUseGlobalState)
584+ io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
530585
586+ // SDL on Linux/OSX doesn't report events for unfocused windows (see https://github.com/ocornut/imgui/issues/4960)
587+ // We will use 'MouseCanReportHoveredViewport' to set 'ImGuiBackendFlags_HasMouseHoveredViewport' dynamically each frame.
588+#ifndef __APPLE__
589+ bd->MouseCanReportHoveredViewport = bd->MouseCanUseGlobalState;
590+#else
591+ bd->MouseCanReportHoveredViewport = false;
592+#endif
593+
531594 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
532595 platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
533596 platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
@@ -539,6 +602,9 @@
539602 platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { return SDL_OpenURL(url) == 0; };
540603 #endif
541604
605+ // Update monitor a first time during init
606+ ImGui_ImplSDL2_UpdateMonitors();
607+
542608 // Gamepad handling
543609 bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoFirst;
544610 bd->WantUpdateGamepadsList = true;
@@ -593,7 +659,11 @@
593659 SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0");
594660 #endif
595661
596- (void)sdl_gl_context; // Unused in 'master' branch.
662+ // We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports.
663+ // We left the call to ImGui_ImplSDL2_InitMultiViewportSupport() outside of #ifdef to avoid unused-function warnings.
664+ if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports)
665+ ImGui_ImplSDL2_InitMultiViewportSupport(window, sdl_gl_context);
666+
597667 return true;
598668 }
599669
@@ -607,7 +677,11 @@
607677 #if !SDL_HAS_VULKAN
608678 IM_ASSERT(0 && "Unsupported");
609679 #endif
610- return ImGui_ImplSDL2_Init(window, nullptr, nullptr);
680+ if (!ImGui_ImplSDL2_Init(window, nullptr, nullptr))
681+ return false;
682+ ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
683+ bd->UseVulkan = true;
684+ return true;
611685 }
612686
613687 bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window)
@@ -642,6 +716,7 @@
642716 ImGuiIO& io = ImGui::GetIO();
643717 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
644718
719+ ImGui_ImplSDL2_ShutdownMultiViewportSupport();
645720 if (bd->ClipboardTextData)
646721 SDL_free(bd->ClipboardTextData);
647722 for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
@@ -650,7 +725,7 @@
650725
651726 io.BackendPlatformName = nullptr;
652727 io.BackendPlatformUserData = nullptr;
653- io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
728+ io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport);
654729 platform_io.ClearPlatformHandlers();
655730 IM_DELETE(bd);
656731 }
@@ -663,6 +738,7 @@
663738 bd->MouseCaptureMode = mode;
664739 }
665740
741+// This code is rather messy because some of the functions we need for full viewport support are not available in SDL < 2.0.4.
666742 static void ImGui_ImplSDL2_UpdateMouseData()
667743 {
668744 ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
@@ -686,16 +762,24 @@
686762 }
687763
688764 SDL_Window* focused_window = SDL_GetKeyboardFocus();
689- const bool is_app_focused = (bd->Window == focused_window);
765+ const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui_ImplSDL2_GetViewportForWindowID(SDL_GetWindowID(focused_window)) != NULL));
690766 #else
691767 SDL_Window* focused_window = bd->Window;
692768 const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only
693769 #endif
770+
694771 if (is_app_focused)
695772 {
696773 // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
697774 if (io.WantSetMousePos)
698- SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y);
775+ {
776+#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
777+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
778+ SDL_WarpMouseGlobal((int)io.MousePos.x, (int)io.MousePos.y);
779+ else
780+#endif
781+ SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y);
782+ }
699783
700784 // (Optional) Fallback to provide unclamped mouse position when focused but not hovered (SDL_MOUSEMOTION already provides this when hovered or captured)
701785 // 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.
@@ -704,15 +788,34 @@
704788 if (hovered_window == nullptr && bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode)
705789 {
706790 // 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)
791+ // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
707792 int mouse_x, mouse_y;
708793 int window_x, window_y;
709794 SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
710- SDL_GetWindowPosition(focused_window, &window_x, &window_y);
711- mouse_x -= window_x;
712- mouse_y -= window_y;
795+ if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable))
796+ {
797+ SDL_GetWindowPosition(focused_window, &window_x, &window_y);
798+ mouse_x -= window_x;
799+ mouse_y -= window_y;
800+ }
713801 io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
714802 }
715803 }
804+
805+ // (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
806+ // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic.
807+ // - [!] SDL backend does NOT correctly ignore viewports with the _NoInputs flag.
808+ // Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window
809+ // for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported
810+ // by the backend, and use its flawed heuristic to guess the viewport behind.
811+ // - [X] SDL backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target).
812+ if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)
813+ {
814+ ImGuiID mouse_viewport_id = 0;
815+ if (ImGuiViewport* mouse_viewport = ImGui_ImplSDL2_GetViewportForWindowID(bd->MouseWindowID))
816+ mouse_viewport_id = mouse_viewport->ID;
817+ io.AddMouseViewportEvent(mouse_viewport_id);
818+ }
716819 }
717820
718821 static void ImGui_ImplSDL2_UpdateMouseCursor()
@@ -872,6 +975,38 @@
872975 ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767);
873976 }
874977
978+// FIXME: Note that doesn't update with DPI/Scaling change only as SDL2 doesn't have an event for it (SDL3 has).
979+static void ImGui_ImplSDL2_UpdateMonitors()
980+{
981+ ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
982+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
983+ platform_io.Monitors.resize(0);
984+ bd->WantUpdateMonitors = false;
985+ int display_count = SDL_GetNumVideoDisplays();
986+ for (int n = 0; n < display_count; n++)
987+ {
988+ // Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime.
989+ ImGuiPlatformMonitor monitor;
990+ SDL_Rect r;
991+ SDL_GetDisplayBounds(n, &r);
992+ monitor.MainPos = monitor.WorkPos = ImVec2((float)r.x, (float)r.y);
993+ monitor.MainSize = monitor.WorkSize = ImVec2((float)r.w, (float)r.h);
994+#if SDL_HAS_USABLE_DISPLAY_BOUNDS
995+ if (SDL_GetDisplayUsableBounds(n, &r) == 0 && r.w > 0 && r.h > 0)
996+ {
997+ monitor.WorkPos = ImVec2((float)r.x, (float)r.y);
998+ monitor.WorkSize = ImVec2((float)r.w, (float)r.h);
999+ }
1000+#endif
1001+ float dpi_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(n);
1002+ if (dpi_scale <= 0.0f)
1003+ continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902.
1004+ monitor.DpiScale = dpi_scale;
1005+ monitor.PlatformHandle = (void*)(intptr_t)n;
1006+ platform_io.Monitors.push_back(monitor);
1007+ }
1008+}
1009+
8751010 static void ImGui_ImplSDL2_GetWindowSizeAndFramebufferScale(SDL_Window* window, SDL_Renderer* renderer, ImVec2* out_size, ImVec2* out_framebuffer_scale)
8761011 {
8771012 int w, h;
@@ -902,6 +1037,13 @@
9021037 // Setup main viewport size (every frame to accommodate for window resizing)
9031038 ImGui_ImplSDL2_GetWindowSizeAndFramebufferScale(bd->Window, bd->Renderer, &io.DisplaySize, &io.DisplayFramebufferScale);
9041039
1040+ // Update monitors
1041+#ifdef WIN32
1042+ bd->WantUpdateMonitors = true; // Keep polling under Windows to handle changes of work area when resizing task-bar (#8415)
1043+#endif
1044+ if (bd->WantUpdateMonitors)
1045+ ImGui_ImplSDL2_UpdateMonitors();
1046+
9051047 // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
9061048 // (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644)
9071049 static Uint64 frequency = SDL_GetPerformanceFrequency();
@@ -918,11 +1060,278 @@
9181060 io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
9191061 }
9201062
1063+ // Our io.AddMouseViewportEvent() calls will only be valid when not capturing.
1064+ // Technically speaking testing for 'bd->MouseButtonsDown == 0' would be more rigorous, but testing for payload reduces noise and potential side-effects.
1065+ if (bd->MouseCanReportHoveredViewport && ImGui::GetDragDropPayload() == nullptr)
1066+ io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport;
1067+ else
1068+ io.BackendFlags &= ~ImGuiBackendFlags_HasMouseHoveredViewport;
1069+
9211070 ImGui_ImplSDL2_UpdateMouseData();
9221071 ImGui_ImplSDL2_UpdateMouseCursor();
9231072
9241073 // Update game controllers (if enabled and available)
9251074 ImGui_ImplSDL2_UpdateGamepads();
1075+}
1076+
1077+//--------------------------------------------------------------------------------------------------------
1078+// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
1079+// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
1080+// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
1081+//--------------------------------------------------------------------------------------------------------
1082+
1083+// Helper structure we store in the void* PlatformUserData field of each ImGuiViewport to easily retrieve our backend data.
1084+struct ImGui_ImplSDL2_ViewportData
1085+{
1086+ SDL_Window* Window;
1087+ Uint32 WindowID; // Stored in ImGuiViewport::PlatformHandle. Use SDL_GetWindowFromID() to get SDL_Window* from Uint32 WindowID.
1088+ bool WindowOwned;
1089+ SDL_GLContext GLContext;
1090+
1091+ ImGui_ImplSDL2_ViewportData() { Window = nullptr; WindowID = 0; WindowOwned = false; GLContext = nullptr; }
1092+ ~ImGui_ImplSDL2_ViewportData() { IM_ASSERT(Window == nullptr && GLContext == nullptr); }
1093+};
1094+
1095+static void ImGui_ImplSDL2_CreateWindow(ImGuiViewport* viewport)
1096+{
1097+ ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
1098+ ImGui_ImplSDL2_ViewportData* vd = IM_NEW(ImGui_ImplSDL2_ViewportData)();
1099+ viewport->PlatformUserData = vd;
1100+
1101+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
1102+ ImGui_ImplSDL2_ViewportData* main_viewport_data = (ImGui_ImplSDL2_ViewportData*)main_viewport->PlatformUserData;
1103+
1104+ // Share GL resources with main context
1105+ bool use_opengl = (main_viewport_data->GLContext != nullptr);
1106+ SDL_GLContext backup_context = nullptr;
1107+ if (use_opengl)
1108+ {
1109+ backup_context = SDL_GL_GetCurrentContext();
1110+ SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
1111+ SDL_GL_MakeCurrent(main_viewport_data->Window, main_viewport_data->GLContext);
1112+ }
1113+
1114+ Uint32 sdl_flags = 0;
1115+ sdl_flags |= use_opengl ? SDL_WINDOW_OPENGL : (bd->UseVulkan ? SDL_WINDOW_VULKAN : 0);
1116+ sdl_flags |= SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_ALLOW_HIGHDPI;
1117+ sdl_flags |= SDL_WINDOW_HIDDEN;
1118+ sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0;
1119+ sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE;
1120+#if !defined(_WIN32)
1121+ // See SDL hack in ImGui_ImplSDL2_ShowWindow().
1122+ sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) ? SDL_WINDOW_SKIP_TASKBAR : 0;
1123+#endif
1124+#if SDL_HAS_ALWAYS_ON_TOP
1125+ sdl_flags |= (viewport->Flags & ImGuiViewportFlags_TopMost) ? SDL_WINDOW_ALWAYS_ON_TOP : 0;
1126+#endif
1127+ vd->Window = SDL_CreateWindow("No Title Yet", (int)viewport->Pos.x, (int)viewport->Pos.y, (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags);
1128+ vd->WindowOwned = true;
1129+ if (use_opengl)
1130+ {
1131+ vd->GLContext = SDL_GL_CreateContext(vd->Window);
1132+ SDL_GL_SetSwapInterval(0);
1133+ }
1134+ if (use_opengl && backup_context)
1135+ SDL_GL_MakeCurrent(vd->Window, backup_context);
1136+
1137+ viewport->PlatformHandle = (void*)(intptr_t)SDL_GetWindowID(vd->Window);
1138+ viewport->PlatformHandleRaw = nullptr;
1139+ SDL_SysWMinfo info;
1140+ SDL_VERSION(&info.version);
1141+ if (SDL_GetWindowWMInfo(vd->Window, &info))
1142+ {
1143+#if defined(SDL_VIDEO_DRIVER_WINDOWS)
1144+ viewport->PlatformHandleRaw = info.info.win.window;
1145+#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA)
1146+ viewport->PlatformHandleRaw = (void*)info.info.cocoa.window;
1147+#endif
1148+ }
1149+}
1150+
1151+static void ImGui_ImplSDL2_DestroyWindow(ImGuiViewport* viewport)
1152+{
1153+ if (ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData)
1154+ {
1155+ if (vd->GLContext && vd->WindowOwned)
1156+ SDL_GL_DeleteContext(vd->GLContext);
1157+ if (vd->Window && vd->WindowOwned)
1158+ SDL_DestroyWindow(vd->Window);
1159+ vd->GLContext = nullptr;
1160+ vd->Window = nullptr;
1161+ IM_DELETE(vd);
1162+ }
1163+ viewport->PlatformUserData = viewport->PlatformHandle = nullptr;
1164+}
1165+
1166+static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport)
1167+{
1168+ ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
1169+#if defined(_WIN32) && !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_APP) && WINAPI_FAMILY == WINAPI_FAMILY_APP) || (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES)))
1170+ HWND hwnd = (HWND)viewport->PlatformHandleRaw;
1171+
1172+ // SDL hack: Hide icon from task bar
1173+ // Note: SDL 2.0.6+ has a SDL_WINDOW_SKIP_TASKBAR flag which is supported under Windows but the way it create the window breaks our seamless transition.
1174+ if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon)
1175+ {
1176+ LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
1177+ ex_style &= ~WS_EX_APPWINDOW;
1178+ ex_style |= WS_EX_TOOLWINDOW;
1179+ ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
1180+ }
1181+#endif
1182+
1183+#if SDL_HAS_SHOW_WINDOW_ACTIVATION_HINT
1184+ SDL_SetHint(SDL_HINT_WINDOW_NO_ACTIVATION_WHEN_SHOWN, (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) ? "1" : "0");
1185+#elif defined(_WIN32)
1186+ // SDL hack: SDL always activate/focus windows :/
1187+ if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
1188+ {
1189+ ::ShowWindow(hwnd, SW_SHOWNA);
1190+ return;
1191+ }
1192+#endif
1193+ SDL_ShowWindow(vd->Window);
1194+}
1195+
1196+static ImVec2 ImGui_ImplSDL2_GetWindowPos(ImGuiViewport* viewport)
1197+{
1198+ ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
1199+ int x = 0, y = 0;
1200+ SDL_GetWindowPosition(vd->Window, &x, &y);
1201+ return ImVec2((float)x, (float)y);
1202+}
1203+
1204+static void ImGui_ImplSDL2_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
1205+{
1206+ ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
1207+ SDL_SetWindowPosition(vd->Window, (int)pos.x, (int)pos.y);
1208+}
1209+
1210+static ImVec2 ImGui_ImplSDL2_GetWindowSize(ImGuiViewport* viewport)
1211+{
1212+ ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
1213+ int w = 0, h = 0;
1214+ SDL_GetWindowSize(vd->Window, &w, &h);
1215+ return ImVec2((float)w, (float)h);
1216+}
1217+
1218+static void ImGui_ImplSDL2_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
1219+{
1220+ ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
1221+ SDL_SetWindowSize(vd->Window, (int)size.x, (int)size.y);
1222+}
1223+
1224+static ImVec2 ImGui_ImplSDL2_GetWindowFramebufferScale(ImGuiViewport* viewport)
1225+{
1226+ // FIXME: SDL_Renderer does not support multi-viewport.
1227+ ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
1228+ ImVec2 framebuffer_scale;
1229+ ImGui_ImplSDL2_GetWindowSizeAndFramebufferScale(vd->Window, nullptr, nullptr, &framebuffer_scale);
1230+ return framebuffer_scale;
1231+}
1232+
1233+static void ImGui_ImplSDL2_SetWindowTitle(ImGuiViewport* viewport, const char* title)
1234+{
1235+ ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
1236+ SDL_SetWindowTitle(vd->Window, title);
1237+}
1238+
1239+#if SDL_HAS_WINDOW_ALPHA
1240+static void ImGui_ImplSDL2_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
1241+{
1242+ ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
1243+ SDL_SetWindowOpacity(vd->Window, alpha);
1244+}
1245+#endif
1246+
1247+static void ImGui_ImplSDL2_SetWindowFocus(ImGuiViewport* viewport)
1248+{
1249+ ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
1250+ SDL_RaiseWindow(vd->Window);
1251+}
1252+
1253+static bool ImGui_ImplSDL2_GetWindowFocus(ImGuiViewport* viewport)
1254+{
1255+ ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
1256+ return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0;
1257+}
1258+
1259+static bool ImGui_ImplSDL2_GetWindowMinimized(ImGuiViewport* viewport)
1260+{
1261+ ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
1262+ return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_MINIMIZED) != 0;
1263+}
1264+
1265+static void ImGui_ImplSDL2_RenderWindow(ImGuiViewport* viewport, void*)
1266+{
1267+ ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
1268+ if (vd->GLContext)
1269+ SDL_GL_MakeCurrent(vd->Window, vd->GLContext);
1270+}
1271+
1272+static void ImGui_ImplSDL2_SwapBuffers(ImGuiViewport* viewport, void*)
1273+{
1274+ ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
1275+ if (vd->GLContext)
1276+ {
1277+ SDL_GL_MakeCurrent(vd->Window, vd->GLContext);
1278+ SDL_GL_SwapWindow(vd->Window);
1279+ }
1280+}
1281+
1282+// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface)
1283+// SDL is graceful enough to _not_ need <vulkan/vulkan.h> so we can safely include this.
1284+#if SDL_HAS_VULKAN
1285+#include <SDL_vulkan.h>
1286+static int ImGui_ImplSDL2_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface)
1287+{
1288+ ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
1289+ (void)vk_allocator;
1290+ SDL_bool ret = SDL_Vulkan_CreateSurface(vd->Window, (VkInstance)vk_instance, (VkSurfaceKHR*)out_vk_surface);
1291+ return ret ? 0 : 1; // ret ? VK_SUCCESS : VK_NOT_READY
1292+}
1293+#endif // SDL_HAS_VULKAN
1294+
1295+static void ImGui_ImplSDL2_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context)
1296+{
1297+ // Register platform interface (will be coupled with a renderer interface)
1298+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
1299+ platform_io.Platform_CreateWindow = ImGui_ImplSDL2_CreateWindow;
1300+ platform_io.Platform_DestroyWindow = ImGui_ImplSDL2_DestroyWindow;
1301+ platform_io.Platform_ShowWindow = ImGui_ImplSDL2_ShowWindow;
1302+ platform_io.Platform_SetWindowPos = ImGui_ImplSDL2_SetWindowPos;
1303+ platform_io.Platform_GetWindowPos = ImGui_ImplSDL2_GetWindowPos;
1304+ platform_io.Platform_SetWindowSize = ImGui_ImplSDL2_SetWindowSize;
1305+ platform_io.Platform_GetWindowSize = ImGui_ImplSDL2_GetWindowSize;
1306+ platform_io.Platform_GetWindowFramebufferScale = ImGui_ImplSDL2_GetWindowFramebufferScale;
1307+ platform_io.Platform_SetWindowFocus = ImGui_ImplSDL2_SetWindowFocus;
1308+ platform_io.Platform_GetWindowFocus = ImGui_ImplSDL2_GetWindowFocus;
1309+ platform_io.Platform_GetWindowMinimized = ImGui_ImplSDL2_GetWindowMinimized;
1310+ platform_io.Platform_SetWindowTitle = ImGui_ImplSDL2_SetWindowTitle;
1311+ platform_io.Platform_RenderWindow = ImGui_ImplSDL2_RenderWindow;
1312+ platform_io.Platform_SwapBuffers = ImGui_ImplSDL2_SwapBuffers;
1313+#if SDL_HAS_WINDOW_ALPHA
1314+ platform_io.Platform_SetWindowAlpha = ImGui_ImplSDL2_SetWindowAlpha;
1315+#endif
1316+#if SDL_HAS_VULKAN
1317+ platform_io.Platform_CreateVkSurface = ImGui_ImplSDL2_CreateVkSurface;
1318+#endif
1319+
1320+ // Register main window handle (which is owned by the main application, not by us)
1321+ // This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
1322+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
1323+ ImGui_ImplSDL2_ViewportData* vd = IM_NEW(ImGui_ImplSDL2_ViewportData)();
1324+ vd->Window = window;
1325+ vd->WindowID = SDL_GetWindowID(window);
1326+ vd->WindowOwned = false;
1327+ vd->GLContext = sdl_gl_context;
1328+ main_viewport->PlatformUserData = vd;
1329+ main_viewport->PlatformHandle = (void*)(intptr_t)vd->WindowID;
1330+}
1331+
1332+static void ImGui_ImplSDL2_ShutdownMultiViewportSupport()
1333+{
1334+ ImGui::DestroyPlatformWindows();
9261335 }
9271336
9281337 //-----------------------------------------------------------------------------
@@ -9,6 +9,10 @@
99 // [X] Platform: Gamepad support.
1010 // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
1111 // [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
12+// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
13+// Missing features or Issues:
14+// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
15+// [ ] Platform: Multi-viewport: Missing ImGuiBackendFlags_HasParentViewport support. The viewport->ParentViewportID field is ignored, and therefore io.ConfigViewportsNoDefaultParent has no effect either.
1216
1317 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1418 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -8,7 +8,10 @@
88 // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
99 // [X] Platform: Gamepad support.
1010 // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
11-// [X] Platform: IME support.
11+// [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue.
12+// Missing features or Issues:
13+// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
14+// [x] Platform: IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
1215
1316 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1417 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -20,6 +23,9 @@
2023
2124 // CHANGELOG
2225 // (minor and older changes stripped away, please see git history for details)
26+// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
27+// 2026-03-25: [Docking] Use SDL_HAS_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED (SDL 3.4.0+) when available to avoid refreshing monitor work area every frame on Windows. (#8415)
28+// 2026-03-09: [Docking] Fixed an issue dated 2025/04/09 (1.92 WIP) where a refactor+merge caused ImGuiBackendFlags_HasMouseHoveredViewport to never be set, causing foreign windows to be ignored when deciding of hovered viewport. (#9284)
2329 // 2026-02-13: Inputs: systems other than X11 are back to starting mouse capture on mouse down (reverts 2025-02-26 change). Only X11 requires waiting for a drag by default (not ideal, but a better default for X11 users). Added ImGui_ImplSDL3_SetMouseCaptureMode() for X11 debugger users. (#3650, #6410, #9235)
2430 // 2026-01-15: Changed GetClipboardText() handler to return nullptr on error aka clipboard contents is not text. Consistent with other backends. (#9168)
2531 // 2025-11-05: Fixed an issue with missing characters events when an already active text field changes viewports. (#9054)
@@ -28,17 +34,23 @@
2834 // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown.
2935 // 2025-09-15: Use SDL_GetWindowDisplayScale() on Mac to output DisplayFrameBufferScale. The function is more reliable during resolution changes e.g. going fullscreen. (#8703, #4414)
3036 // 2025-06-27: IME: avoid calling SDL_StartTextInput() again if already active. (#8727)
37+// 2025-05-15: [Docking] Add Platform_GetWindowFramebufferScale() handler, to allow varying Retina display density on multiple monitors.
38+// 2025-05-06: [Docking] macOS: fixed secondary viewports not appearing on other monitors before of parenting.
39+// 2025-04-09: [Docking] Revert update monitors and work areas information every frame. Only do it on Windows. (#8415, #8558)
3140 // 2025-04-22: IME: honor ImGuiPlatformImeData->WantTextInput as an alternative way to call SDL_StartTextInput(), without IME being necessarily visible.
3241 // 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561)
3342 // 2025-03-30: Update for SDL3 api changes: Revert SDL_GetClipboardText() memory ownership change. (#8530, #7801)
3443 // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set.
3544 // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468)
3645 // 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g. Linux debuggers not claiming capture back. (#6410, #3650)
46+// 2025-02-25: [Docking] Revert to use SDL_GetDisplayBounds() for WorkPos/WorkRect if SDL_GetDisplayUsableBounds() failed.
3747 // 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode.
48+// 2025-02-21: [Docking] Update monitors and work areas information every frame, as the later may change regardless of monitor changes. (#8415)
3849 // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support.
3950 // 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler.
4051 // 2025-01-20: Made ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode_Manual) accept an empty array.
4152 // 2024-10-24: Emscripten: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f on Emscripten.
53+// 2024-09-11: (Docking) Added support for viewport->ParentViewportId field to support parenting at OS level. (#7973)
4254 // 2024-09-03: Update for SDL3 api changes: SDL_GetGamepads() memory ownership revert. (#7918, #7898, #7807)
4355 // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
4456 // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
@@ -94,6 +106,7 @@
94106 #else
95107 #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0
96108 #endif
109+#define SDL_HAS_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED SDL_VERSION_ATLEAST(3,4,0)
97110
98111 // FIXME-LEGACY: remove when SDL 3.1.3 preview is released.
99112 #ifndef SDLK_APOSTROPHE
@@ -112,6 +125,8 @@
112125 Uint64 Time;
113126 char* ClipboardTextData;
114127 char BackendPlatformName[48];
128+ bool UseVulkan;
129+ bool WantUpdateMonitors;
115130
116131 // IME handling
117132 SDL_Window* ImeWindow;
@@ -125,12 +140,13 @@
125140 SDL_Cursor* MouseLastCursor;
126141 int MousePendingLeaveFrame;
127142 bool MouseCanUseGlobalState;
143+ bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state.
128144 ImGui_ImplSDL3_MouseCaptureMode MouseCaptureMode;
129145
130146 // Gamepad handling
131- ImVector<SDL_Gamepad*> Gamepads;
147+ ImVector<SDL_Gamepad*> Gamepads;
132148 ImGui_ImplSDL3_GamepadMode GamepadMode;
133- bool WantUpdateGamepadsList;
149+ bool WantUpdateGamepadsList;
134150
135151 ImGui_ImplSDL3_Data() { memset((void*)this, 0, sizeof(*this)); }
136152 };
@@ -146,6 +162,9 @@
146162
147163 // Forward Declarations
148164 static void ImGui_ImplSDL3_UpdateIme();
165+static void ImGui_ImplSDL3_UpdateMonitors();
166+static void ImGui_ImplSDL3_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context);
167+static void ImGui_ImplSDL3_ShutdownMultiViewportSupport();
149168
150169 // Functions
151170 static const char* ImGui_ImplSDL3_GetClipboardText(ImGuiContext*)
@@ -167,8 +186,7 @@
167186
168187 static ImGuiViewport* ImGui_ImplSDL3_GetViewportForWindowID(SDL_WindowID window_id)
169188 {
170- ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
171- return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : nullptr;
189+ return ImGui::FindViewportByPlatformHandle((void*)(intptr_t)window_id);
172190 }
173191
174192 static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport*, ImGuiPlatformImeData* data)
@@ -199,9 +217,12 @@
199217 bd->ImeDirty = false;
200218 if (data->WantVisible)
201219 {
220+ ImVec2 viewport_pos;
221+ if (ImGuiViewport* viewport = ImGui_ImplSDL3_GetViewportForWindowID(SDL_GetWindowID(window)))
222+ viewport_pos = viewport->Pos;
202223 SDL_Rect r;
203- r.x = (int)data->InputPos.x;
204- r.y = (int)data->InputPos.y;
224+ r.x = (int)(data->InputPos.x - viewport_pos.x);
225+ r.y = (int)(data->InputPos.y - viewport_pos.y);
205226 r.w = 1;
206227 r.h = (int)data->InputLineHeight;
207228 SDL_SetTextInputArea(window, &r, 0);
@@ -390,6 +411,13 @@
390411 if (ImGui_ImplSDL3_GetViewportForWindowID(event->motion.windowID) == nullptr)
391412 return false;
392413 ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y);
414+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
415+ {
416+ int window_x, window_y;
417+ SDL_GetWindowPosition(SDL_GetWindowFromID(event->motion.windowID), &window_x, &window_y);
418+ mouse_pos.x += window_x;
419+ mouse_pos.y += window_y;
420+ }
393421 io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse);
394422 io.AddMousePosEvent(mouse_pos.x, mouse_pos.y);
395423 return true;
@@ -433,16 +461,29 @@
433461 case SDL_EVENT_KEY_DOWN:
434462 case SDL_EVENT_KEY_UP:
435463 {
436- if (ImGui_ImplSDL3_GetViewportForWindowID(event->key.windowID) == nullptr)
464+ ImGuiViewport* viewport = ImGui_ImplSDL3_GetViewportForWindowID(event->key.windowID);
465+ if (viewport == nullptr)
437466 return false;
467+ //IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%s : key=0x%08X ('%s'), scancode=%d ('%s'), mod=%X, windowID=%d, viewport=%08X\n",
468+ // (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP ", event->key.key, SDL_GetKeyName(event->key.key), event->key.scancode, SDL_GetScancodeName(event->key.scancode), event->key.mod, event->key.windowID, viewport ? viewport->ID : 0);
438469 ImGui_ImplSDL3_UpdateKeyModifiers((SDL_Keymod)event->key.mod);
439- //IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%s : key=%d ('%s'), scancode=%d ('%s'), mod=%X\n",
440- // (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP ", event->key.key, SDL_GetKeyName(event->key.key), event->key.scancode, SDL_GetScancodeName(event->key.scancode), event->key.mod);
441470 ImGuiKey key = ImGui_ImplSDL3_KeyEventToImGuiKey(event->key.key, event->key.scancode);
442471 io.AddKeyEvent(key, (event->type == SDL_EVENT_KEY_DOWN));
443472 io.SetKeyEventNativeData(key, (int)event->key.key, (int)event->key.scancode, (int)event->key.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
444473 return true;
445474 }
475+ case SDL_EVENT_DISPLAY_ORIENTATION:
476+ case SDL_EVENT_DISPLAY_ADDED:
477+ case SDL_EVENT_DISPLAY_REMOVED:
478+ case SDL_EVENT_DISPLAY_MOVED:
479+ case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED:
480+#if SDL_HAS_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED
481+ case SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED:
482+#endif
483+ {
484+ bd->WantUpdateMonitors = true;
485+ return true;
486+ }
446487 case SDL_EVENT_WINDOW_MOUSE_ENTER:
447488 {
448489 if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == nullptr)
@@ -465,11 +506,28 @@
465506 case SDL_EVENT_WINDOW_FOCUS_GAINED:
466507 case SDL_EVENT_WINDOW_FOCUS_LOST:
467508 {
468- if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == nullptr)
509+ ImGuiViewport* viewport = ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID);
510+ if (viewport == nullptr)
469511 return false;
512+ //IMGUI_DEBUG_LOG("%s: windowId %d, viewport: %08X\n", (event->type == SDL_EVENT_WINDOW_FOCUS_GAINED) ? "SDL_EVENT_WINDOW_FOCUS_GAINED" : "SDL_WINDOWEVENT_FOCUS_LOST", event->window.windowID, viewport ? viewport->ID : 0);
470513 io.AddFocusEvent(event->type == SDL_EVENT_WINDOW_FOCUS_GAINED);
471514 return true;
472515 }
516+ case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
517+ case SDL_EVENT_WINDOW_MOVED:
518+ case SDL_EVENT_WINDOW_RESIZED:
519+ {
520+ ImGuiViewport* viewport = ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID);
521+ if (viewport == NULL)
522+ return false;
523+ if (event->type == SDL_EVENT_WINDOW_CLOSE_REQUESTED)
524+ viewport->PlatformRequestClose = true;
525+ if (event->type == SDL_EVENT_WINDOW_MOVED)
526+ viewport->PlatformRequestMove = true;
527+ if (event->type == SDL_EVENT_WINDOW_RESIZED)
528+ viewport->PlatformRequestResize = true;
529+ return true;
530+ }
473531 case SDL_EVENT_GAMEPAD_ADDED:
474532 case SDL_EVENT_GAMEPAD_REMOVED:
475533 {
@@ -511,6 +569,8 @@
511569 io.BackendPlatformName = bd->BackendPlatformName;
512570 io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
513571 io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
572+ // (ImGuiBackendFlags_PlatformHasViewports and ImGuiBackendFlags_HasParentViewport may be set just below)
573+ // (ImGuiBackendFlags_HasMouseHoveredViewport is set dynamically in our _NewFrame function)
514574
515575 bd->Window = window;
516576 bd->WindowID = SDL_GetWindowID(window);
@@ -530,13 +590,29 @@
530590 bd->MouseCaptureMode = (strcmp(item, "x11") == 0) ? ImGui_ImplSDL3_MouseCaptureMode_EnabledAfterDrag : ImGui_ImplSDL3_MouseCaptureMode_Enabled;
531591 }
532592 #endif
593+ if (bd->MouseCanUseGlobalState)
594+ {
595+ io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
596+ io.BackendFlags |= ImGuiBackendFlags_HasParentViewport; // We can honor viewport->ParentViewportId by applying the corresponding parent/child relationship at platform level (optional)
597+ }
533598
599+ // SDL on Linux/OSX doesn't report events for unfocused windows (see https://github.com/ocornut/imgui/issues/4960)
600+ // We will use 'MouseCanReportHoveredViewport' to set 'ImGuiBackendFlags_HasMouseHoveredViewport' dynamically each frame.
601+#ifndef __APPLE__
602+ bd->MouseCanReportHoveredViewport = bd->MouseCanUseGlobalState;
603+#else
604+ bd->MouseCanReportHoveredViewport = false;
605+#endif
606+
534607 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
535608 platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText;
536609 platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText;
537610 platform_io.Platform_SetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData;
538611 platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { return SDL_OpenURL(url); };
539612
613+ // Update monitor a first time during init
614+ ImGui_ImplSDL3_UpdateMonitors();
615+
540616 // Gamepad handling
541617 bd->GamepadMode = ImGui_ImplSDL3_GamepadMode_AutoFirst;
542618 bd->WantUpdateGamepadsList = true;
@@ -569,6 +645,14 @@
569645 // From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710)
570646 SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0");
571647
648+ // SDL 3.x : see https://github.com/libsdl-org/SDL/issues/6659
649+ SDL_SetHint("SDL_BORDERLESS_WINDOWED_STYLE", "0");
650+
651+ // We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports.
652+ // We left the call to ImGui_ImplSDL3_InitPlatformInterface() outside of #ifdef to avoid unused-function warnings.
653+ if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports)
654+ ImGui_ImplSDL3_InitMultiViewportSupport(window, sdl_gl_context);
655+
572656 return true;
573657 }
574658
@@ -580,7 +664,11 @@
580664
581665 bool ImGui_ImplSDL3_InitForVulkan(SDL_Window* window)
582666 {
583- return ImGui_ImplSDL3_Init(window, nullptr, nullptr);
667+ if (!ImGui_ImplSDL3_Init(window, nullptr, nullptr))
668+ return false;
669+ ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
670+ bd->UseVulkan = true;
671+ return true;
584672 }
585673
586674 bool ImGui_ImplSDL3_InitForD3D(SDL_Window* window)
@@ -620,6 +708,7 @@
620708 ImGuiIO& io = ImGui::GetIO();
621709 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
622710
711+ ImGui_ImplSDL3_ShutdownMultiViewportSupport();
623712 if (bd->ClipboardTextData)
624713 SDL_free(bd->ClipboardTextData);
625714 for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
@@ -628,7 +717,7 @@
628717
629718 io.BackendPlatformName = nullptr;
630719 io.BackendPlatformUserData = nullptr;
631- io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
720+ io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport | ImGuiBackendFlags_HasParentViewport);
632721 platform_io.ClearPlatformHandlers();
633722 IM_DELETE(bd);
634723 }
@@ -664,7 +753,7 @@
664753 }
665754
666755 SDL_Window* focused_window = SDL_GetKeyboardFocus();
667- const bool is_app_focused = (bd->Window == focused_window);
756+ const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui_ImplSDL3_GetViewportForWindowID(SDL_GetWindowID(focused_window)) != NULL));
668757 #else
669758 SDL_Window* focused_window = bd->Window;
670759 const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only
@@ -673,7 +762,14 @@
673762 {
674763 // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
675764 if (io.WantSetMousePos)
676- SDL_WarpMouseInWindow(bd->Window, io.MousePos.x, io.MousePos.y);
765+ {
766+#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
767+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
768+ SDL_WarpMouseGlobal(io.MousePos.x, io.MousePos.y);
769+ else
770+#endif
771+ SDL_WarpMouseInWindow(bd->Window, io.MousePos.x, io.MousePos.y);
772+ }
677773
678774 // (Optional) Fallback to provide unclamped mouse position when focused but not hovered (SDL_EVENT_MOUSE_MOTION already provides this when hovered or captured)
679775 // 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.
@@ -682,15 +778,34 @@
682778 if (hovered_window == nullptr && bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode)
683779 {
684780 // 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)
781+ // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
685782 float mouse_x, mouse_y;
686783 int window_x, window_y;
687784 SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
688- SDL_GetWindowPosition(focused_window, &window_x, &window_y);
689- mouse_x -= (float)window_x;
690- mouse_y -= (float)window_y;
785+ if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable))
786+ {
787+ SDL_GetWindowPosition(focused_window, &window_x, &window_y);
788+ mouse_x -= (float)window_x;
789+ mouse_y -= (float)window_y;
790+ }
691791 io.AddMousePosEvent(mouse_x, mouse_y);
692792 }
693793 }
794+
795+ // (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
796+ // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic.
797+ // - [!] SDL backend does NOT correctly ignore viewports with the _NoInputs flag.
798+ // Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window
799+ // for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported
800+ // by the backend, and use its flawed heuristic to guess the viewport behind.
801+ // - [X] SDL backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target).
802+ if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)
803+ {
804+ ImGuiID mouse_viewport_id = 0;
805+ if (ImGuiViewport* mouse_viewport = ImGui_ImplSDL3_GetViewportForWindowID(bd->MouseWindowID))
806+ mouse_viewport_id = mouse_viewport->ID;
807+ io.AddMouseViewportEvent(mouse_viewport_id);
808+ }
694809 }
695810
696811 static void ImGui_ImplSDL3_UpdateMouseCursor()
@@ -822,6 +937,38 @@
822937 ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL_GAMEPAD_AXIS_RIGHTY, +thumb_dead_zone, +32767);
823938 }
824939
940+static void ImGui_ImplSDL3_UpdateMonitors()
941+{
942+ ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
943+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
944+ platform_io.Monitors.resize(0);
945+ bd->WantUpdateMonitors = false;
946+
947+ int display_count;
948+ SDL_DisplayID* displays = SDL_GetDisplays(&display_count);
949+ for (int n = 0; n < display_count; n++)
950+ {
951+ // Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime.
952+ SDL_DisplayID display_id = displays[n];
953+ ImGuiPlatformMonitor monitor;
954+ SDL_Rect r;
955+ SDL_GetDisplayBounds(display_id, &r);
956+ monitor.MainPos = monitor.WorkPos = ImVec2((float)r.x, (float)r.y);
957+ monitor.MainSize = monitor.WorkSize = ImVec2((float)r.w, (float)r.h);
958+ if (SDL_GetDisplayUsableBounds(display_id, &r) && r.w > 0 && r.h > 0)
959+ {
960+ monitor.WorkPos = ImVec2((float)r.x, (float)r.y);
961+ monitor.WorkSize = ImVec2((float)r.w, (float)r.h);
962+ }
963+ monitor.DpiScale = SDL_GetDisplayContentScale(display_id); // See https://wiki.libsdl.org/SDL3/README-highdpi for details.
964+ monitor.PlatformHandle = (void*)(intptr_t)n;
965+ if (monitor.DpiScale <= 0.0f)
966+ continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902.
967+ platform_io.Monitors.push_back(monitor);
968+ }
969+ SDL_free(displays);
970+}
971+
825972 static void ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale(SDL_Window* window, ImVec2* out_size, ImVec2* out_framebuffer_scale)
826973 {
827974 int w, h;
@@ -854,6 +1001,13 @@
8541001 // Setup main viewport size (every frame to accommodate for window resizing)
8551002 ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale(bd->Window, &io.DisplaySize, &io.DisplayFramebufferScale);
8561003
1004+ // Update monitors
1005+#if defined(WIN32) && !SDL_HAS_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED
1006+ bd->WantUpdateMonitors = true; // Keep polling under Windows to handle changes of work area when resizing task-bar (#8415)
1007+#endif
1008+ if (bd->WantUpdateMonitors)
1009+ ImGui_ImplSDL3_UpdateMonitors();
1010+
8571011 // Setup time step (we could also use SDL_GetTicksNS() available since SDL3)
8581012 // (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644)
8591013 static Uint64 frequency = SDL_GetPerformanceFrequency();
@@ -870,12 +1024,285 @@
8701024 io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
8711025 }
8721026
1027+ // Our io.AddMouseViewportEvent() calls will only be valid when not capturing.
1028+ // Technically speaking testing for 'bd->MouseButtonsDown == 0' would be more rigorous, but testing for payload reduces noise and potential side-effects.
1029+ if (bd->MouseCanReportHoveredViewport && ImGui::GetDragDropPayload() == nullptr)
1030+ io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport;
1031+ else
1032+ io.BackendFlags &= ~ImGuiBackendFlags_HasMouseHoveredViewport;
1033+
8731034 ImGui_ImplSDL3_UpdateMouseData();
8741035 ImGui_ImplSDL3_UpdateMouseCursor();
8751036 ImGui_ImplSDL3_UpdateIme();
8761037
8771038 // Update game controllers (if enabled and available)
8781039 ImGui_ImplSDL3_UpdateGamepads();
1040+}
1041+
1042+//--------------------------------------------------------------------------------------------------------
1043+// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
1044+// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
1045+// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
1046+//--------------------------------------------------------------------------------------------------------
1047+
1048+// Helper structure we store in the void* PlatformUserData field of each ImGuiViewport to easily retrieve our backend data.
1049+struct ImGui_ImplSDL3_ViewportData
1050+{
1051+ SDL_Window* Window;
1052+ SDL_Window* ParentWindow;
1053+ Uint32 WindowID; // Stored in ImGuiViewport::PlatformHandle. Use SDL_GetWindowFromID() to get SDL_Window* from Uint32 WindowID.
1054+ bool WindowOwned;
1055+ SDL_GLContext GLContext;
1056+
1057+ ImGui_ImplSDL3_ViewportData() { Window = ParentWindow = nullptr; WindowID = 0; WindowOwned = false; GLContext = nullptr; }
1058+ ~ImGui_ImplSDL3_ViewportData() { IM_ASSERT(Window == nullptr && GLContext == nullptr); }
1059+};
1060+
1061+static SDL_Window* ImGui_ImplSDL3_GetSDLWindowFromViewport(ImGuiViewport* viewport)
1062+{
1063+ if (viewport != nullptr)
1064+ {
1065+ SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle;
1066+ return SDL_GetWindowFromID(window_id);
1067+ }
1068+ return nullptr;
1069+}
1070+
1071+static void ImGui_ImplSDL3_CreateWindow(ImGuiViewport* viewport)
1072+{
1073+ ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
1074+ ImGui_ImplSDL3_ViewportData* vd = IM_NEW(ImGui_ImplSDL3_ViewportData)();
1075+ viewport->PlatformUserData = vd;
1076+
1077+ vd->ParentWindow = ImGui_ImplSDL3_GetSDLWindowFromViewport(viewport->ParentViewport);
1078+
1079+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
1080+ ImGui_ImplSDL3_ViewportData* main_viewport_data = (ImGui_ImplSDL3_ViewportData*)main_viewport->PlatformUserData;
1081+
1082+ // Share GL resources with main context
1083+ bool use_opengl = (main_viewport_data->GLContext != nullptr);
1084+ SDL_GLContext backup_context = nullptr;
1085+ if (use_opengl)
1086+ {
1087+ backup_context = SDL_GL_GetCurrentContext();
1088+ SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
1089+ SDL_GL_MakeCurrent(main_viewport_data->Window, main_viewport_data->GLContext);
1090+ }
1091+
1092+ SDL_WindowFlags sdl_flags = 0;
1093+ sdl_flags |= SDL_WINDOW_HIDDEN;
1094+ sdl_flags |= use_opengl ? SDL_WINDOW_OPENGL : (bd->UseVulkan ? SDL_WINDOW_VULKAN : 0);
1095+ sdl_flags |= SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_HIGH_PIXEL_DENSITY;
1096+ sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0;
1097+ sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE;
1098+ sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) ? SDL_WINDOW_UTILITY : 0;
1099+ sdl_flags |= (viewport->Flags & ImGuiViewportFlags_TopMost) ? SDL_WINDOW_ALWAYS_ON_TOP : 0;
1100+ vd->Window = SDL_CreateWindow("No Title Yet", (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags);
1101+#ifndef __APPLE__ // On Mac, SDL3 Parenting appears to prevent viewport from appearing in another monitor
1102+ SDL_SetWindowParent(vd->Window, vd->ParentWindow);
1103+#endif
1104+ SDL_SetWindowPosition(vd->Window, (int)viewport->Pos.x, (int)viewport->Pos.y);
1105+ vd->WindowOwned = true;
1106+ if (use_opengl)
1107+ {
1108+ vd->GLContext = SDL_GL_CreateContext(vd->Window);
1109+ SDL_GL_SetSwapInterval(0);
1110+ }
1111+ if (use_opengl && backup_context)
1112+ SDL_GL_MakeCurrent(vd->Window, backup_context);
1113+
1114+ ImGui_ImplSDL3_SetupPlatformHandles(viewport, vd->Window);
1115+}
1116+
1117+static void ImGui_ImplSDL3_DestroyWindow(ImGuiViewport* viewport)
1118+{
1119+ if (ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData)
1120+ {
1121+ if (vd->GLContext && vd->WindowOwned)
1122+ SDL_GL_DestroyContext(vd->GLContext);
1123+ if (vd->Window && vd->WindowOwned)
1124+ SDL_DestroyWindow(vd->Window);
1125+ vd->GLContext = nullptr;
1126+ vd->Window = nullptr;
1127+ IM_DELETE(vd);
1128+ }
1129+ viewport->PlatformUserData = viewport->PlatformHandle = nullptr;
1130+}
1131+
1132+static void ImGui_ImplSDL3_ShowWindow(ImGuiViewport* viewport)
1133+{
1134+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1135+#if defined(_WIN32) && !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_APP) && WINAPI_FAMILY == WINAPI_FAMILY_APP) || (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES)))
1136+ HWND hwnd = (HWND)viewport->PlatformHandleRaw;
1137+
1138+ // SDL hack: Show icon in task bar (#7989)
1139+ // Note: SDL_WINDOW_UTILITY can be used to control task bar visibility, but on Windows, it does not affect child windows.
1140+ if (!(viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon))
1141+ {
1142+ LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
1143+ ex_style |= WS_EX_APPWINDOW;
1144+ ex_style &= ~WS_EX_TOOLWINDOW;
1145+ ::ShowWindow(hwnd, SW_HIDE);
1146+ ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
1147+ }
1148+#endif
1149+
1150+#ifdef __APPLE__
1151+ SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_SHOWN, "1"); // Otherwise new window appear under
1152+#else
1153+ SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_SHOWN, (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) ? "0" : "1");
1154+#endif
1155+ SDL_ShowWindow(vd->Window);
1156+}
1157+
1158+static void ImGui_ImplSDL3_UpdateWindow(ImGuiViewport* viewport)
1159+{
1160+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1161+ IM_UNUSED(vd);
1162+
1163+#ifndef __APPLE__ // On Mac, SDL3 Parenting appears to prevent viewport from appearing in another monitor
1164+ // Update SDL3 parent if it changed _after_ creation.
1165+ // This is for advanced apps that are manipulating ParentViewportID manually.
1166+ SDL_Window* new_parent = ImGui_ImplSDL3_GetSDLWindowFromViewport(viewport->ParentViewport);
1167+ if (new_parent != vd->ParentWindow)
1168+ {
1169+ vd->ParentWindow = new_parent;
1170+ SDL_SetWindowParent(vd->Window, vd->ParentWindow);
1171+ }
1172+#endif
1173+}
1174+
1175+static ImVec2 ImGui_ImplSDL3_GetWindowPos(ImGuiViewport* viewport)
1176+{
1177+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1178+ int x = 0, y = 0;
1179+ SDL_GetWindowPosition(vd->Window, &x, &y);
1180+ return ImVec2((float)x, (float)y);
1181+}
1182+
1183+static void ImGui_ImplSDL3_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
1184+{
1185+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1186+ SDL_SetWindowPosition(vd->Window, (int)pos.x, (int)pos.y);
1187+}
1188+
1189+static ImVec2 ImGui_ImplSDL3_GetWindowSize(ImGuiViewport* viewport)
1190+{
1191+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1192+ int w = 0, h = 0;
1193+ SDL_GetWindowSize(vd->Window, &w, &h);
1194+ return ImVec2((float)w, (float)h);
1195+}
1196+
1197+static void ImGui_ImplSDL3_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
1198+{
1199+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1200+ SDL_SetWindowSize(vd->Window, (int)size.x, (int)size.y);
1201+}
1202+
1203+static ImVec2 ImGui_ImplSDL3_GetWindowFramebufferScale(ImGuiViewport* viewport)
1204+{
1205+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1206+ ImVec2 framebuffer_scale;
1207+ ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale(vd->Window, nullptr, &framebuffer_scale);
1208+ return framebuffer_scale;
1209+}
1210+
1211+static void ImGui_ImplSDL3_SetWindowTitle(ImGuiViewport* viewport, const char* title)
1212+{
1213+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1214+ SDL_SetWindowTitle(vd->Window, title);
1215+}
1216+
1217+static void ImGui_ImplSDL3_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
1218+{
1219+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1220+ SDL_SetWindowOpacity(vd->Window, alpha);
1221+}
1222+
1223+static void ImGui_ImplSDL3_SetWindowFocus(ImGuiViewport* viewport)
1224+{
1225+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1226+ SDL_RaiseWindow(vd->Window);
1227+}
1228+
1229+static bool ImGui_ImplSDL3_GetWindowFocus(ImGuiViewport* viewport)
1230+{
1231+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1232+ return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0;
1233+}
1234+
1235+static bool ImGui_ImplSDL3_GetWindowMinimized(ImGuiViewport* viewport)
1236+{
1237+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1238+ return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_MINIMIZED) != 0;
1239+}
1240+
1241+static void ImGui_ImplSDL3_RenderWindow(ImGuiViewport* viewport, void*)
1242+{
1243+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1244+ if (vd->GLContext)
1245+ SDL_GL_MakeCurrent(vd->Window, vd->GLContext);
1246+}
1247+
1248+static void ImGui_ImplSDL3_SwapBuffers(ImGuiViewport* viewport, void*)
1249+{
1250+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1251+ if (vd->GLContext)
1252+ {
1253+ SDL_GL_MakeCurrent(vd->Window, vd->GLContext);
1254+ SDL_GL_SwapWindow(vd->Window);
1255+ }
1256+}
1257+
1258+// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface)
1259+// SDL is graceful enough to _not_ need <vulkan/vulkan.h> so we can safely include this.
1260+#include <SDL3/SDL_vulkan.h>
1261+static int ImGui_ImplSDL3_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface)
1262+{
1263+ ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
1264+ (void)vk_allocator;
1265+ bool ret = SDL_Vulkan_CreateSurface(vd->Window, (VkInstance)vk_instance, (const VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface);
1266+ return ret ? 0 : 1; // ret ? VK_SUCCESS : VK_NOT_READY
1267+}
1268+
1269+static void ImGui_ImplSDL3_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context)
1270+{
1271+ // Register platform interface (will be coupled with a renderer interface)
1272+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
1273+ platform_io.Platform_CreateWindow = ImGui_ImplSDL3_CreateWindow;
1274+ platform_io.Platform_DestroyWindow = ImGui_ImplSDL3_DestroyWindow;
1275+ platform_io.Platform_ShowWindow = ImGui_ImplSDL3_ShowWindow;
1276+ platform_io.Platform_UpdateWindow = ImGui_ImplSDL3_UpdateWindow;
1277+ platform_io.Platform_SetWindowPos = ImGui_ImplSDL3_SetWindowPos;
1278+ platform_io.Platform_GetWindowPos = ImGui_ImplSDL3_GetWindowPos;
1279+ platform_io.Platform_SetWindowSize = ImGui_ImplSDL3_SetWindowSize;
1280+ platform_io.Platform_GetWindowSize = ImGui_ImplSDL3_GetWindowSize;
1281+ platform_io.Platform_GetWindowFramebufferScale = ImGui_ImplSDL3_GetWindowFramebufferScale;
1282+ platform_io.Platform_SetWindowFocus = ImGui_ImplSDL3_SetWindowFocus;
1283+ platform_io.Platform_GetWindowFocus = ImGui_ImplSDL3_GetWindowFocus;
1284+ platform_io.Platform_GetWindowMinimized = ImGui_ImplSDL3_GetWindowMinimized;
1285+ platform_io.Platform_SetWindowTitle = ImGui_ImplSDL3_SetWindowTitle;
1286+ platform_io.Platform_RenderWindow = ImGui_ImplSDL3_RenderWindow;
1287+ platform_io.Platform_SwapBuffers = ImGui_ImplSDL3_SwapBuffers;
1288+ platform_io.Platform_SetWindowAlpha = ImGui_ImplSDL3_SetWindowAlpha;
1289+ platform_io.Platform_CreateVkSurface = ImGui_ImplSDL3_CreateVkSurface;
1290+
1291+ // Register main window handle (which is owned by the main application, not by us)
1292+ // This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
1293+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
1294+ ImGui_ImplSDL3_ViewportData* vd = IM_NEW(ImGui_ImplSDL3_ViewportData)();
1295+ vd->Window = window;
1296+ vd->WindowID = SDL_GetWindowID(window);
1297+ vd->WindowOwned = false;
1298+ vd->GLContext = (SDL_GLContext)sdl_gl_context;
1299+ main_viewport->PlatformUserData = vd;
1300+ main_viewport->PlatformHandle = (void*)(intptr_t)vd->WindowID;
1301+}
1302+
1303+static void ImGui_ImplSDL3_ShutdownMultiViewportSupport()
1304+{
1305+ ImGui::DestroyPlatformWindows();
8791306 }
8801307
8811308 //-----------------------------------------------------------------------------
@@ -8,7 +8,10 @@
88 // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
99 // [X] Platform: Gamepad support.
1010 // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
11-// [X] Platform: IME support.
11+// [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue.
12+// Missing features or Issues:
13+// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
14+// [x] Platform: IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
1215
1316 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1417 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -5,6 +5,7 @@
55 // [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct.
66 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
77 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
8+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
89
910 // The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification.
1011 // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
@@ -22,6 +23,7 @@
2223 // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info.
2324
2425 // CHANGELOG
26+// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
2527 // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplSDLGPU3_RenderState. (#9378)
2628 // 2026-03-19: Fixed issue in ImGui_ImplSDLGPU3_DestroyTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310)
2729 // 2026-02-25: Removed unnecessary call to SDL_WaitForGPUIdle when releasing vertex/index buffers. (#9262)
@@ -652,6 +654,9 @@
652654 if (bd->Pipeline) { SDL_ReleaseGPUGraphicsPipeline(v->Device, bd->Pipeline); bd->Pipeline = nullptr; }
653655 }
654656
657+static void ImGui_ImplSDLGPU3_InitMultiViewportSupport();
658+static void ImGui_ImplSDLGPU3_ShutdownMultiViewportSupport();
659+
655660 bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info)
656661 {
657662 ImGuiIO& io = ImGui::GetIO();
@@ -664,6 +669,7 @@
664669 io.BackendRendererName = "imgui_impl_sdlgpu3";
665670 io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
666671 io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
672+ io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
667673
668674 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
669675 platform_io.DrawCallback_ResetRenderState = ImGui_ImplSDLGPU3_DrawCallback_ResetRenderState;
@@ -675,6 +681,8 @@
675681
676682 bd->InitInfo = *info;
677683
684+ ImGui_ImplSDLGPU3_InitMultiViewportSupport();
685+
678686 return true;
679687 }
680688
@@ -685,11 +693,12 @@
685693 ImGuiIO& io = ImGui::GetIO();
686694 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
687695
696+ ImGui_ImplSDLGPU3_ShutdownMultiViewportSupport();
688697 ImGui_ImplSDLGPU3_DestroyDeviceObjects();
689698
690699 io.BackendRendererName = nullptr;
691700 io.BackendRendererUserData = nullptr;
692- io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
701+ io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
693702 platform_io.ClearRendererHandlers();
694703 IM_DELETE(bd);
695704 }
@@ -702,5 +711,77 @@
702711 if (!bd->TexSamplerLinear)
703712 ImGui_ImplSDLGPU3_CreateDeviceObjects();
704713 }
714+
715+//--------------------------------------------------------------------------------------------------------
716+// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
717+// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
718+// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
719+//--------------------------------------------------------------------------------------------------------
720+
721+static void ImGui_ImplSDLGPU3_CreateWindow(ImGuiViewport* viewport)
722+{
723+ ImGui_ImplSDLGPU3_Data* data = ImGui_ImplSDLGPU3_GetBackendData();
724+ SDL_Window* window = SDL_GetWindowFromID((SDL_WindowID)(intptr_t)viewport->PlatformHandle);
725+ SDL_ClaimWindowForGPUDevice(data->InitInfo.Device, window);
726+ SDL_SetGPUSwapchainParameters(data->InitInfo.Device, window, data->InitInfo.SwapchainComposition, data->InitInfo.PresentMode);
727+ viewport->RendererUserData = (void*)1;
728+}
729+
730+static void ImGui_ImplSDLGPU3_RenderWindow(ImGuiViewport* viewport, void*)
731+{
732+ ImGui_ImplSDLGPU3_Data* data = ImGui_ImplSDLGPU3_GetBackendData();
733+ SDL_Window* window = SDL_GetWindowFromID((SDL_WindowID)(intptr_t)viewport->PlatformHandle);
734+
735+ ImDrawData* draw_data = viewport->DrawData;
736+
737+ SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(data->InitInfo.Device);
738+
739+ SDL_GPUTexture* swapchain_texture;
740+ SDL_AcquireGPUSwapchainTexture(command_buffer, window, &swapchain_texture, nullptr, nullptr);
741+
742+ if (swapchain_texture != nullptr)
743+ {
744+ ImGui_ImplSDLGPU3_PrepareDrawData(draw_data, command_buffer); // FIXME-OPT: Not optimal, may this be done earlier?
745+ SDL_GPUColorTargetInfo target_info = {};
746+ target_info.texture = swapchain_texture;
747+ target_info.clear_color = SDL_FColor{ 0.0f,0.0f,0.0f,1.0f };
748+ target_info.load_op = SDL_GPU_LOADOP_CLEAR;
749+ target_info.store_op = SDL_GPU_STOREOP_STORE;
750+ target_info.mip_level = 0;
751+ target_info.layer_or_depth_plane = 0;
752+ target_info.cycle = false;
753+ SDL_GPURenderPass* render_pass = SDL_BeginGPURenderPass(command_buffer, &target_info, 1, nullptr);
754+ ImGui_ImplSDLGPU3_RenderDrawData(draw_data, command_buffer, render_pass);
755+ SDL_EndGPURenderPass(render_pass);
756+ }
757+
758+ SDL_SubmitGPUCommandBuffer(command_buffer);
759+}
760+
761+static void ImGui_ImplSDLGPU3_DestroyWindow(ImGuiViewport* viewport)
762+{
763+ ImGui_ImplSDLGPU3_Data* data = ImGui_ImplSDLGPU3_GetBackendData();
764+ if (viewport->RendererUserData)
765+ {
766+ SDL_Window* window = SDL_GetWindowFromID((SDL_WindowID)(intptr_t)viewport->PlatformHandle);
767+ SDL_ReleaseWindowFromGPUDevice(data->InitInfo.Device, window);
768+ }
769+ viewport->RendererUserData = nullptr;
770+}
771+
772+static void ImGui_ImplSDLGPU3_InitMultiViewportSupport()
773+{
774+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
775+ platform_io.Renderer_RenderWindow = ImGui_ImplSDLGPU3_RenderWindow;
776+ platform_io.Renderer_CreateWindow = ImGui_ImplSDLGPU3_CreateWindow;
777+ platform_io.Renderer_DestroyWindow = ImGui_ImplSDLGPU3_DestroyWindow;
778+}
779+
780+static void ImGui_ImplSDLGPU3_ShutdownMultiViewportSupport()
781+{
782+ ImGui::DestroyPlatformWindows();
783+}
784+
785+//-----------------------------------------------------------------------------
705786
706787 #endif // #ifndef IMGUI_DISABLE
@@ -5,6 +5,7 @@
55 // [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct.
66 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
77 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
8+// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
89
910 // The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification.
1011 // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
@@ -15,6 +15,7 @@
1515 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
1616 // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
1717 // Missing features or Issues:
18+// [ ] Renderer: Multi-viewport support (multiple windows).
1819 // [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: SDLRenderer2 does not support changing SDL_SCALE_MODE while rendering.
1920
2021 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
@@ -15,6 +15,7 @@
1515 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
1616 // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
1717 // Missing features or Issues:
18+// [ ] Renderer: Multi-viewport support (multiple windows).
1819 // [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: SDLRenderer2 does not support changing SDL_SCALE_MODE while rendering.
1920
2021 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
@@ -14,6 +14,8 @@
1414 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
1515 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
1616 // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
17+// Missing features:
18+// [ ] Renderer: Multi-viewport support (multiple windows).
1719
1820 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1921 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -14,6 +14,8 @@
1414 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
1515 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
1616 // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
17+// Missing features:
18+// [ ] Renderer: Multi-viewport support (multiple windows).
1719
1820 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1921 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -6,6 +6,7 @@
66 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
77 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
88 // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
9+// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
910
1011 // The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
1112 // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
@@ -27,6 +28,7 @@
2728
2829 // CHANGELOG
2930 // (minor and older changes stripped away, please see git history for details)
31+// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
3032 // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
3133 // 2026-04-22: *BREAKING CHANGE* redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. This change allows us to facilitate changing samplers, in line with other backends.
3234 // - When registering custom textures: changed ImGui_ImplVulkan_AddTexture() signature to remove Sampler.
@@ -41,11 +43,13 @@
4143 // 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)
4244 // 2026-01-05: [Helpers] *BREAKING CHANGE*: Vulkan: Helper for creating render pass uses ImGui_ImplVulkanH_Window::AttachmentDesc to create render pass. Removed ClearEnabled. (#9152)
4345 // 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)
46+// 2025-11-13: [Docking] Handle viewport surface creation failure without crashing. (#9068)
4447 // 2025-10-15: Vulkan: Added IMGUI_IMPL_VULKAN_VOLK_FILENAME to configure path to volk.h header. (#9008)
4548 // 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.
4649 // 2025-09-26: *BREAKING CHANGE*: renamed ImGui_ImplVulkan_MainPipelineCreateInfo to ImGui_ImplVulkan_PipelineInfo. Introduced very recently so shouldn't affect many users.
4750 // 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.
4851 // 2025-09-26: Vulkan: Added a way to customize shaders by filling ImGui_ImplVulkan_InitInfo::CustomShaderVertCreateInfo/CustomShaderFragCreateInfo. (#8585)
52+// 2025-09-22: [Docking] Added ImGui_ImplVulkanH_GetWindowDataFromViewport() accessor/helper. (#8946, #8940)
4953 // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
5054 // 2025-09-04: Vulkan: Added ImGui_ImplVulkan_CreateMainPipeline(). (#8110, #8111)
5155 // 2025-07-27: Vulkan: Fixed texture update corruption introduced on 2025-06-11. (#8801, #8755, #8840)
@@ -144,6 +148,7 @@
144148 void ImGui_ImplVulkan_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkan_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
145149 void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);
146150 void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
151+void ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(VkDevice device, const VkAllocationCallbacks* allocator);
147152 void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count, VkImageUsageFlags image_usage);
148153 void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
149154
@@ -160,15 +165,18 @@
160165 IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateCommandBuffers) \
161166 IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateDescriptorSets) \
162167 IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateMemory) \
168+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkAcquireNextImageKHR) \
163169 IMGUI_VULKAN_FUNC_MAP_MACRO(vkBeginCommandBuffer) \
164170 IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindBufferMemory) \
165171 IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindImageMemory) \
172+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBeginRenderPass) \
166173 IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindDescriptorSets) \
167174 IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindIndexBuffer) \
168175 IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindPipeline) \
169176 IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindVertexBuffers) \
170177 IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdCopyBufferToImage) \
171178 IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdDrawIndexed) \
179+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdEndRenderPass) \
172180 IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPipelineBarrier) \
173181 IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPushConstants) \
174182 IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdSetScissor) \
@@ -220,8 +228,10 @@
220228 IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \
221229 IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceFormatsKHR) \
222230 IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfacePresentModesKHR) \
231+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceSupportKHR) \
223232 IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetSwapchainImagesKHR) \
224233 IMGUI_VULKAN_FUNC_MAP_MACRO(vkMapMemory) \
234+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueuePresentKHR) \
225235 IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueSubmit) \
226236 IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueWaitIdle) \
227237 IMGUI_VULKAN_FUNC_MAP_MACRO(vkResetCommandPool) \
@@ -272,6 +282,20 @@
272282 ImGui_ImplVulkan_Texture() { memset((void*)this, 0, sizeof(*this)); }
273283 };
274284
285+// For multi-viewport support:
286+// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
287+struct ImGui_ImplVulkan_ViewportData
288+{
289+ ImGui_ImplVulkanH_Window Window; // Used by secondary viewports only
290+ ImGui_ImplVulkan_WindowRenderBuffers RenderBuffers; // Used by all viewports
291+ bool WindowOwned;
292+ bool SwapChainNeedRebuild; // Flag when viewport swapchain resized in the middle of processing a frame
293+ bool SwapChainSuboptimal; // Flag when VK_SUBOPTIMAL_KHR was returned.
294+
295+ ImGui_ImplVulkan_ViewportData() { WindowOwned = SwapChainNeedRebuild = SwapChainSuboptimal = false; memset((void*)&RenderBuffers, 0, sizeof(RenderBuffers)); }
296+ ~ImGui_ImplVulkan_ViewportData() { }
297+};
298+
275299 // Vulkan data
276300 struct ImGui_ImplVulkan_Data
277301 {
@@ -284,6 +308,7 @@
284308 VkDescriptorSetLayout DescriptorSetLayoutSampler;
285309 VkPipelineLayout PipelineLayout;
286310 VkPipeline Pipeline; // pipeline for main render pass (created by app)
311+ VkPipeline PipelineForViewports; // pipeline for secondary viewports (created by backend)
287312 VkShaderModule ShaderModuleVert;
288313 VkShaderModule ShaderModuleFrag;
289314 VkDescriptorPool DescriptorPool;
@@ -312,6 +337,10 @@
312337 // SHADERS
313338 //-----------------------------------------------------------------------------
314339
340+// Forward Declarations
341+static void ImGui_ImplVulkan_InitMultiViewportSupport();
342+static void ImGui_ImplVulkan_ShutdownMultiViewportSupport();
343+
315344 // backends/vulkan/glsl_shader.vert, compiled with:
316345 // # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert
317346 /*
@@ -537,9 +566,18 @@
537566
538567 // Draw callbacks
539568 static void ImGui_ImplVulkan_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
540-static void ImGui_ImplVulkan_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); }
541-static void ImGui_ImplVulkan_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerNearestDS, 0, nullptr); }
569+static void ImGui_ImplVulkan_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->RenderState->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); }
570+static void ImGui_ImplVulkan_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->RenderState->PipelineLayout, 1, 1, &bd->SamplerNearestDS, 0, nullptr); }
542571
572+// If you want to use your own sampler, you can create your own callback, access ImGui_ImplVulkan_RenderState for command-buffer and pipeline layout, e.g.
573+/*
574+void ImGui_ImplVulkan_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd)
575+{
576+ ImGui_ImplVulkan_RenderState* render_state = (ImGui_ImplVulkan_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState;
577+ vkCmdBindDescriptorSets(render_state->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, render_state->PipelineLayout, 1, 1, (VkDescriptorSet*)cmd->UserCallbackData, 0, nullptr);
578+}
579+*/
580+
543581 // Render function
544582 void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline)
545583 {
@@ -561,8 +599,10 @@
561599 if (pipeline == VK_NULL_HANDLE)
562600 pipeline = bd->Pipeline;
563601
564- // Allocate array to store enough vertex/index buffers
565- ImGui_ImplVulkan_WindowRenderBuffers* wrb = &bd->MainWindowRenderBuffers;
602+ // Allocate array to store enough vertex/index buffers. Each unique viewport gets its own storage.
603+ ImGui_ImplVulkan_ViewportData* viewport_renderer_data = (ImGui_ImplVulkan_ViewportData*)draw_data->OwnerViewport->RendererUserData;
604+ IM_ASSERT(viewport_renderer_data != nullptr);
605+ ImGui_ImplVulkan_WindowRenderBuffers* wrb = &viewport_renderer_data->RenderBuffers;
566606 if (wrb->FrameRenderBuffers.Size == 0)
567607 {
568608 wrb->Index = 0;
@@ -1252,7 +1292,7 @@
12521292 {
12531293 ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
12541294 ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
1255- ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator);
1295+ ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(v->Device, v->Allocator);
12561296
12571297 // Destroy all textures
12581298 for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
@@ -1269,6 +1309,7 @@
12691309 if (bd->DescriptorSetLayoutSampler) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayoutSampler, v->Allocator); bd->DescriptorSetLayoutSampler = VK_NULL_HANDLE; }
12701310 if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; }
12711311 if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; }
1312+ if (bd->PipelineForViewports) { vkDestroyPipeline(v->Device, bd->PipelineForViewports, v->Allocator); bd->PipelineForViewports = VK_NULL_HANDLE; }
12721313 if (bd->DescriptorPool) { vkDestroyDescriptorPool(v->Device, bd->DescriptorPool, v->Allocator); bd->DescriptorPool = VK_NULL_HANDLE; }
12731314 }
12741315
@@ -1361,6 +1402,7 @@
13611402 io.BackendRendererName = "imgui_impl_vulkan";
13621403 io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
13631404 io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
1405+ io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
13641406
13651407 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
13661408 platform_io.DrawCallback_ResetRenderState = ImGui_ImplVulkan_DrawCallback_ResetRenderState;
@@ -1379,7 +1421,7 @@
13791421 else
13801422 IM_ASSERT(info->DescriptorPoolSize > 0);
13811423 if (info->UseDynamicRendering)
1382- IM_ASSERT(info->PipelineInfoMain.RenderPass == VK_NULL_HANDLE);
1424+ IM_ASSERT(info->PipelineInfoMain.RenderPass == VK_NULL_HANDLE && info->PipelineInfoForViewports.RenderPass == VK_NULL_HANDLE);
13831425
13841426 bd->VulkanInitInfo = *info;
13851427
@@ -1390,6 +1432,12 @@
13901432 if (!ImGui_ImplVulkan_CreateDeviceObjects())
13911433 IM_ASSERT(0 && "ImGui_ImplVulkan_CreateDeviceObjects() failed!"); // <- Can't be hit yet.
13921434
1435+ // Our render function expect RendererUserData to be storing the window render buffer we need (for the main viewport we won't use ->Window)
1436+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
1437+ main_viewport->RendererUserData = IM_NEW(ImGui_ImplVulkan_ViewportData)();
1438+
1439+ ImGui_ImplVulkan_InitMultiViewportSupport();
1440+
13931441 return true;
13941442 }
13951443
@@ -1400,11 +1448,21 @@
14001448 ImGuiIO& io = ImGui::GetIO();
14011449 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
14021450
1451+ // First destroy objects in all viewports
14031452 ImGui_ImplVulkan_DestroyDeviceObjects();
14041453
1454+ // Manually delete main viewport render data in-case we haven't initialized for viewports
1455+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
1456+ if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)main_viewport->RendererUserData)
1457+ IM_DELETE(vd);
1458+ main_viewport->RendererUserData = nullptr;
1459+
1460+ // Clean up windows
1461+ ImGui_ImplVulkan_ShutdownMultiViewportSupport();
1462+
14051463 io.BackendRendererName = nullptr;
14061464 io.BackendRendererUserData = nullptr;
1407- io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
1465+ io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
14081466 platform_io.ClearRendererHandlers();
14091467 IM_DELETE(bd);
14101468 }
@@ -1423,10 +1481,12 @@
14231481 if (bd->VulkanInitInfo.MinImageCount == min_image_count)
14241482 return;
14251483
1484+ IM_ASSERT(0); // FIXME-VIEWPORT: Unsupported. Need to recreate all swap chains!
14261485 ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
14271486 VkResult err = vkDeviceWaitIdle(v->Device);
14281487 check_vk_result(err);
1429- ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator);
1488+ ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(v->Device, v->Allocator);
1489+
14301490 bd->VulkanInitInfo.MinImageCount = min_image_count;
14311491 }
14321492
@@ -1711,8 +1771,6 @@
17111771 wd->ImageCount = 0;
17121772 if (wd->RenderPass)
17131773 vkDestroyRenderPass(device, wd->RenderPass, allocator);
1714- if (wd->Pipeline)
1715- vkDestroyPipeline(device, wd->Pipeline, allocator);
17161774
17171775 // If min image count was not specified, request different count of images dependent on selected present mode
17181776 if (min_image_count == 0)
@@ -1956,7 +2014,6 @@
19562014 ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
19572015 wd->Frames.clear();
19582016 wd->FrameSemaphores.clear();
1959- vkDestroyPipeline(device, wd->Pipeline, allocator);
19602017 vkDestroyRenderPass(device, wd->RenderPass, allocator);
19612018 vkDestroySwapchainKHR(device, wd->Swapchain, allocator);
19622019 wd->RenderPass = VK_NULL_HANDLE;
@@ -1984,6 +2041,333 @@
19842041 vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator);
19852042 vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator);
19862043 fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;
2044+}
2045+
2046+void ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(VkDevice device, const VkAllocationCallbacks* allocator)
2047+{
2048+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
2049+ for (int n = 0; n < platform_io.Viewports.Size; n++)
2050+ if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)platform_io.Viewports[n]->RendererUserData)
2051+ ImGui_ImplVulkan_DestroyWindowRenderBuffers(device, &vd->RenderBuffers, allocator);
2052+}
2053+
2054+ImGui_ImplVulkanH_Window* ImGui_ImplVulkanH_GetWindowDataFromViewport(ImGuiViewport* viewport)
2055+{
2056+ ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData;
2057+ return vd ? &vd->Window : nullptr;
2058+}
2059+
2060+//--------------------------------------------------------------------------------------------------------
2061+// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
2062+// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
2063+// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
2064+//--------------------------------------------------------------------------------------------------------
2065+
2066+static void ImGui_ImplVulkan_CreateWindow(ImGuiViewport* viewport)
2067+{
2068+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
2069+ ImGui_ImplVulkan_ViewportData* vd = IM_NEW(ImGui_ImplVulkan_ViewportData)();
2070+ ImGui_ImplVulkanH_Window* wd = &vd->Window;
2071+ ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
2072+
2073+ // Create surface
2074+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
2075+ VkResult err = (VkResult)platform_io.Platform_CreateVkSurface(viewport, (ImU64)v->Instance, (const void*)v->Allocator, (ImU64*)&wd->Surface);
2076+ check_vk_result(err);
2077+
2078+ // Check if surface creation failed
2079+ if (err != VK_SUCCESS || wd->Surface == VK_NULL_HANDLE)
2080+ {
2081+ IM_DELETE(vd);
2082+ return;
2083+ }
2084+
2085+ // Check for WSI support
2086+ VkBool32 res;
2087+ vkGetPhysicalDeviceSurfaceSupportKHR(v->PhysicalDevice, v->QueueFamily, wd->Surface, &res);
2088+ if (res != VK_TRUE)
2089+ {
2090+ vkDestroySurfaceKHR(v->Instance, wd->Surface, v->Allocator); // Error: no WSI support on physical device, clean up and return
2091+ IM_DELETE(vd);
2092+ return;
2093+ }
2094+ viewport->RendererUserData = vd;
2095+
2096+ // Select Surface Format
2097+ ImGui_ImplVulkan_PipelineInfo* pipeline_info = &v->PipelineInfoForViewports;
2098+ ImVector<VkFormat> requestSurfaceImageFormats;
2099+#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
2100+ for (uint32_t n = 0; n < pipeline_info->PipelineRenderingCreateInfo.colorAttachmentCount; n++)
2101+ requestSurfaceImageFormats.push_back(pipeline_info->PipelineRenderingCreateInfo.pColorAttachmentFormats[n]);
2102+#endif
2103+ const VkFormat defaultFormats[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM };
2104+ for (VkFormat format : defaultFormats)
2105+ requestSurfaceImageFormats.push_back(format);
2106+
2107+ const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
2108+ wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(v->PhysicalDevice, wd->Surface, requestSurfaceImageFormats.Data, requestSurfaceImageFormats.Size, requestSurfaceColorSpace);
2109+
2110+ // Select Present Mode
2111+ // FIXME-VULKAN: Even thought mailbox seems to get us maximum framerate with a single window, it halves framerate with a second window etc. (w/ Nvidia and SDK 1.82.1)
2112+ VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR };
2113+ wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(v->PhysicalDevice, wd->Surface, &present_modes[0], IM_COUNTOF(present_modes));
2114+ //printf("[vulkan] Secondary window selected PresentMode = %d\n", wd->PresentMode);
2115+
2116+ // Create SwapChain, RenderPass, Framebuffer, etc.
2117+ wd->UseDynamicRendering = v->UseDynamicRendering;
2118+ wd->AttachmentDesc.loadOp = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : VK_ATTACHMENT_LOAD_OP_CLEAR;
2119+ ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, wd, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount, pipeline_info->SwapChainImageUsage);
2120+ vd->WindowOwned = true;
2121+
2122+ // Create pipeline (shared by all secondary viewports)
2123+ if (bd->PipelineForViewports == VK_NULL_HANDLE)
2124+ {
2125+#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
2126+ if (wd->UseDynamicRendering)
2127+ {
2128+ pipeline_info->PipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
2129+ pipeline_info->PipelineRenderingCreateInfo.colorAttachmentCount = 1;
2130+ pipeline_info->PipelineRenderingCreateInfo.pColorAttachmentFormats = &wd->SurfaceFormat.format;
2131+ }
2132+ else
2133+ {
2134+ pipeline_info->RenderPass = wd->RenderPass;
2135+ }
2136+#endif
2137+ bd->PipelineForViewports = ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, VK_NULL_HANDLE, &v->PipelineInfoForViewports);
2138+ }
2139+}
2140+
2141+static void ImGui_ImplVulkan_DestroyWindow(ImGuiViewport* viewport)
2142+{
2143+ // The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it.
2144+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
2145+ if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData)
2146+ {
2147+ ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
2148+ if (vd->WindowOwned)
2149+ {
2150+ ImGui_ImplVulkanH_DestroyWindow(v->Instance, v->Device, &vd->Window, v->Allocator);
2151+ vkDestroySurfaceKHR(v->Instance, vd->Window.Surface, v->Allocator);
2152+ }
2153+ ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &vd->RenderBuffers, v->Allocator);
2154+ IM_DELETE(vd);
2155+ }
2156+ viewport->RendererUserData = nullptr;
2157+}
2158+
2159+static void ImGui_ImplVulkan_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
2160+{
2161+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
2162+ ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData;
2163+ if (vd == nullptr) // This is nullptr for the main viewport (which is left to the user/app to handle)
2164+ return;
2165+ ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
2166+ ImGui_ImplVulkanH_Window* wd = &vd->Window;
2167+ wd->AttachmentDesc.loadOp = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : VK_ATTACHMENT_LOAD_OP_CLEAR;
2168+ ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, &vd->Window, v->QueueFamily, v->Allocator, (int)size.x, (int)size.y, v->MinImageCount, v->PipelineInfoForViewports.SwapChainImageUsage);
2169+}
2170+
2171+static void ImGui_ImplVulkan_RenderWindow(ImGuiViewport* viewport, void*)
2172+{
2173+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
2174+ ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData;
2175+ if (vd == nullptr)
2176+ return;
2177+ ImGui_ImplVulkanH_Window* wd = &vd->Window;
2178+ ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
2179+ VkResult err;
2180+
2181+ if (vd->SwapChainNeedRebuild || vd->SwapChainSuboptimal)
2182+ {
2183+ ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, wd, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount, v->PipelineInfoForViewports.SwapChainImageUsage);
2184+ vd->SwapChainNeedRebuild = vd->SwapChainSuboptimal = false;
2185+ }
2186+
2187+ ImGui_ImplVulkanH_Frame* fd = nullptr;
2188+ ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex];
2189+ {
2190+ {
2191+ err = vkAcquireNextImageKHR(v->Device, wd->Swapchain, UINT64_MAX, fsd->ImageAcquiredSemaphore, VK_NULL_HANDLE, &wd->FrameIndex);
2192+ if (err == VK_ERROR_OUT_OF_DATE_KHR)
2193+ {
2194+ vd->SwapChainNeedRebuild = true; // Since we are not going to swap this frame anyway, it's ok that recreation happens on next frame.
2195+ return;
2196+ }
2197+ if (err == VK_SUBOPTIMAL_KHR)
2198+ vd->SwapChainSuboptimal = true;
2199+ else
2200+ check_vk_result(err);
2201+ fd = &wd->Frames[wd->FrameIndex];
2202+ }
2203+ for (;;)
2204+ {
2205+ err = vkWaitForFences(v->Device, 1, &fd->Fence, VK_TRUE, 100);
2206+ if (err == VK_SUCCESS) break;
2207+ if (err == VK_TIMEOUT) continue;
2208+ check_vk_result(err);
2209+ }
2210+ {
2211+ err = vkResetCommandPool(v->Device, fd->CommandPool, 0);
2212+ check_vk_result(err);
2213+ VkCommandBufferBeginInfo info = {};
2214+ info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
2215+ info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
2216+ err = vkBeginCommandBuffer(fd->CommandBuffer, &info);
2217+ check_vk_result(err);
2218+ }
2219+ {
2220+ ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
2221+ memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float));
2222+ }
2223+#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
2224+ if (v->UseDynamicRendering)
2225+ {
2226+ // Transition swapchain image to a layout suitable for drawing.
2227+ VkImageMemoryBarrier barrier = {};
2228+ barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2229+ barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2230+ barrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2231+ barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2232+ barrier.image = fd->Backbuffer;
2233+ barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2234+ barrier.subresourceRange.levelCount = 1;
2235+ barrier.subresourceRange.layerCount = 1;
2236+ vkCmdPipelineBarrier(fd->CommandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_NONE, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
2237+
2238+ VkRenderingAttachmentInfo attachmentInfo = {};
2239+ attachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
2240+ attachmentInfo.imageView = fd->BackbufferView;
2241+ attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2242+ attachmentInfo.resolveMode = VK_RESOLVE_MODE_NONE;
2243+ attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
2244+ attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
2245+ attachmentInfo.clearValue = wd->ClearValue;
2246+
2247+ VkRenderingInfo renderingInfo = {};
2248+ renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR;
2249+ renderingInfo.renderArea.extent.width = wd->Width;
2250+ renderingInfo.renderArea.extent.height = wd->Height;
2251+ renderingInfo.layerCount = 1;
2252+ renderingInfo.viewMask = 0;
2253+ renderingInfo.colorAttachmentCount = 1;
2254+ renderingInfo.pColorAttachments = &attachmentInfo;
2255+
2256+ ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR(fd->CommandBuffer, &renderingInfo);
2257+ }
2258+ else
2259+#endif
2260+ {
2261+ VkRenderPassBeginInfo info = {};
2262+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
2263+ info.renderPass = wd->RenderPass;
2264+ info.framebuffer = fd->Framebuffer;
2265+ info.renderArea.extent.width = wd->Width;
2266+ info.renderArea.extent.height = wd->Height;
2267+ info.clearValueCount = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? 0 : 1;
2268+ info.pClearValues = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? nullptr : &wd->ClearValue;
2269+ vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
2270+ }
2271+ }
2272+
2273+ ImGui_ImplVulkan_RenderDrawData(viewport->DrawData, fd->CommandBuffer, bd->PipelineForViewports);
2274+
2275+ {
2276+#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
2277+ if (v->UseDynamicRendering)
2278+ {
2279+ ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR(fd->CommandBuffer);
2280+
2281+ // Transition image to a layout suitable for presentation
2282+ VkImageMemoryBarrier barrier = {};
2283+ barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2284+ barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2285+ barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2286+ barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2287+ barrier.image = fd->Backbuffer;
2288+ barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2289+ barrier.subresourceRange.levelCount = 1;
2290+ barrier.subresourceRange.layerCount = 1;
2291+ vkCmdPipelineBarrier(fd->CommandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
2292+ }
2293+ else
2294+#endif
2295+ {
2296+ vkCmdEndRenderPass(fd->CommandBuffer);
2297+ }
2298+ {
2299+ VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2300+ VkSubmitInfo info = {};
2301+ info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2302+ info.waitSemaphoreCount = 1;
2303+ info.pWaitSemaphores = &fsd->ImageAcquiredSemaphore;
2304+ info.pWaitDstStageMask = &wait_stage;
2305+ info.commandBufferCount = 1;
2306+ info.pCommandBuffers = &fd->CommandBuffer;
2307+ info.signalSemaphoreCount = 1;
2308+ info.pSignalSemaphores = &fsd->RenderCompleteSemaphore;
2309+
2310+ err = vkEndCommandBuffer(fd->CommandBuffer);
2311+ check_vk_result(err);
2312+ err = vkResetFences(v->Device, 1, &fd->Fence);
2313+ check_vk_result(err);
2314+ err = vkQueueSubmit(v->Queue, 1, &info, fd->Fence);
2315+ check_vk_result(err);
2316+ }
2317+ }
2318+}
2319+
2320+static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport, void*)
2321+{
2322+ ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
2323+ ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData;
2324+ if (vd == nullptr)
2325+ return;
2326+ ImGui_ImplVulkanH_Window* wd = &vd->Window;
2327+ ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
2328+
2329+ if (vd->SwapChainNeedRebuild) // Frame data became invalid in the middle of rendering
2330+ return;
2331+
2332+ VkResult err;
2333+ uint32_t present_index = wd->FrameIndex;
2334+
2335+ ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex];
2336+ VkPresentInfoKHR info = {};
2337+ info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2338+ info.waitSemaphoreCount = 1;
2339+ info.pWaitSemaphores = &fsd->RenderCompleteSemaphore;
2340+ info.swapchainCount = 1;
2341+ info.pSwapchains = &wd->Swapchain;
2342+ info.pImageIndices = &present_index;
2343+ err = vkQueuePresentKHR(v->Queue, &info);
2344+ if (err == VK_ERROR_OUT_OF_DATE_KHR)
2345+ {
2346+ vd->SwapChainNeedRebuild = true;
2347+ return;
2348+ }
2349+ if (err == VK_SUBOPTIMAL_KHR)
2350+ vd->SwapChainSuboptimal = true;
2351+ else
2352+ check_vk_result(err);
2353+ wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores
2354+}
2355+
2356+void ImGui_ImplVulkan_InitMultiViewportSupport()
2357+{
2358+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
2359+ if (ImGui::GetIO().BackendFlags & ImGuiBackendFlags_PlatformHasViewports)
2360+ IM_ASSERT(platform_io.Platform_CreateVkSurface != nullptr && "Platform needs to setup the CreateVkSurface handler.");
2361+ platform_io.Renderer_CreateWindow = ImGui_ImplVulkan_CreateWindow;
2362+ platform_io.Renderer_DestroyWindow = ImGui_ImplVulkan_DestroyWindow;
2363+ platform_io.Renderer_SetWindowSize = ImGui_ImplVulkan_SetWindowSize;
2364+ platform_io.Renderer_RenderWindow = ImGui_ImplVulkan_RenderWindow;
2365+ platform_io.Renderer_SwapBuffers = ImGui_ImplVulkan_SwapBuffers;
2366+}
2367+
2368+void ImGui_ImplVulkan_ShutdownMultiViewportSupport()
2369+{
2370+ ImGui::DestroyPlatformWindows();
19872371 }
19882372
19892373 //-----------------------------------------------------------------------------
@@ -6,6 +6,7 @@
66 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
77 // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
88 // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
9+// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
910
1011 // The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
1112 // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
@@ -84,13 +85,19 @@
8485 // Specify settings to create pipeline and swapchain
8586 struct ImGui_ImplVulkan_PipelineInfo
8687 {
88+ // For Main viewport only
8789 VkRenderPass RenderPass; // Ignored if using dynamic rendering
90+
91+ // For Main and Secondary viewports
8892 uint32_t Subpass; //
8993 VkSampleCountFlagBits MSAASamples = {}; // 0 defaults to VK_SAMPLE_COUNT_1_BIT
9094 ImVector<VkDynamicState> ExtraDynamicStates; // Optional, allows to insert more dynamic states into our VkPipeline
9195 #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
9296 VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; // Optional, valid if .sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR
9397 #endif
98+
99+ // For Secondary viewports only (created/managed by backend)
100+ VkImageUsageFlags SwapChainImageUsage; // Extra flags for vkCreateSwapchainKHR() calls for secondary viewports. We automatically add VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT. You can add e.g. VK_IMAGE_USAGE_TRANSFER_SRC_BIT if you need to capture from viewports.
94101 };
95102
96103 // Initialization data, for ImGui_ImplVulkan_Init()
@@ -117,13 +124,14 @@
117124
118125 // Pipeline
119126 ImGui_ImplVulkan_PipelineInfo PipelineInfoMain; // Infos for Main Viewport (created by app/user)
127+ ImGui_ImplVulkan_PipelineInfo PipelineInfoForViewports; // Infos for Secondary Viewports (created by backend)
120128 //VkRenderPass RenderPass; // --> Since 2025/09/26: set 'PipelineInfoMain.RenderPass' instead
121129 //uint32_t Subpass; // --> Since 2025/09/26: set 'PipelineInfoMain.Subpass' instead
122130 //VkSampleCountFlagBits MSAASamples; // --> Since 2025/09/26: set 'PipelineInfoMain.MSAASamples' instead
123131 //VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; // Since 2025/09/26: set 'PipelineInfoMain.PipelineRenderingCreateInfo' instead
124132
125133 // (Optional) Dynamic Rendering
126- // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3 + setup PipelineInfoMain.PipelineRenderingCreateInfo.
134+ // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3 + setup PipelineInfoMain.PipelineRenderingCreateInfo and PipelineInfoViewports.PipelineRenderingCreateInfo.
127135 bool UseDynamicRendering;
128136
129137 // (Optional) Allocation, Debugging
@@ -167,6 +175,7 @@
167175
168176 // [BETA] Selected render state data shared with callbacks.
169177 // This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplVulkan_RenderDrawData() call.
178+// ImGui_ImplVulkan_RenderState* render_state = (ImGui_ImplVulkan_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState;
170179 // (Please open an issue if you feel you need access to more data)
171180 struct ImGui_ImplVulkan_RenderState
172181 {
@@ -207,6 +216,7 @@
207216 IMGUI_IMPL_API VkPhysicalDevice ImGui_ImplVulkanH_SelectPhysicalDevice(VkInstance instance);
208217 IMGUI_IMPL_API uint32_t ImGui_ImplVulkanH_SelectQueueFamilyIndex(VkPhysicalDevice physical_device);
209218 IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
219+IMGUI_IMPL_API ImGui_ImplVulkanH_Window* ImGui_ImplVulkanH_GetWindowDataFromViewport(ImGuiViewport* viewport); // Access to Vulkan objects associated with a viewport (e.g to export a screenshot)
210220
211221 // Helper structure to hold the data needed by one rendering frame
212222 // (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
@@ -244,7 +254,6 @@
244254 int Height;
245255 VkSwapchainKHR Swapchain;
246256 VkRenderPass RenderPass;
247- VkPipeline Pipeline; // The window pipeline may uses a different VkRenderPass than the one passed in ImGui_ImplVulkan_InitInfo
248257 uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
249258 uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
250259 uint32_t SemaphoreCount; // Number of simultaneous in-flight frames + 1, to be able to use it in vkAcquireNextImageKHR
@@ -7,6 +7,8 @@
77 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
88 // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
99 // [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures).
10+// Missing features or Issues:
11+// [ ] Renderer: Multi-viewport support (multiple windows), useful for desktop.
1012
1113 // Read imgui_impl_wgpu.h about how to use the IMGUI_IMPL_WEBGPU_BACKEND_WGPU or IMGUI_IMPL_WEBGPU_BACKEND_DAWN flags.
1214
@@ -19,6 +19,8 @@
1919 // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
2020 // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
2121 // [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures).
22+// Missing features or Issues:
23+// [ ] Renderer: Multi-viewport support (multiple windows), useful for desktop.
2224
2325 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
2426 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -7,6 +7,7 @@
77 // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values are obsolete since 1.87 and not supported since 1.91.5]
88 // [X] Platform: Gamepad support.
99 // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
10+// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
1011
1112 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1213 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -21,14 +22,24 @@
2122
2223 // CHANGELOG
2324 // (minor and older changes stripped away, please see git history for details)
25+// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
26+// 2026-05-19: DPI: ImGui_ImplWin32_EnableDpiAwareness() helper uses SetProcessDpiAwarenessContext() instead of SetThreadDpiAwarenessContext(), fixes DPI scaling issues with e.g. OpenGL. (#9403)
27+// 2026-03-31: [Viewports] Fixed setting/getting size when viewports have OS decorations (e.g. io.ConfigViewportsNoDecoration = false) and process is running in Per-Monitor V2 DPI mode. (#8897)
2428 // 2026-01-28: Inputs: Minor optimization not submitting gamepad input if packet number has not changed (reworked from 2025-09-23 attempt). (#9202, #8556)
29+// 2026-01-26: [Viewports] Fixed an issue from 1.90.5 where newly appearing windows that are not parented to the main viewport don't have task bar icon appear before the windows was explicited refocused. (#7354, #8669)
2530 // 2025-12-03: Inputs: handle WM_IME_CHAR/WM_IME_COMPOSITION messages to support Unicode inputs on MBCS (non-Unicode) Windows. (#9099, #3653, #5961)
2631 // 2025-10-19: Inputs: Revert previous change to allow for io.ClearInputKeys() on focus-out not losing gamepad state.
2732 // 2025-09-23: Inputs: Minor optimization not submitting gamepad input if packet number has not changed.
2833 // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown.
34+// 2025-06-02: [Viewports] WM_DPICHANGED also apply io.ConfigDpiScaleViewports for main viewport instead of letting it be done by application code.
2935 // 2025-04-30: Inputs: Fixed an issue where externally losing mouse capture (due to e.g. focus loss) would fail to claim it again the next subsequent click. (#8594)
36+// 2025-03-26: [Viewports] Viewports: fixed an issue when closing a window from the OS close button (with io.ConfigViewportsNoDecoration = false) while user code was discarding the 'bool* p_open = false' output from Begin(). Because we allowed the Win32 window to close early, Windows destroyed it and our imgui window became not visible even though user code was still submitting it.
3037 // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468)
38+// 2025-02-21: [Viewports] WM_SETTINGCHANGE's SPI_SETWORKAREA message also triggers a refresh of monitor list. (#8415)
3139 // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support.
40+// 2024-11-21: [Viewports] Fixed a crash when multiple processes are running with multi-viewports, caused by misusage of GetProp(). (#8162, #8069)
41+// 2024-10-28: [Viewports] Rely on property stored inside HWND to retrieve context/viewport, should facilitate attempt to use this for parallel contexts. (#8069)
42+// 2024-09-16: [Viewports] Inputs: fixed an issue where a viewport destroyed while clicking would hog mouse tracking and temporary lead to incorrect update of HoveredWindow. (#7971)
3243 // 2024-07-08: Inputs: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. (#7768)
3344 // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys.
3445 // 2023-09-25: Inputs: Synthesize key-down event on key-up for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit it (same behavior as GLFW/SDL).
@@ -99,6 +110,7 @@
99110 typedef DWORD(WINAPI* PFN_XInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*);
100111 typedef DWORD(WINAPI* PFN_XInputGetState)(DWORD, XINPUT_STATE*);
101112 #endif
113+typedef BOOL(WINAPI* PFN_AdjustWindowRectExForDpi)(LPRECT, DWORD, BOOL, DWORD, UINT);
102114
103115 // Clang/GCC warnings with -Weverything
104116 #if defined(__clang__)
@@ -111,6 +123,12 @@
111123 #pragma GCC diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader)
112124 #endif
113125
126+// Forward Declarations
127+static void ImGui_ImplWin32_InitMultiViewportSupport(bool platform_has_own_dc);
128+static void ImGui_ImplWin32_ShutdownMultiViewportSupport();
129+static void ImGui_ImplWin32_UpdateMonitors();
130+static bool ImGui_ImplWin32_IsDpiAwarenessPerMonitorAwareV2();
131+
114132 struct ImGui_ImplWin32_Data
115133 {
116134 HWND hWnd;
@@ -121,6 +139,9 @@
121139 INT64 TicksPerSecond;
122140 ImGuiMouseCursor LastMouseCursor;
123141 UINT32 KeyboardCodePage;
142+ bool WantUpdateMonitors;
143+ bool IsPerMonitorDpiAwareV2;
144+ PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi;
124145
125146 #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
126147 bool HasGamepad;
@@ -176,6 +197,9 @@
176197 io.BackendPlatformName = "imgui_impl_win32";
177198 io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
178199 io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
200+ io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
201+ io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional)
202+ io.BackendFlags |= ImGuiBackendFlags_HasParentViewport; // We can honor viewport->ParentViewportId by applying the corresponding parent/child relationship at platform levle (optional)
179203
180204 bd->hWnd = (HWND)hwnd;
181205 bd->TicksPerSecond = perf_frequency;
@@ -183,11 +207,22 @@
183207 bd->LastMouseCursor = ImGuiMouseCursor_COUNT;
184208 ImGui_ImplWin32_UpdateKeyboardCodePage(io);
185209
210+ // Update monitor a first time during init
211+ ImGui_ImplWin32_UpdateMonitors();
212+
186213 // Our mouse update function expect PlatformHandle to be filled for the main viewport
187214 ImGuiViewport* main_viewport = ImGui::GetMainViewport();
188215 main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (void*)bd->hWnd;
189- IM_UNUSED(platform_has_own_dc); // Used in 'docking' branch
190216
217+ // Be aware that GetPropA()/SetPropA() may be accessed from other processes.
218+ // So as we store a pointer in IMGUI_CONTEXT we need to make sure we only call GetPropA() on windows owned by our process.
219+ ::SetPropA(bd->hWnd, "IMGUI_CONTEXT", ImGui::GetCurrentContext());
220+ ImGui_ImplWin32_InitMultiViewportSupport(platform_has_own_dc);
221+
222+ if (HINSTANCE user32_dll = ::GetModuleHandleA("user32.dll"))
223+ bd->AdjustWindowRectExForDpi = (PFN_AdjustWindowRectExForDpi)::GetProcAddress(user32_dll, "AdjustWindowRectExForDpi");
224+ bd->IsPerMonitorDpiAwareV2 = ImGui_ImplWin32_IsDpiAwarenessPerMonitorAwareV2();
225+
191226 // Dynamically load XInput library
192227 #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
193228 bd->WantUpdateHasGamepad = true;
@@ -230,6 +265,9 @@
230265 ImGuiIO& io = ImGui::GetIO();
231266 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
232267
268+ ::SetPropA(bd->hWnd, "IMGUI_CONTEXT", nullptr);
269+ ImGui_ImplWin32_ShutdownMultiViewportSupport();
270+
233271 // Unload XInput library
234272 #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
235273 if (bd->XInputDLL)
@@ -238,7 +276,7 @@
238276
239277 io.BackendPlatformName = nullptr;
240278 io.BackendPlatformUserData = nullptr;
241- io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
279+ io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport | ImGuiBackendFlags_HasParentViewport);
242280 platform_io.ClearPlatformHandlers();
243281 IM_DELETE(bd);
244282 }
@@ -311,32 +349,69 @@
311349 io.AddKeyEvent(ImGuiMod_Super, IsVkDown(VK_LWIN) || IsVkDown(VK_RWIN));
312350 }
313351
314-static void ImGui_ImplWin32_UpdateMouseData(ImGuiIO& io)
352+static ImGuiViewport* ImGui_ImplWin32_FindViewportByPlatformHandle(ImGuiPlatformIO& platform_io, HWND hwnd)
315353 {
354+ // We cannot use ImGui::FindViewportByPlatformHandle() because it doesn't take a context.
355+ // When called from ImGui_ImplWin32_WndProcHandler_PlatformWindow() we don't assume that context is bound.
356+ //return ImGui::FindViewportByPlatformHandle((void*)hwnd);
357+ for (ImGuiViewport* viewport : platform_io.Viewports)
358+ if (viewport->PlatformHandle == hwnd)
359+ return viewport;
360+ return nullptr;
361+}
362+
363+// This code supports multi-viewports (multiple OS Windows mapped into different Dear ImGui viewports)
364+// Because of that, it is a little more complicated than your typical single-viewport binding code!
365+static void ImGui_ImplWin32_UpdateMouseData(ImGuiIO& io, ImGuiPlatformIO& platform_io)
366+{
316367 ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io);
317368 IM_ASSERT(bd->hWnd != 0);
318369
370+ POINT mouse_screen_pos;
371+ bool has_mouse_screen_pos = ::GetCursorPos(&mouse_screen_pos) != 0;
372+
319373 HWND focused_window = ::GetForegroundWindow();
320- const bool is_app_focused = (focused_window == bd->hWnd);
374+ const bool is_app_focused = (focused_window && (focused_window == bd->hWnd || ::IsChild(focused_window, bd->hWnd) || ImGui_ImplWin32_FindViewportByPlatformHandle(platform_io, focused_window)));
321375 if (is_app_focused)
322376 {
323377 // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
378+ // When multi-viewports are enabled, all Dear ImGui positions are same as OS positions.
324379 if (io.WantSetMousePos)
325380 {
326381 POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
327- if (::ClientToScreen(bd->hWnd, &pos))
328- ::SetCursorPos(pos.x, pos.y);
382+ if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) == 0)
383+ ::ClientToScreen(focused_window, &pos);
384+ ::SetCursorPos(pos.x, pos.y);
329385 }
330386
331387 // (Optional) Fallback to provide mouse position when focused (WM_MOUSEMOVE already provides this when hovered or captured)
332388 // This also fills a short gap when clicking non-client area: WM_NCMOUSELEAVE -> modal OS move -> gap -> WM_NCMOUSEMOVE
333- if (!io.WantSetMousePos && bd->MouseTrackedArea == 0)
389+ if (!io.WantSetMousePos && bd->MouseTrackedArea == 0 && has_mouse_screen_pos)
334390 {
335- POINT pos;
336- if (::GetCursorPos(&pos) && ::ScreenToClient(bd->hWnd, &pos))
337- io.AddMousePosEvent((float)pos.x, (float)pos.y);
391+ // 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)
392+ // (This is the position you can get with ::GetCursorPos() + ::ScreenToClient() or WM_MOUSEMOVE.)
393+ // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
394+ // (This is the position you can get with ::GetCursorPos() or WM_MOUSEMOVE + ::ClientToScreen(). In theory adding viewport->Pos to a client position would also be the same.)
395+ POINT mouse_pos = mouse_screen_pos;
396+ if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable))
397+ ::ScreenToClient(bd->hWnd, &mouse_pos);
398+ io.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y);
338399 }
339400 }
401+
402+ // (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
403+ // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic.
404+ // - [X] Win32 backend correctly ignore viewports with the _NoInputs flag (here using ::WindowFromPoint with WM_NCHITTEST + HTTRANSPARENT in WndProc does that)
405+ // Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window
406+ // for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported
407+ // by the backend, and use its flawed heuristic to guess the viewport behind.
408+ // - [X] Win32 backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target).
409+ ImGuiID mouse_viewport_id = 0;
410+ if (has_mouse_screen_pos)
411+ if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos))
412+ if (ImGuiViewport* viewport = ImGui_ImplWin32_FindViewportByPlatformHandle(platform_io, hovered_hwnd))
413+ mouse_viewport_id = viewport->ID;
414+ io.AddMouseViewportEvent(mouse_viewport_id);
340415 }
341416
342417 // Gamepad navigation mapping
@@ -398,16 +473,50 @@
398473 #endif
399474 }
400475
476+static BOOL CALLBACK ImGui_ImplWin32_UpdateMonitors_EnumFunc(HMONITOR monitor, HDC, LPRECT, LPARAM)
477+{
478+ MONITORINFO info = {};
479+ info.cbSize = sizeof(MONITORINFO);
480+ if (!::GetMonitorInfo(monitor, &info))
481+ return TRUE;
482+ ImGuiPlatformMonitor imgui_monitor;
483+ imgui_monitor.MainPos = ImVec2((float)info.rcMonitor.left, (float)info.rcMonitor.top);
484+ imgui_monitor.MainSize = ImVec2((float)(info.rcMonitor.right - info.rcMonitor.left), (float)(info.rcMonitor.bottom - info.rcMonitor.top));
485+ imgui_monitor.WorkPos = ImVec2((float)info.rcWork.left, (float)info.rcWork.top);
486+ imgui_monitor.WorkSize = ImVec2((float)(info.rcWork.right - info.rcWork.left), (float)(info.rcWork.bottom - info.rcWork.top));
487+ imgui_monitor.DpiScale = ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
488+ imgui_monitor.PlatformHandle = (void*)monitor;
489+ if (imgui_monitor.DpiScale <= 0.0f)
490+ return TRUE; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902.
491+ ImGuiPlatformIO& io = ImGui::GetPlatformIO();
492+ if (info.dwFlags & MONITORINFOF_PRIMARY)
493+ io.Monitors.push_front(imgui_monitor);
494+ else
495+ io.Monitors.push_back(imgui_monitor);
496+ return TRUE;
497+}
498+
499+static void ImGui_ImplWin32_UpdateMonitors()
500+{
501+ ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
502+ ImGui::GetPlatformIO().Monitors.resize(0);
503+ ::EnumDisplayMonitors(nullptr, nullptr, ImGui_ImplWin32_UpdateMonitors_EnumFunc, 0);
504+ bd->WantUpdateMonitors = false;
505+}
506+
401507 void ImGui_ImplWin32_NewFrame()
402508 {
403509 ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
404510 IM_ASSERT(bd != nullptr && "Context or backend not initialized? Did you call ImGui_ImplWin32_Init()?");
405511 ImGuiIO& io = ImGui::GetIO();
512+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
406513
407514 // Setup display size (every frame to accommodate for window resizing)
408515 RECT rect = { 0, 0, 0, 0 };
409516 ::GetClientRect(bd->hWnd, &rect);
410517 io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
518+ if (bd->WantUpdateMonitors)
519+ ImGui_ImplWin32_UpdateMonitors();
411520
412521 // Setup time step
413522 INT64 current_time = 0;
@@ -416,7 +525,7 @@
416525 bd->Time = current_time;
417526
418527 // Update OS mouse position
419- ImGui_ImplWin32_UpdateMouseData(io);
528+ ImGui_ImplWin32_UpdateMouseData(io, platform_io);
420529
421530 // Process workarounds for known Windows key handling issues
422531 ImGui_ImplWin32_ProcessKeyEventsWorkarounds(io);
@@ -621,6 +730,10 @@
621730 extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Use ImGui::GetCurrentContext()
622731 extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, ImGuiIO& io); // Doesn't use ImGui::GetCurrentContext()
623732
733+#ifndef WM_DPICHANGED
734+#define WM_DPICHANGED 0x02E0 // From Windows SDK 8.1+ headers
735+#endif
736+
624737 IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
625738 {
626739 // Most backends don't have silent checks like this one, but we need it because WndProc are called early in CreateWindow().
@@ -655,8 +768,11 @@
655768 bd->MouseTrackedArea = area;
656769 }
657770 POINT mouse_pos = { (LONG)GET_X_LPARAM(lParam), (LONG)GET_Y_LPARAM(lParam) };
658- if (msg == WM_NCMOUSEMOVE) // WM_NCMOUSEMOVE are absolute coordinates.
659- ::ScreenToClient(hwnd, &mouse_pos);
771+ bool want_absolute_pos = (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) != 0;
772+ if (msg == WM_MOUSEMOVE && want_absolute_pos) // WM_MOUSEMOVE are client-relative coordinates.
773+ ::ClientToScreen(hwnd, &mouse_pos);
774+ if (msg == WM_NCMOUSEMOVE && !want_absolute_pos) // WM_NCMOUSEMOVE are absolute coordinates.
775+ ::ScreenToClient(hwnd, &mouse_pos);
660776 io.AddMouseSourceEvent(mouse_source);
661777 io.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y);
662778 return 0;
@@ -826,7 +942,22 @@
826942 bd->WantUpdateHasGamepad = true;
827943 #endif
828944 return 0;
945+ case WM_DISPLAYCHANGE:
946+ bd->WantUpdateMonitors = true;
947+ return 0;
948+ case WM_SETTINGCHANGE:
949+ if (wParam == SPI_SETWORKAREA)
950+ bd->WantUpdateMonitors = true;
951+ return 0;
952+ case WM_DPICHANGED:
953+ {
954+ // FIXME-DPI: see SDL3's WM_GETDPISCALEDSIZE handler.
955+ const RECT* suggested_rect = (RECT*)lParam;
956+ if (io.ConfigDpiScaleViewports)
957+ ::SetWindowPos(hwnd, nullptr, suggested_rect->left, suggested_rect->top, suggested_rect->right - suggested_rect->left, suggested_rect->bottom - suggested_rect->top, SWP_NOZORDER | SWP_NOACTIVATE);
958+ return 0;
829959 }
960+ }
830961 return 0;
831962 }
832963
@@ -883,18 +1014,30 @@
8831014 #ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
8841015 #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4
8851016 #endif
886-typedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib + dll, Windows 8.1+
887-typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib + dll, Windows 8.1+
888-typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update)
1017+typedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib + dll, Windows 8.1+
1018+typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib + dll, Windows 8.1+
1019+typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update)
1020+typedef BOOL (WINAPI* PFN_SetProcessDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1703+ (Creators Update)
1021+typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_GetThreadDpiAwarenessContext)(); // "
1022+typedef BOOL(WINAPI* PFN_AreDpiAwarenessContextsEqual)(DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT); // "
8891023
8901024 // Helper function to enable DPI awareness without setting up a manifest
8911025 void ImGui_ImplWin32_EnableDpiAwareness()
8921026 {
1027+ // Make sure monitors will be updated with latest correct scaling
1028+ if (ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData())
1029+ bd->WantUpdateMonitors = true;
1030+
8931031 if (_IsWindows10OrGreater())
8941032 {
8951033 static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process
896- if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext"))
1034+ if (PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContextFn = (PFN_SetProcessDpiAwarenessContext)::GetProcAddress(user32_dll, "SetProcessDpiAwarenessContext")) // Windows 10 v1703+
8971035 {
1036+ SetProcessDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
1037+ return;
1038+ }
1039+ if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext")) // Windows 10 v1607+
1040+ {
8981041 SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
8991042 return;
9001043 }
@@ -913,6 +1056,18 @@
9131056 #endif
9141057 }
9151058
1059+static bool ImGui_ImplWin32_IsDpiAwarenessPerMonitorAwareV2()
1060+{
1061+ if (!_IsWindows10OrGreater())
1062+ return false;
1063+ static HINSTANCE user32_dll = ::GetModuleHandleA("user32.dll");
1064+ PFN_GetThreadDpiAwarenessContext GetThreadDpiAwarenessContextFn = (PFN_GetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "GetThreadDpiAwarenessContext");
1065+ PFN_AreDpiAwarenessContextsEqual AreDpiAwarenessContextsEqualFn = (PFN_AreDpiAwarenessContextsEqual)::GetProcAddress(user32_dll, "AreDpiAwarenessContextsEqual");
1066+ if (GetThreadDpiAwarenessContextFn && AreDpiAwarenessContextsEqualFn)
1067+ return AreDpiAwarenessContextsEqualFn(GetThreadDpiAwarenessContextFn(), DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) != 0;
1068+ return false;
1069+}
1070+
9161071 #if defined(_MSC_VER) && !defined(NOGDI)
9171072 #pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps(). MinGW will require linking with '-lgdi32'
9181073 #endif
@@ -987,6 +1142,398 @@
9871142 bb.dwFlags = DWM_BB_ENABLE;
9881143 ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
9891144 }
1145+}
1146+
1147+//---------------------------------------------------------------------------------------------------------
1148+// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
1149+// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
1150+// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
1151+//--------------------------------------------------------------------------------------------------------
1152+
1153+// Helper structure we store in the void* PlatformUserData field of each ImGuiViewport to easily retrieve our backend data.
1154+struct ImGui_ImplWin32_ViewportData
1155+{
1156+ HWND Hwnd; // Stored in ImGuiViewport::PlatformHandle + PlatformHandleRaw
1157+ HWND HwndParent;
1158+ bool HwndOwned;
1159+ DWORD DwStyle;
1160+ DWORD DwExStyle;
1161+
1162+ ImGui_ImplWin32_ViewportData() { Hwnd = HwndParent = nullptr; HwndOwned = false; DwStyle = DwExStyle = 0; }
1163+ ~ImGui_ImplWin32_ViewportData() { IM_ASSERT(Hwnd == nullptr); }
1164+};
1165+
1166+static void ImGui_ImplWin32_GetWin32StyleFromViewportFlags(ImGuiViewportFlags flags, DWORD* out_style, DWORD* out_ex_style)
1167+{
1168+ if (flags & ImGuiViewportFlags_NoDecoration)
1169+ *out_style = WS_POPUP;
1170+ else
1171+ *out_style = WS_OVERLAPPEDWINDOW;
1172+
1173+ if (flags & ImGuiViewportFlags_NoTaskBarIcon)
1174+ *out_ex_style = WS_EX_TOOLWINDOW;
1175+ else
1176+ *out_ex_style = WS_EX_APPWINDOW;
1177+
1178+ if (flags & ImGuiViewportFlags_TopMost)
1179+ *out_ex_style |= WS_EX_TOPMOST;
1180+}
1181+
1182+static HWND ImGui_ImplWin32_GetHwndFromViewport(ImGuiViewport* viewport)
1183+{
1184+ if (viewport != nullptr)
1185+ return (HWND)viewport->PlatformHandle;
1186+ return nullptr;
1187+}
1188+
1189+static void ImGui_ImplWin32_AdjustWindowRect(ImGuiViewport* viewport, RECT* rect, DWORD style, DWORD ex_style)
1190+{
1191+ ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
1192+ if (bd->AdjustWindowRectExForDpi && bd->IsPerMonitorDpiAwareV2)
1193+ {
1194+ UINT dpi = (UINT)(viewport->DpiScale * 96.0f + 0.5f);
1195+ if (dpi != 0 && bd->AdjustWindowRectExForDpi(rect, style, FALSE, ex_style, dpi))
1196+ return;
1197+ }
1198+ ::AdjustWindowRectEx(rect, style, FALSE, ex_style);
1199+}
1200+
1201+static void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport)
1202+{
1203+ ImGui_ImplWin32_ViewportData* vd = IM_NEW(ImGui_ImplWin32_ViewportData)();
1204+ viewport->PlatformUserData = vd;
1205+
1206+ // Select style and parent window
1207+ ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &vd->DwStyle, &vd->DwExStyle);
1208+ vd->HwndParent = ImGui_ImplWin32_GetHwndFromViewport(viewport->ParentViewport);
1209+
1210+ // Create window
1211+ RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) };
1212+ ImGui_ImplWin32_AdjustWindowRect(viewport, &rect, vd->DwStyle, vd->DwExStyle);
1213+ vd->Hwnd = ::CreateWindowExW(
1214+ vd->DwExStyle, L"ImGui Platform", L"Untitled", vd->DwStyle, // Style, class name, window name
1215+ rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area
1216+ vd->HwndParent, nullptr, ::GetModuleHandle(nullptr), nullptr); // Owner window, Menu, Instance, Param
1217+ vd->HwndOwned = true;
1218+ viewport->PlatformRequestResize = false;
1219+ viewport->PlatformHandle = viewport->PlatformHandleRaw = vd->Hwnd;
1220+
1221+ // Secondary viewports store their imgui context
1222+ ::SetPropA(vd->Hwnd, "IMGUI_CONTEXT", ImGui::GetCurrentContext());
1223+}
1224+
1225+static void ImGui_ImplWin32_DestroyWindow(ImGuiViewport* viewport)
1226+{
1227+ ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
1228+ if (ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData)
1229+ {
1230+ if (::GetCapture() == vd->Hwnd)
1231+ {
1232+ // Transfer capture so if we started dragging from a window that later disappears, we'll still receive the MOUSEUP event.
1233+ ::ReleaseCapture();
1234+ ::SetCapture(bd->hWnd);
1235+ }
1236+ if (vd->Hwnd && vd->HwndOwned)
1237+ ::DestroyWindow(vd->Hwnd);
1238+ vd->Hwnd = nullptr;
1239+ IM_DELETE(vd);
1240+ }
1241+ viewport->PlatformUserData = viewport->PlatformHandle = nullptr;
1242+}
1243+
1244+static void ImGui_ImplWin32_ShowWindow(ImGuiViewport* viewport)
1245+{
1246+ ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
1247+ IM_ASSERT(vd->Hwnd != 0);
1248+
1249+ // ShowParent() even with SW_SHOWNA also brings parent to front, which is not always desirable,
1250+ // so we temporarily disable parenting. (#7354, #8669)
1251+ bool avoid_bringing_parent_to_front = vd->HwndParent != NULL && (viewport->Flags & (ImGuiViewportFlags_NoFocusOnAppearing | ImGuiViewportFlags_NoTaskBarIcon)) != 0;
1252+ if (avoid_bringing_parent_to_front)
1253+ ::SetWindowLongPtr(vd->Hwnd, GWLP_HWNDPARENT, (LONG_PTR)nullptr);
1254+
1255+ if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
1256+ ::ShowWindow(vd->Hwnd, SW_SHOWNA);
1257+ else
1258+ ::ShowWindow(vd->Hwnd, SW_SHOW);
1259+
1260+ // Restore
1261+ if (avoid_bringing_parent_to_front)
1262+ ::SetWindowLongPtr(vd->Hwnd, GWLP_HWNDPARENT, (LONG_PTR)vd->HwndParent);
1263+}
1264+
1265+static void ImGui_ImplWin32_UpdateWindow(ImGuiViewport* viewport)
1266+{
1267+ ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
1268+ IM_ASSERT(vd->Hwnd != 0);
1269+
1270+ // Update Win32 parent if it changed _after_ creation
1271+ // Unlike style settings derived from configuration flags, this is more likely to change for advanced apps that are manipulating ParentViewportID manually.
1272+ HWND new_parent = ImGui_ImplWin32_GetHwndFromViewport(viewport->ParentViewport);
1273+ if (new_parent != vd->HwndParent)
1274+ {
1275+ // Win32 windows can either have a "Parent" (for WS_CHILD window) or an "Owner" (which among other thing keeps window above its owner).
1276+ // Our Dear Imgui-side concept of parenting only mostly care about what Win32 call "Owner".
1277+ // The parent parameter of CreateWindowEx() sets up Parent OR Owner depending on WS_CHILD flag. In our case an Owner as we never use WS_CHILD.
1278+ // Calling ::SetParent() here would be incorrect: it will create a full child relation, alter coordinate system and clipping.
1279+ // Calling ::SetWindowLongPtr() with GWLP_HWNDPARENT seems correct although poorly documented.
1280+ // https://devblogs.microsoft.com/oldnewthing/20100315-00/?p=14613
1281+ vd->HwndParent = new_parent;
1282+ ::SetWindowLongPtr(vd->Hwnd, GWLP_HWNDPARENT, (LONG_PTR)vd->HwndParent);
1283+ }
1284+
1285+ // (Optional) Update Win32 style if it changed _after_ creation.
1286+ // Generally they won't change unless configuration flags are changed, but advanced uses (such as manually rewriting viewport flags) make this useful.
1287+ DWORD new_style;
1288+ DWORD new_ex_style;
1289+ ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &new_style, &new_ex_style);
1290+
1291+ // Only reapply the flags that have been changed from our point of view (as other flags are being modified by Windows)
1292+ if (vd->DwStyle != new_style || vd->DwExStyle != new_ex_style)
1293+ {
1294+ // (Optional) Update TopMost state if it changed _after_ creation
1295+ bool top_most_changed = (vd->DwExStyle & WS_EX_TOPMOST) != (new_ex_style & WS_EX_TOPMOST);
1296+ HWND insert_after = top_most_changed ? ((viewport->Flags & ImGuiViewportFlags_TopMost) ? HWND_TOPMOST : HWND_NOTOPMOST) : 0;
1297+ UINT swp_flag = top_most_changed ? 0 : SWP_NOZORDER;
1298+
1299+ // Apply flags and position (since it is affected by flags)
1300+ vd->DwStyle = new_style;
1301+ vd->DwExStyle = new_ex_style;
1302+ ::SetWindowLong(vd->Hwnd, GWL_STYLE, vd->DwStyle);
1303+ ::SetWindowLong(vd->Hwnd, GWL_EXSTYLE, vd->DwExStyle);
1304+ RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) };
1305+ ImGui_ImplWin32_AdjustWindowRect(viewport, &rect, vd->DwStyle, vd->DwExStyle); // Client to Screen
1306+ ::SetWindowPos(vd->Hwnd, insert_after, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, swp_flag | SWP_NOACTIVATE | SWP_FRAMECHANGED);
1307+ ::ShowWindow(vd->Hwnd, SW_SHOWNA); // This is necessary when we alter the style
1308+ viewport->PlatformRequestMove = viewport->PlatformRequestResize = true;
1309+ }
1310+}
1311+
1312+static ImVec2 ImGui_ImplWin32_GetWindowPos(ImGuiViewport* viewport)
1313+{
1314+ ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
1315+ IM_ASSERT(vd->Hwnd != 0);
1316+ POINT pos = { 0, 0 };
1317+ ::ClientToScreen(vd->Hwnd, &pos);
1318+ return ImVec2((float)pos.x, (float)pos.y);
1319+}
1320+
1321+static void ImGui_ImplWin32_UpdateWin32StyleFromWindow(ImGuiViewport* viewport)
1322+{
1323+ ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
1324+ vd->DwStyle = ::GetWindowLongW(vd->Hwnd, GWL_STYLE);
1325+ vd->DwExStyle = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE);
1326+}
1327+
1328+static void ImGui_ImplWin32_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
1329+{
1330+ ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
1331+ IM_ASSERT(vd->Hwnd != 0);
1332+ RECT rect = { (LONG)pos.x, (LONG)pos.y, (LONG)pos.x, (LONG)pos.y };
1333+ if (viewport->Flags & ImGuiViewportFlags_OwnedByApp)
1334+ ImGui_ImplWin32_UpdateWin32StyleFromWindow(viewport); // Not our window, poll style before using
1335+ ImGui_ImplWin32_AdjustWindowRect(viewport, &rect, vd->DwStyle, vd->DwExStyle);
1336+ ::SetWindowPos(vd->Hwnd, nullptr, rect.left, rect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1337+}
1338+
1339+static ImVec2 ImGui_ImplWin32_GetWindowSize(ImGuiViewport* viewport)
1340+{
1341+ ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
1342+ IM_ASSERT(vd->Hwnd != 0);
1343+ RECT rect;
1344+ ::GetClientRect(vd->Hwnd, &rect);
1345+ return ImVec2(float(rect.right - rect.left), float(rect.bottom - rect.top));
1346+}
1347+
1348+static void ImGui_ImplWin32_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
1349+{
1350+ ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
1351+ IM_ASSERT(vd->Hwnd != 0);
1352+ RECT rect = { 0, 0, (LONG)size.x, (LONG)size.y };
1353+ if (viewport->Flags & ImGuiViewportFlags_OwnedByApp)
1354+ ImGui_ImplWin32_UpdateWin32StyleFromWindow(viewport); // Not our window, poll style before using
1355+ ImGui_ImplWin32_AdjustWindowRect(viewport, &rect, vd->DwStyle, vd->DwExStyle); // Client to Screen
1356+ ::SetWindowPos(vd->Hwnd, nullptr, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1357+}
1358+
1359+static void ImGui_ImplWin32_SetWindowFocus(ImGuiViewport* viewport)
1360+{
1361+ ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
1362+ IM_ASSERT(vd->Hwnd != 0);
1363+ ::BringWindowToTop(vd->Hwnd);
1364+ ::SetForegroundWindow(vd->Hwnd);
1365+ ::SetFocus(vd->Hwnd);
1366+}
1367+
1368+static bool ImGui_ImplWin32_GetWindowFocus(ImGuiViewport* viewport)
1369+{
1370+ ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
1371+ IM_ASSERT(vd->Hwnd != 0);
1372+ return ::GetForegroundWindow() == vd->Hwnd;
1373+}
1374+
1375+static bool ImGui_ImplWin32_GetWindowMinimized(ImGuiViewport* viewport)
1376+{
1377+ ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
1378+ IM_ASSERT(vd->Hwnd != 0);
1379+ return ::IsIconic(vd->Hwnd) != 0;
1380+}
1381+
1382+static void ImGui_ImplWin32_SetWindowTitle(ImGuiViewport* viewport, const char* title)
1383+{
1384+ // ::SetWindowTextA() doesn't properly handle UTF-8 so we explicitely convert our string.
1385+ ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
1386+ IM_ASSERT(vd->Hwnd != 0);
1387+ int n = ::MultiByteToWideChar(CP_UTF8, 0, title, -1, nullptr, 0);
1388+ ImVector<wchar_t> title_w;
1389+ title_w.resize(n);
1390+ ::MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w.Data, n);
1391+
1392+ // Calling SetWindowTextW() in a project where UNICODE is not set doesn't work but there's a trick
1393+ // which is to pass it directly to the DefWindowProcW() handler.
1394+ // See: https://stackoverflow.com/questions/9410681/setwindowtextw-in-an-ansi-project
1395+ //::SetWindowTextW(vd->Hwnd, title_w.Data);
1396+ ::DefWindowProcW(vd->Hwnd, WM_SETTEXT, 0, (LPARAM)title_w.Data);
1397+}
1398+
1399+static void ImGui_ImplWin32_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
1400+{
1401+ ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
1402+ IM_ASSERT(vd->Hwnd != 0);
1403+ IM_ASSERT(alpha >= 0.0f && alpha <= 1.0f);
1404+ if (alpha < 1.0f)
1405+ {
1406+ DWORD ex_style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) | WS_EX_LAYERED;
1407+ ::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, ex_style);
1408+ ::SetLayeredWindowAttributes(vd->Hwnd, 0, (BYTE)(255 * alpha), LWA_ALPHA);
1409+ }
1410+ else
1411+ {
1412+ DWORD ex_style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED;
1413+ ::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, ex_style);
1414+ }
1415+}
1416+
1417+static float ImGui_ImplWin32_GetWindowDpiScale(ImGuiViewport* viewport)
1418+{
1419+ ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
1420+ IM_ASSERT(vd->Hwnd != 0);
1421+ return ImGui_ImplWin32_GetDpiScaleForHwnd(vd->Hwnd);
1422+}
1423+
1424+// FIXME-DPI: Testing DPI related ideas
1425+static void ImGui_ImplWin32_OnChangedViewport(ImGuiViewport* viewport)
1426+{
1427+ (void)viewport;
1428+#if 0
1429+ ImGuiStyle default_style;
1430+ //default_style.WindowPadding = ImVec2(0, 0);
1431+ //default_style.WindowBorderSize = 0.0f;
1432+ //default_style.ItemSpacing.y = 3.0f;
1433+ //default_style.FramePadding = ImVec2(0, 0);
1434+ default_style.ScaleAllSizes(viewport->DpiScale);
1435+ ImGuiStyle& style = ImGui::GetStyle();
1436+ style = default_style;
1437+#endif
1438+}
1439+
1440+namespace ImGui { extern ImGuiIO& GetIO(ImGuiContext*); extern ImGuiPlatformIO& GetPlatformIO(ImGuiContext*); }
1441+
1442+static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1443+{
1444+ // Allow secondary viewport WndProc to be called regardless of current context
1445+ ImGuiContext* ctx = (ImGuiContext*)::GetPropA(hWnd, "IMGUI_CONTEXT");
1446+ if (ctx == NULL)
1447+ return ::DefWindowProcW(hWnd, msg, wParam, lParam); // unlike ImGui_ImplWin32_WndProcHandler() we are called directly by Windows, we can't just return 0.
1448+
1449+ ImGuiIO& io = ImGui::GetIO(ctx);
1450+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(ctx);
1451+ LRESULT result = 0;
1452+ if (ImGui_ImplWin32_WndProcHandlerEx(hWnd, msg, wParam, lParam, io))
1453+ result = 1;
1454+ else if (ImGuiViewport* viewport = ImGui_ImplWin32_FindViewportByPlatformHandle(platform_io, hWnd))
1455+ {
1456+ switch (msg)
1457+ {
1458+ case WM_CLOSE:
1459+ viewport->PlatformRequestClose = true;
1460+ return 0; // 0 = Operating system will ignore the message and not destroy the window. We close ourselves.
1461+ case WM_MOVE:
1462+ viewport->PlatformRequestMove = true;
1463+ break;
1464+ case WM_SIZE:
1465+ viewport->PlatformRequestResize = true;
1466+ break;
1467+ case WM_MOUSEACTIVATE:
1468+ if (viewport->Flags & ImGuiViewportFlags_NoFocusOnClick)
1469+ result = MA_NOACTIVATE;
1470+ break;
1471+ case WM_NCHITTEST:
1472+ // Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() correctly. (which is optional).
1473+ // The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
1474+ // If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
1475+ // your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
1476+ if (viewport->Flags & ImGuiViewportFlags_NoInputs)
1477+ result = HTTRANSPARENT;
1478+ break;
1479+ }
1480+ }
1481+ if (result == 0)
1482+ result = ::DefWindowProcW(hWnd, msg, wParam, lParam);
1483+ return result;
1484+}
1485+
1486+static void ImGui_ImplWin32_InitMultiViewportSupport(bool platform_has_own_dc)
1487+{
1488+ WNDCLASSEXW wcex;
1489+ wcex.cbSize = sizeof(WNDCLASSEXW);
1490+ wcex.style = CS_HREDRAW | CS_VREDRAW | (platform_has_own_dc ? CS_OWNDC : 0);
1491+ wcex.lpfnWndProc = ImGui_ImplWin32_WndProcHandler_PlatformWindow;
1492+ wcex.cbClsExtra = 0;
1493+ wcex.cbWndExtra = 0;
1494+ wcex.hInstance = ::GetModuleHandle(nullptr);
1495+ wcex.hIcon = nullptr;
1496+ wcex.hCursor = nullptr;
1497+ wcex.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
1498+ wcex.lpszMenuName = nullptr;
1499+ wcex.lpszClassName = L"ImGui Platform";
1500+ wcex.hIconSm = nullptr;
1501+ ::RegisterClassExW(&wcex);
1502+
1503+ ImGui_ImplWin32_UpdateMonitors();
1504+
1505+ // Register platform interface (will be coupled with a renderer interface)
1506+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
1507+ platform_io.Platform_CreateWindow = ImGui_ImplWin32_CreateWindow;
1508+ platform_io.Platform_DestroyWindow = ImGui_ImplWin32_DestroyWindow;
1509+ platform_io.Platform_ShowWindow = ImGui_ImplWin32_ShowWindow;
1510+ platform_io.Platform_SetWindowPos = ImGui_ImplWin32_SetWindowPos;
1511+ platform_io.Platform_GetWindowPos = ImGui_ImplWin32_GetWindowPos;
1512+ platform_io.Platform_SetWindowSize = ImGui_ImplWin32_SetWindowSize;
1513+ platform_io.Platform_GetWindowSize = ImGui_ImplWin32_GetWindowSize;
1514+ platform_io.Platform_SetWindowFocus = ImGui_ImplWin32_SetWindowFocus;
1515+ platform_io.Platform_GetWindowFocus = ImGui_ImplWin32_GetWindowFocus;
1516+ platform_io.Platform_GetWindowMinimized = ImGui_ImplWin32_GetWindowMinimized;
1517+ platform_io.Platform_SetWindowTitle = ImGui_ImplWin32_SetWindowTitle;
1518+ platform_io.Platform_SetWindowAlpha = ImGui_ImplWin32_SetWindowAlpha;
1519+ platform_io.Platform_UpdateWindow = ImGui_ImplWin32_UpdateWindow;
1520+ platform_io.Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale; // FIXME-DPI
1521+ platform_io.Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport; // FIXME-DPI
1522+
1523+ // Register main window handle (which is owned by the main application, not by us)
1524+ // This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
1525+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
1526+ ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
1527+ ImGui_ImplWin32_ViewportData* vd = IM_NEW(ImGui_ImplWin32_ViewportData)();
1528+ vd->Hwnd = bd->hWnd;
1529+ vd->HwndOwned = false;
1530+ main_viewport->PlatformUserData = vd;
1531+}
1532+
1533+static void ImGui_ImplWin32_ShutdownMultiViewportSupport()
1534+{
1535+ ::UnregisterClassW(L"ImGui Platform", ::GetModuleHandle(nullptr));
1536+ ImGui::DestroyPlatformWindows();
9901537 }
9911538
9921539 //---------------------------------------------------------------------------------------------------------
@@ -7,6 +7,7 @@
77 // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values are obsolete since 1.87 and not supported since 1.91.5]
88 // [X] Platform: Gamepad support.
99 // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
10+// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
1011
1112 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
1213 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@@ -183,6 +183,7 @@
183183 - `ImGuiBackendFlags_HasSetMousePos`: supports io.WantSetMousePos requests to reposition the OS mouse position (only used if io.ConfigNavMoveSetMousePos is set).
184184 - `ImGuiBackendFlags_PlatformHasViewports` supports multiple viewports. (multi-viewports only)
185185 - `ImGuiBackendFlags_HasMouseHoveredViewport` supports calling io.AddMouseViewportEvent() with the viewport under the mouse. IF POSSIBLE, ignore viewports with the ImGuiViewportFlags_NoInputs flag. If this cannot be done, Dear ImGui needs to use a flawed heuristic to find the viewport under mouse position, as it doesn't know about foreign windows. (multi-viewports only)
186+ - `ImGuiBackendFlags_HasParentViewport` supports honoring viewport->ParentViewportId value, by applying the corresponding parent/child relation at the Platform level.
186187
187188 **In your `ImGui_ImplXXX_NewFrame()` function:**
188189 - Set `io.DeltaTime` to the time elapsed (in seconds) since last frame.
@@ -36,6 +36,110 @@
3636 - Please report any issue!
3737
3838 -----------------------------------------------------------------------
39+ VERSION 1.92.9 WIP (In Progress)
40+-----------------------------------------------------------------------
41+
42+Breaking Changes:
43+
44+- TreeNode: commented out legacy name `ImGuiTreeNodeFlags_SpanTextWidth` which
45+ was obsoleted in 1.90.7 (May 2024). Use `ImGuiTreeNodeFlags_SpanLabelWidth`.
46+
47+Other Changes:
48+
49+- Windows:
50+ - Clicking on a window's empty-space to move/focus a window checks
51+ for lack of mouse button ownership. This gives an additional opportunity
52+ for user code to bypass it without using a clickable item. (#9382)
53+ - Clicking on a window's empty-space to move/focus a window checks
54+ for lack of queued focus request. (#9382)
55+ - Fixed double-click collapse toggle not owning the mouse button. If a
56+ `SetNextWindowPos()` with pivot was queued in the same frame, the second
57+ click could trigger another item in the same window. (#9439) [@Cleroth]
58+- InputText:
59+ - Added `style.InputTextCursorSize` to configure cursor/caret thickness. (#7031, #9409)
60+ This is automatically scaled by `style.ScaleAllSizes()`.
61+- Tables:
62+ - Redesigned/rewrote code to reconcile columns and settings on topology changes. (#9108)
63+ - When a column label is passed to TableSetupColumn(), the underlying identifier
64+ is used to match live columns data and .ini settings data when changing.
65+ This makes it possible to add/remove columns from a table without losing
66+ neither live data neither .ini settings data.
67+ - PS: Note that this is distinct from toggling column visibility or reordering
68+ columns, which was always possible. The new matching makes it easier to create
69+ tables that are entirely customized by user or code, without losing state.
70+ - Columns without identifiers or with duplicate identifiers are matched
71+ sequentially, matching old behavior.
72+ - Column ID are stored in .ini file.
73+ - Code is being tested both for live topology changes and for loading .ini
74+ data with mismatched topology.
75+ - Context Menu: added a "Reset" sub-menu with a "Reset Visibility" option.
76+ (which is greyed out when using default settings)
77+ - Headers: fixed label being clipped early to reserve space for a sort marker
78+ even when no sort marker is displayed. Auto-fitting a column still accounts
79+ for the possible marker, so that sorting after an auto-fit doesn't clip the label.
80+- Multi-Select
81+ - Reworked ImGuiMultiSelectFlags_NoAutoSelect as it carried side-effects that
82+ were hardcoded/designed to use multi-selection on checkboxes. (#9391)
83+ Specifically removed those undocumented behaviors from _NoAutoSelect:
84+ - Clicking a selected/checked item always unselect/uncheck.
85+ - Shift+Click inverts targets value and copy to range.
86+ - Shift+Keyboard copy selection source value to range.
87+ Those behaviors are still happening on checkboxes used within multi-selection.
88+- Fonts:
89+ - Added `IMGUI_DISABLE_DEFAULT_FONT_BITMAP`/`IMGUI_DISABLE_DEFAULT_FONT_VECTOR` to
90+ disable embedding either fonts separately. (#9407)
91+ - Tweak `CalcTextSize()` awkward width rounding/ceiling code to reduce floating-point
92+ imprecisions altering the result by 1 even at relatively small width. (#791)
93+ - Better document the fact that ImFontAtlas::Clear()/ClearFonts() functions are
94+ unlikely to be useful nowadays. Better recover to an edge case of mistakenly
95+ calling ClearFonts() during rendering.
96+ - Fixed an issue where passing a manually created ImFontAtlas to CreateContext() would
97+ incorrectly destroy it in DestroyContext() when ref-count gets back to zero. (#9426)
98+- Nav:
99+ - Fixed context menu activation with gamepad erroneously testing for _NavEnableKeyboard
100+ instead of _NavEnableGamepad. (#9454, #8803, #9270) [@Clownacy]
101+- TreeNode:
102+ - Fixed nav cursor rendering with rounding even though tree nodes don't have it. (#7589)
103+- Style:
104+ - Added style.MenuItemRounding, ImGuiStyleVar_MenuItemRounding. (#7589, #9375, #9453)
105+ - Added style.SelectableRounding, ImGuiStyleVar_SelectableRounding. (#7589, #9375, #9453)
106+ The use of this is discouraged because it can easily create problems rendering e.g.
107+ contiguous selection.
108+ - Scale the NavCursor border thickness when using large values with `ScallAllSizes()`.
109+- DrawList:
110+ - Minor optimization to `AddLine()`, `AddLineH()`, `AddLineV()` functions. (#4091)
111+ - Added `ImDrawListFlags_TextNoPixelSnap` to disable snapping of AddText()
112+ coordinates for a given scope. (#3437, #9417, #2291)
113+- ColorButton:
114+ - Small rendering tweak/optimization for the alpha checkerboard.
115+- Demo:
116+ - Extract 'Widgets->Tree Nodes->Selectable Nodes' out of the 'Advanced'
117+ demo for clarity (manual reimplementation of basic selection).
118+- Misc:
119+ - Added IM_DEBUG_BREAK() handler for GCC+AArch64/ARM64. [@tom-seddon]
120+- Backends:
121+ - OpenGL3:
122+ - GLSL version detection assume GLSL 410 when GL context is 4.1.
123+ Fixes an issue running on macOS with Wine. [#9427, #6577) [@perminovVS]
124+ - Expose selected render state in ImGui_ImplOpenGL3_RenderState, allowing to
125+ dynamically select between use of glBindSampler() and glTexParameter(). (#9378)
126+ - Win32:
127+ - Uses `SetProcessDpiAwarenessContext()` instead of `SetThreadDpiAwarenessContext()`
128+ when available, fixing OpenGL DPI scaling issues as e.g. NVIDIA drivers tends
129+ to spawn multiple-thread to manage OpenGL. (#9403)
130+
131+Docking+Viewports Branch:
132+
133+- Viewports:
134+ - Fixed an issue where the implicit "Debug" window while hidden would erroneously
135+ interfere with merging secondary viewports into the main viewport.
136+- Docking:
137+ - Fixed behavior change/regression in 1.92.8 where a window using the
138+ ImGuiWindowFlags_AlwaysAutoResize flag would have ItemWidth default
139+ change when docked. (#9355, #9443) [@reybits]
140+
141+
142+-----------------------------------------------------------------------
39143 VERSION 1.92.8 (Released 2026-05-12)
40144 -----------------------------------------------------------------------
41145
@@ -64,9 +168,13 @@
64168 The new order is also more convenient as `flags` are less frequently used than `thickness` in real code.
65169 - As a general policy in Dear ImGui, all our flags default to 0 so ImDrawFlags_None was likely written 0 in some call sites.
66170 - Consider adding `#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS` in your imconfig.h, even temporarily, to clean up legacy code.
171+ - Reminder: you do NOT need to specify `ImDrawFlags_RoundCornersAll` for rounding, it is already the default!
67172 - DrawList: obsoleted `ImDrawCallback_ResetRenderState` in favor of using `ImGui::GetPlatformIO().DrawCallback_ResetRenderState`,
68173 which is part of our new standard draw callbacks. (#9378)
69174 Redirecting the earlier value into the later one when set, so both old and new code should work.
175+- DrawList: changed value of `ImDrawFlags_Closed`. It was previously advertised as "always == 1" when introduced
176+ in 1.82 (2021/02), in order to facilitate backward compatibility with the legacy `bool closed` flag. This
177+ guarantee has been removed. The bit is reserved, and `AddPolyline()`, `PathStroke()` will assert when it is used.
70178 - Backends:
71179 - Vulkan: redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. (#914)
72180 This change allows us to facilitate changing samplers, in line with other backends. [@yaz0r, @ocornut]
@@ -81,6 +189,8 @@
81189 - DirectX10, DirectX11, SDLGPU3, Vulkan: removed samplers from `ImGui_ImplXXXX_RenderState`.
82190 Prefer to use backend-agnostic DrawCallback_SetSamplerLinear which works everywhere! (#9378)
83191 If there is a legit need/request for them or any render state we can always add them back.
192+ - OpenGL3: the new sampler support system prioritize using glBindSampler() when available,
193+ which would override glTexParameter() settings you may have set on custom textures. (#9378)
84194
85195 Other Changes:
86196
@@ -97,6 +207,15 @@
97207 #5999, #6452, #5156, #7342, #7592, #7511)
98208 - Made `AddCallback()` user data default to Null for convenience.
99209 - Added `AddLineH()`, `AddLineV()` helpers to draw horizontal and vertical lines. [@memononen]
210+ The new functions are more optimal and will be part of a larger effort in 1.93 to fix
211+ inconsistencies and improve the DrawList API. In the current API, `AddLine()` adds a "magic" +0.5f
212+ offset and then center the line, whereas AddLineH()/AddLineV() use the right side of the line to expand.
213+ For thickness=1.0f lines this is equivalent:
214+ `AddLine({10,3}, {20,3}, ...)` --> `AddLineH(x1=10, x2=20, y=3, ...)`.
215+ `AddLine({3,10}, {3,20}, ...)` --> `AddLineV(x=3, y1=10, y2=20, ...)`.
216+ For larger integer thickness, AddLine() will center but may be blurry, AddLineH()/AddLineV()
217+ will expand "inside" (to the right side) and will always be sharp.
218+ A subsequent release will expand on those concepts and add new options.
100219 - InputText:
101220 - InputTextMultiline: fixed an issue processing deactivation logic when an active
102221 multi-line edit is clipped due to being out of view.
@@ -225,7 +344,15 @@
225344 - `IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE` descriptors of type `VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE`.
226345 - `IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE` descriptors of type `VK_DESCRIPTOR_TYPE_SAMPLER`.
227346
347+Docking+Viewports Branch:
228348
349+- Docking:
350+ - Toggling tab bar visibility marks saved settings as dirty. (#9380)
351+- Viewports:
352+ - Added opaque `void* PlatformIconData` storage in viewport and `ImGuiWindowClass`
353+ to allow passing icon information to a custom backend or hook. (#2715)
354+
355+
229356 -----------------------------------------------------------------------
230357 VERSION 1.92.7 (Released 2026-04-02)
231358 -----------------------------------------------------------------------
@@ -294,7 +421,7 @@
294421 part of the scroll freeze. So if you intentionally hide columns <N, the scroll
295422 freeze area would start covering the subsequent/following columns (N+1) etc.
296423 - After: `TableSetupScrollFreeze(N, 0)`: include the N left-most columns (regardless of visibility),
297- as part of the scroll freeze. So if you intentionally hide columns <N, the scroll
424+ part of the scroll freeze. So if you intentionally hide columns <N, the scroll as
298425 freeze area will cover less columns.
299426 - This is generally more sane and logical.
300427 - Fixed dragging a header to reorder outside of visible bounds (due to horizontal scrolling)
@@ -390,7 +517,24 @@
390517 - GLFW/SDL2/SDL3+WebGPU: added support for WGVK. (#9316, #9246, #9257) [@r-lyeh, @ocornut]
391518 - GLFW/SDL2/SDL3+WebGPU: removed support for Emscripten <4.0.10. (#9281) [@ypujante]
392519
520+Docking+Viewports Branch:
393521
522+- Viewports:
523+ - Fixed an issue where the implicit "Debug" window would erroneously be targetted for
524+ mouse inputs while hidden if (1) the implicit "Debug" window was used in a previous
525+ session and moved to a secondary viewport and (2) the Platform Backend does not
526+ support the `ImGuiBackendFlags_HasMouseHoveredViewport` feature. (#9254)
527+ - Backends: SDL2, SDL3: fixed an issue dated 2025/04/09 (1.92 WIP) where a refactor
528+ and a merge caused `ImGuiBackendFlags_HasMouseHoveredViewport` to never be set, causing
529+ foreign windows to be ignored when deciding of hovered viewport. (#9284) [@ravencgg]
530+ - Backends: SDL3: use `SDL_HAS_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED` (SDL 3.4.0+) when
531+ available to avoid refreshing monitor work area every frame on Windows. (#8415)
532+ - Backends: Win32: fixed setting/getting correct size when viewports have OS decorations
533+ enabled (e.g. io.ConfigViewportsNoDecoration = false) and process is running in
534+ Per-Monitor V2 DPI mode. May be related to incorrect mouse offset when using
535+ decorated OS windows. (#8897) [@lailoken]
536+
537+
394538 -----------------------------------------------------------------------
395539 VERSION 1.92.6 (2026-02-17)
396540 -----------------------------------------------------------------------
@@ -632,7 +776,38 @@
632776 - Win32+DirectX12: ignore seemingly incorrect `D3D12_MESSAGE_ID_FENCE_ZERO_WAIT`
633777 warning on startups on some setups. (#9084, #9093) [@RT2Code, @LeoGautheron]
634778
779+Docking+Viewports Branch:
635780
781+- Docking:
782+ - Fixed various rendering issues and ability to have rounded floating dock nodes.
783+ (#6993, #6151) - please note that rounding is still disabled on standalone
784+ viewports.
785+ - Fixed implicit/fallback "Debug" window from staying visible if once docked. (#9151)
786+ - Demo: rework 'Dockspace' demo to increase clarity and put more emphasis on the
787+ basic path of simply calling `DockSpaceOverViewport()`.
788+- Viewports:
789+ - Fixed a regression in 1.92.4 where partially moving a floating docking node
790+ with horizontal/vertical split over the main viewport would set the window in
791+ an invalid state in some situations, making user unable to further interact
792+ with the window.
793+ - Fixed a regression in 1.92.4 which could cause combos/popups window from
794+ appearing under their parent viewport if their geometry overlapped the main
795+ viewport. (#8948, #9172, #9131, #9128)
796+ - Fixed an assert in background dimming code, which could trigger after using
797+ gamepad/keyboard to move a window to another viewport. (#9053) [@lut0pia, @ocornut]
798+- Backends:
799+ - GLFW: dynamically load X11 functions to avoid `-lx11` linking requirement introduced
800+ in 1.92.3. (#9116, #9109) [@ramenguy99]
801+ - GLFW: improve workarounds for cases where GLFW is unable to provide reliable monitor
802+ info. Preserve existing monitor list when none of the new one is valid. (#9195, #7902, #5683)
803+ - SDL2, SDL3: adjust IME offset to match other backends and master branch. (#6071, #1953)
804+ - Win32: viewports created by backend forcefully direct messages to
805+ `DefWindowProcW()` in order to support Unicode text input. (#9099, #3653, #5961) [@ulhc]
806+ - Win32: fixed an issue from 1.90.5 where newly appearing windows that are not parented
807+ to the main viewport didn't have their task bar icon appear before the window was
808+ explicitly refocused. (#7354, #8669)
809+
810+
636811 -----------------------------------------------------------------------
637812 VERSION 1.92.5 (Released 2025-11-20)
638813 -----------------------------------------------------------------------
@@ -777,7 +952,23 @@
777952 - SDL3+WebGPU: added new example (Emscripten + native Dawn/WGPU). (#8381) [@brutpitt]
778953 - Win32+OpenGL3: enable DPI awareness. (#9083)
779954
955+Docking+Viewports Branch:
780956
957+- Docking, Style: fixed per-window ImGuiCol_UnsavedMarker changes not being latched
958+ by docked windows. (#8983, #9064)
959+- Docking: fixed crash loading certain form of invalid .ini settings (e.g. nodes
960+ referring to a missing parent, duplicate nodes id). (#9070)
961+- Docking: added io.ConfigDockingNoDockingOver helper config flag to prevent
962+ merging windows into a same tab-bar.
963+- Examples:
964+ - SDL2+DX11, SDL3+DX11, Win32+DX10, Win32+DX11: fixed one resource leak
965+ from the use of MakeWindowAssociation() in 1.92.4. (#9010, #4350) [@o-3-o]
966+- Backends:
967+ - DirectX12: Fixed an issue in synchronization logic improving rendering
968+ throughput for secondary viewports. (#9025, #8961)
969+ - Vulkan: handle viewport surface creation failure without crashing. (#9068) [@zentia]
970+
971+
781972 -----------------------------------------------------------------------
782973 VERSION 1.92.4 (Released 2025-10-14)
783974 -----------------------------------------------------------------------
@@ -786,6 +977,10 @@
786977
787978 Breaking Changes:
788979
980+- Viewports: for consistency with other config flags, renamed
981+ io.ConfigViewportPlatformFocusSetsImGuiFocus
982+ to io.ConfigViewportsPlatformFocusSetsImGuiFocus. (#6299, #6462)
983+ It was really a typo in the first place, and introduced in 1.92.2.
789984 - Backends:
790985 - TreeNode, Selectable, Clipper: commented out legacy names obsoleted in
791986 1.89.7 (July 2023) and 1.89.9 (Sept 2023):
@@ -887,7 +1082,54 @@
8871082 - Win32+DirectX12: Rework synchronization logic. (#8961) [@RT2Code]
8881083 - Made examples's main.cpp consistent with returning 1 on error.
8891084
1085+Docking+Viewports Branch:
8901086
1087+- Nav, Docking, Selection: Fixed tab change from reinitializing navigation state,
1088+ which would erroneously clear selection when using ImGuiSelectableFlags_SelectOnNav
1089+ or clear multi-selection when not using ImGuiMultiSelectFlags_NoAutoSelect. (#8997)
1090+- Nav: Fixed a crash that could occur when opening a popup following the processing
1091+ of a global shortcut while no windows were focused (the fix done in 1.92.3 was
1092+ incomplete for docking branch).
1093+- Viewports:
1094+ - Added ImGuiBackendFlags_HasParentViewport backend flag for
1095+ backend to specify if it can honor the `viewport->ParentViewport`/`ParentViewportId`
1096+ value by applying the corresponding parent/child relation at the Platform level. (#8948)
1097+ - SDL3, Win32 backends: supported.
1098+ - SDL2, GLFW, OSX backends: unsupported.
1099+ - Fixed a bug where ImGuiWindowFlags_NoBringToFrontOnFocus would effectively
1100+ be ignored when windows first appear and viewports are enabled. (#7008) [@jshofmann]
1101+ - Changed default value of io.ConfigViewportsNoDefaultParent to true. (#8948)
1102+ As a reminder, for backend honoring ParentViewportID:
1103+ - Parented windows will always appear in front of the main viewport.
1104+ - Non-parented windows can appear behing the main viewport.
1105+ - Fixed an issue inferring Z-order when attempting to merge a viewport
1106+ back in the the main/hosting viewport. (#8948)
1107+ Note that for GLFW/SDL2/OSX backends, which do not support honoring ParentViewportID.
1108+ Setting io.ConfigViewportsNoDefaultParent=true will align imgui's expectation
1109+ with what the backend does.
1110+ - Storing `ImGuiViewport* ParentViewport` pointer along with ParentViewportID.
1111+ - ImGui::DestroyContext() does not call DestroyPlatformWindows() anymore at it
1112+ is assumed to be unnecessary as backends should have done it and we check that
1113+ backends have been shutdown since 1.90.4. Changed into asserts. (#7175, #8945)
1114+- Backends:
1115+ - DirectX10, DirectX11, DirectX12: Disabled DXGI's Alt+Enter default behavior on
1116+ secondary viewports managed by the backend. (#4350) [@PathogenDavid]
1117+ - DirectX10, DirectX11: avoid ImGui_ImplXXXX_SwapBuffers() handlers for secondary
1118+ viewports crashing if SwapChain could not be created.
1119+ - Vulkan: Added a way to configure secondary viewport pipeline creation by
1120+ setting init_info.PipelineInfoForViewports fields. (#8946, #8110, #8111, #8686)
1121+ - Vulkan: Added a way to configure secondary viewport swapchain VkImageUsageFlags
1122+ to e.g. capture rendering. (#8946, #8940) [@olivier-gerard, @ocornut]
1123+ Usage example: `init_info.PipelineInfoForViewports.SwapChainImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;`
1124+ - Vulkan: pipeline created for secondary viewport automatically match
1125+ surface format. (#8686) [@sylmroz]
1126+ - Vulkan: Added ImGui_ImplVulkanH_GetWindowDataFromViewport() accessor/helper. (#8946, #8940) [@olivier-gerard]
1127+- Docs: improve docking API comments and demo. (#9000)
1128+- Examples: DX10, DX11: Disabled DXGI's Alt+Enter default behavior in examples.
1129+ Applications are free to leave this enabled, but it does not work properly with
1130+ multiple viewports. (#4350, #8979) [@PathogenDavid]
1131+
1132+
8911133 -----------------------------------------------------------------------
8921134 VERSION 1.92.3 (Released 2025-09-17)
8931135 -----------------------------------------------------------------------
@@ -981,7 +1223,23 @@
9811223 - Backends: Vulkan: added ImGui_ImplVulkan_CreateMainPipeline() to recreate pipeline
9821224 without reinitializing backend. (#8110, #8111) [@SuperRonan]
9831225
1226+Docking+Viewports Branch:
9841227
1228+- DPI: fixed io.ConfigDpiScaleFonts from ever working since 1.92 (the irony
1229+ being that it is when it started to make sense!). As a reminder, the option
1230+ automatically copy the _current_ viewport DpiScale to style.FontScaleDpi.
1231+ This is why we separated the style.FontScaleMain and style.FontScaleDpi scaling
1232+ factor, as the later is meant to be overwritten. (#8832, #8465)
1233+- DPI: Fixed obsoleted ImGuiConfigFlags_DpiEnableScaleFonts/_DpiEnableScaleViewports
1234+ names from setting the equivalent io.ConfigDpiScaleFonts/io.ConfigDpiScaleViewports
1235+ flag correctly (regression in 1.92).
1236+- Docking, Style: added style.DockingNodeHasCloseButton option to hide the
1237+ Close Button attached to each docking node. (#8933)
1238+- Backends: GLFW: improve multi-viewport behavior in tiling WMs on X11.
1239+ Note: using GLFW backend on Linux/BSD etc. requires linking with `-lX11`.
1240+ (#8884, #8474, #8289, #2117) [@Ikos3k, @Madman10K]
1241+
1242+
9851243 -----------------------------------------------------------------------
9861244 VERSION 1.92.2b (Released 2025-08-13)
9871245 -----------------------------------------------------------------------
@@ -1002,7 +1260,13 @@
10021260 - Backends: Allegro5: Fixed missing support for ImGuiKey_PrintScreen
10031261 under Windows, as raw Allegro 5 does not receive it.
10041262
1263+Docking+Viewports Branch:
10051264
1265+- Fixed a bug where closing a viewport using OS facility (e.g. ALT+F4, Close Button)
1266+ would erroneously close all windows located in the viewport, even ones docked
1267+ into nested dockspaces. Only top-most windows should be closed. (#8887) [@lailoken]
1268+
1269+
10061270 -----------------------------------------------------------------------
10071271 VERSION 1.92.2 (Released 2025-08-11)
10081272 -----------------------------------------------------------------------
@@ -1089,7 +1353,20 @@
10891353 - Backends: Vulkan: Avoid calling vkCmdBindDescriptorSets() when texture
10901354 has not changed. (#8666) [@micb25]
10911355
1356+Docking+Viewports Branch:
10921357
1358+- Windows, Viewport: fixed an issue where interrupting a viewport move with
1359+ e.g. a ClearActiveID() call would leave the dragged viewport with the
1360+ normally temporary ImGuiViewportFlags_NoInputs flag, preventing further
1361+ interactions with the viewport. (#5324) (thanks @mdelaharpe)
1362+- Viewports: added io.ConfigViewportPlatformFocusSetsImGuiFocus to opt-out
1363+ of focusing imgui windows When a platform window is focused (e.g. using Alt+Tab,
1364+ clicking Platform Title Bar). In principle this is better enabled but we
1365+ provide an opt-out because some Linux window managers tend to eagerly focus
1366+ windows (on e.g. mouse hover, or even on a simple window pos/size change).
1367+ (#6299, #6462)
1368+
1369+
10931370 -----------------------------------------------------------------------
10941371 VERSION 1.92.1 (Released 2025-07-09)
10951372 -----------------------------------------------------------------------
@@ -1138,7 +1415,11 @@
11381415 - Backends: Vulkan: fixed texture synchronization issue introduced in 1.92.0,
11391416 leading to validation layers reacting. (#8772) [@Majora320]
11401417
1418+Docking+Viewports Branch:
11411419
1420+- Backends: OSX: Fixed multi-viewport handling broken in 1.92.0. (#8644, #8777) [@cfillion]
1421+
1422+
11421423 -----------------------------------------------------------------------
11431424 VERSION 1.92.0 (Released 2025-06-25)
11441425 -----------------------------------------------------------------------
@@ -1365,6 +1646,9 @@
13651646 - Imgui_ImplSDLGPU3_PrepareDrawData() --> ImGui_ImplSDLGPU3_PrepareDrawData()
13661647 - Internals: RenderTextEllipsis() function removed the 'float clip_max_x' parameter directly
13671648 preceding 'float ellipsis_max_x'. Values were identical for a vast majority of users. (#8387)
1649+- [Docking] renamed/moved ImGuiConfigFlags_DpiEnableScaleFonts -> bool io.ConfigDpiScaleFonts.
1650+- [Docking] renamed/moved ImGuiConfigFlags_DpiEnableScaleViewports -> bool io.ConfigDpiScaleViewports.
1651+ **Neither of those flags are very useful in current code. They will be useful once we merge font changes.**
13681652
13691653 Non-breaking Fonts/Textures related changes:
13701654
@@ -1598,7 +1882,36 @@
15981882 - Examples: DirectX12+Win32: also test for IsIconic() for sleeping since we don't seem to
15991883 get a DXGI_STATUS_OCCLUDED signal when minimized. (#8603) [@dooann]
16001884
1885+Docking+Viewports Branch:
16011886
1887+- Viewports: added per-viewport FramebufferScale for Retina display multi-monitor support.
1888+ Backend must provide platform_io.platform_io.Platform_GetWindowFramebufferScale handler.
1889+ This effectively fixes clipping/rendering on multi-monitors with varying Retina scale.
1890+ (#1065, #1542, #1676, #1786, #2826, #3757, #5081, #5580, #5592, #6465, #7273, #7779 etc.)
1891+- Viewports: fixed handling of simultaneous move + resize (e.g. toggling maximized)
1892+ when ImGuiConfigFlags_DpiEnableScaleViewports is enabled.
1893+- Backends: Win32: Viewports: fixed an issue when closing a window from
1894+ the OS close button (with io.ConfigViewportsNoDecoration=false) while
1895+ user code is discarding the 'bool *p_open=false output' from Begin().
1896+ Because we allowed the Win32 window to close early, Windows destroyed
1897+ it and our imgui window became not visible even though user code was
1898+ still submitting it. (#8670)
1899+- Backends: Win32: Viewports: handle WM_DPICHANGED in backend when
1900+ ImGuiConfigFlags_DpiEnableScaleViewports is enabled.
1901+- Backends: GLFW, SDL2, SDL3, Apple: provide Platform_GetWindowFramebufferScale handler,
1902+ (#1065, #1542, #1676, #1786, #2826, #3757, #5081, #5580, #5592, #6465, #7273, #7779 etc.)
1903+- Backends: SDLGPU3 for SDL3: added multi-viewport support. (#8573) [@Lekoopapaul]
1904+- Backends: SDL2, SDL3: revert updating monitors and work areas info every
1905+ frame. Only do it on Windows to detect task-bar resize until we get an
1906+ adequate event for it. (#8415, #8558)
1907+- Backends: SDL3: macOS: Fixed secondary-viewports not appearing on a different
1908+ monitor than the main viewport. Because SDL_SetWindowParent() seems to restrict it.
1909+- Backends: GLFW: Disable multi-viewports under Wayland (require GLFW 3.4). (#8587)
1910+- Backends: GLFW: Fixed an issue where Win32 specific WndProc hook was not installed
1911+ for all GLFW version, preventing mouse vs touch detection from working on
1912+ secondary viewports.
1913+
1914+
16021915 -----------------------------------------------------------------------
16031916 VERSION 1.91.9b (Released 2025-03-17)
16041917 -----------------------------------------------------------------------
@@ -1730,6 +2043,8 @@
17302043 with asserts enabled. (#8452)
17312044 - Backends: SDL2, SDL3: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn
17322045 handler. (#7660) [@achabense]
2046+- Backends: SDL2, SDL3: Use display bounds when SDL_GetDisplayUsableBounds()
2047+ fails or return a zero size. (#8415, #3457)
17332048 - Backends: SDL2, SDL3, Win32, Allegro5: Added support for ImGuiMouseCursor_Wait
17342049 and ImGuiMouseCursor_Progress cursors.
17352050 - Backends: SDL2, SDL3: Avoid calling SDL_GetGlobalMouseState() when mouse is in
@@ -1752,7 +2067,23 @@
17522067 [@PhantomCloak] (#8369)
17532068 - Backends: WebGPU: Fix for webgpu-native API changes. (#8426) [@pplux]
17542069
2070+Docking+Viewports Branch:
17552071
2072+- Docking: Removed legacy assert preventing to call DockBuilderSplitNode() on an existing
2073+ split node. This makes using DockBuilder a little more flexible and bearable! (#8472) [@MegaMech]
2074+- Viewports: fixed an issue where in certain cases, a window repositioning leading
2075+ to a monitor change could have the window incorrectly get clamped within the boundaries
2076+ of its previous monitor. Would happen e.g. when loading .ini data during runtime. (#8484)
2077+- Viewports: fixed an assert when a window load settings with a position outside
2078+ monitor bounds, when there are multiple monitors. (#8393, #8385) [@gaborodriguez]
2079+- Viewports + Backends: Win32: Fixed setting title bar text when application
2080+ is compiled without UNICODE. (#7979, #5725) [@lailoken]
2081+- Backends: GLFW, SDL2/SDL3: Update monitors and work areas information every frame,
2082+ as the later may change regardless of monitor/display changes. (#8415)
2083+- Backends: Win32: WM_SETTINGCHANGE's SPI_SETWORKAREA message also triggers a refresh
2084+ of monitor list, as they contain work area information. (#8415) [@PathogenDavid, @lailoken]
2085+
2086+
17562087 -----------------------------------------------------------------------
17572088 VERSION 1.91.8 (Released 2025-01-31)
17582089 -----------------------------------------------------------------------
@@ -1814,7 +2145,7 @@
18142145 one without the other is never correct. (#8174, #6556, #6336, #4723)
18152146 - Examples: DirectX12: Reduced number of frame in flight from 3 to 2 in
18162147 provided example, to reduce latency.
1817-- Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by
2148+- Backends+Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by
18182149 vkAcquireNextImageKHR() or vkQueuePresentKHR(). (#7825, #7831) [@NostraMagister]
18192150 - Backends: SDL2: removed assert preventing using ImGui_ImplSDL2_SetGamepadMode()
18202151 with ImGui_ImplSDL2_GamepadMode_Manual and an empty array. (#8329)
@@ -1828,7 +2159,15 @@
18282159 ImGui_ImplDX12_InitInfo instead of creating its own.
18292160 - Backends: OSX: Removed notification observer when shutting down. (#8331) [@jrachele]
18302161
2162+Docking+Viewports Branch:
18312163
2164+- Docking: Fixed an issue in 1.91.7 where using legacy ImGuiWindowFlags_NavFlattened
2165+ flag (instead of ImGuiChildFlags_NavFlattened) in docking branch would conflict
2166+ with internal docking flags. (#8357) [@DanielGibson]
2167+- Backends: SDL3: new viewport windows are created with the SDL_WINDOW_HIDDEN flag
2168+ before calling SDL_ShowWindow(). (#8328) [@PathogenDavid]
2169+
2170+
18322171 -----------------------------------------------------------------------
18332172 VERSION 1.91.7 (Released 2025-01-14)
18342173 -----------------------------------------------------------------------
@@ -1962,7 +2301,16 @@
19622301 - Examples: Win32+DX12: Using a basic free-list allocator to manage multiple
19632302 SRV descriptors.
19642303
2304+Docking+Viewports Branch:
19652305
2306+- Docking: Added an assert to clarify that ImGuiDockNodeFlags_CentralNode flag
2307+ (from internals) does not need to be passed to DockSpace(), as it causes general
2308+ havoc. (#8145)
2309+- Backends: Win32: Fixed a crash/regression in 1.91.5 when running two processes
2310+ with multi-viewports (was using GetProp() to query property which could have
2311+ belonged to another process). (#8162, #8069) [@sammyfreg, @ocornut]
2312+
2313+
19662314 -----------------------------------------------------------------------
19672315 VERSION 1.91.5 (Released 2024-11-07)
19682316 -----------------------------------------------------------------------
@@ -2021,7 +2369,16 @@
20212369 - Examples: Android+OpenGL: Using ALooper_pollOnce() instead of ALooper_pollAll()
20222370 which has been deprecated. (#8013) [@feather179]
20232371
2372+Docking+Viewports Branch:
20242373
2374+- Backends: GLFW: added Linux workaround for spurious mouse up events emitted while dragging
2375+ and creating new viewports. Generally they would be interrupting a dragging operations.
2376+ (#3158, #7733, #7922) [@rokups, @ocornut]
2377+- Docking: fixed using ImGuiDockNodeFlags_KeepAliveOnly with DockSpaceOverViewport():
2378+ the normally invisible space did erroneously claim mouse hover and could be potentially
2379+ focused. (#8125) [@kcbanner]
2380+
2381+
20252382 -----------------------------------------------------------------------
20262383 VERSION 1.91.4 (Released 2024-10-18)
20272384 -----------------------------------------------------------------------
@@ -2110,7 +2467,12 @@
21102467 - Backends: DX9, DX10, DX11, DX12, OpenGL, Vulkan, WGPU: Changed default texture sampler
21112468 to Clamp instead of Repeat/Wrap. (#7468, #7511, #5999, #5502, #7230)
21122469
2470+Docking+Viewports Branch:
21132471
2472+- Backends: changed all backends to allow enabling ImGuiConfigFlags_ViewportsEnable
2473+ after initialization. (#5371)
2474+
2475+
21142476 -----------------------------------------------------------------------
21152477 VERSION 1.91.3 (Released 2024-10-04)
21162478 -----------------------------------------------------------------------
@@ -2173,6 +2535,13 @@
21732535 - Backends: WebGPU: Fixed DAWN api change using WGPUStringView in WGPUShaderSourceWGSL.
21742536 (#8009, #8010) [@blitz-research]
21752537
2538+Docking+Viewports Branch:
2539+
2540+- Backends: SDL2, SDL3: Fixed building for UWP platforms. (#8008)
2541+- Backends: Win32: Use ResisterClassW()/CreateWindowExW() for secondary viewports, to
2542+ ensure correct IME input even if the backend was compiled in MBCS mode. (#7979, #5725)
2543+
2544+
21762545 -----------------------------------------------------------------------
21772546 VERSION 1.91.2 (Released 2024-09-19)
21782547 -----------------------------------------------------------------------
@@ -2233,6 +2602,18 @@
22332602 - Backends: WebGPU: Added support for optional IMGUI_IMPL_WEBGPU_BACKEND_DAWN / IMGUI_IMPL_WEBGPU_BACKEND_WGPU
22342603 defines to handle ever-changing native implementations. (#7977, #7969, #6602, #6188, #7523) [@acgaudette]
22352604
2605+Docking+Viewports Branch:
2606+
2607+- Viewports: fixed an issue where a window manually constrained to the main viewport while crossing
2608+ over main viewport bounds isn't translated properly. (#7985)
2609+- Backends: SDL2, SDL3, Win32: ensure that ImGuiPlatformMonitor list is available after backend Init call. (#7995)
2610+- Backends: Win32: fixed direct calls to platform_io.Platform_SetWindowPos()/Platform_SetWindowSize()
2611+ on windows created by application (typically main viewport).
2612+- Backends: Win32: fixed an issue where a viewport destroyed while clicking would hog
2613+ mouse tracking and temporary lead to incorrect update of HoveredWindow. (#7971)
2614+- Backends: SDL3: added support for viewport->ParentViewportId field to support parenting
2615+ windows at OS level. (#7973, #7989) [@RT2code]
2616+
22362617 -----------------------------------------------------------------------
22372618 VERSION 1.91.1 (Released 2024-09-04)
22382619 -----------------------------------------------------------------------
@@ -2316,6 +2697,16 @@
23162697 to handle minimization without burning CPU or GPU by running unthrottled code. (#7844)
23172698 - Examples: SDL3: Update for API changes: SDL_Init() returns 0 on failure.
23182699
2700+Docking+Viewports Branch:
2701+
2702+- Viewports: added optional platform_io.Platform_GetWindowWorkAreaInsets() hook
2703+ to allow backends to alter the default per-viewport work-area. (#7823)
2704+- Backends: don't report monitors with DpiScale of 0, which seemed to be reported for
2705+ virtual monitors instead by accessibility drivers. (#7902) [@nicolasnoble, @ocornut]
2706+- Backends: SDL2, SDL3: using SDL_HINT_WINDOW_NO_ACTIVATION_WHEN_SHOWN to support the
2707+ ImGuiViewportFlags_NoFocusOnAppearing flag, instead of using a Win32-specific hack.
2708+ (#7896) [@RT2Code]
2709+
23192710 -----------------------------------------------------------------------
23202711 VERSION 1.91.0 (Released 2024-07-30)
23212712 -----------------------------------------------------------------------
@@ -2475,7 +2866,17 @@
24752866 - Backends: GLFW+Emscripten: Fixed Emscripten warning when using mouse wheel on some setups
24762867 "Unable to preventDefault inside passive event listener". (#7647, #7600) [@ypujante]
24772868
2869+Docking+Viewports Branch:
24782870
2871+- Viewports: Always update fallback monitor to primary monitor if there's one.
2872+- Backends: OSX: Fixed NSAppKitVersion version limit for setWantsBestResolutionOpenGLSurface
2873+ usage. (#7814) [@YGXXD]
2874+- Backends: SDL3: Fixed a bug preventing ImGuiViewportFlags_NoFocusOnAppearing support from
2875+ working (Windows only).
2876+- Backends: Vulkan: ImGui_ImplVulkan_SwapBuffers() used by secondary viewports still proceeds
2877+ increasing frame counters on VK_SUBOPTIMAL_KHR. (#7825, #3881) [@NostraMagister]
2878+
2879+
24792880 -----------------------------------------------------------------------
24802881 VERSION 1.90.9 (Released 2024-07-01)
24812882 -----------------------------------------------------------------------
@@ -2556,7 +2957,20 @@
25562957 returning VK_SUBOPTIMAL_KHR, which doesn't seem to happen on Wayland. (#7671)
25572958 [@AndreiNego, @ocornut]
25582959
2960+Docking+Viewports Branch:
25592961
2962+- Windows, Menus: Fixed an issue where the size of sub-menu in their own viewport
2963+ would be erroneously clamped to the size of main viewport. (#7730)
2964+- Merged GetBackgroundDrawList() and GetBackgroundDrawList(ImGuiViewport* viewport)
2965+ api entry points into a same one GetBackgroundDrawList(ImGuiViewport* viewport = NULL);
2966+- Merged GetForegroundDrawList() and GetForegroundDrawList(ImGuiViewport* viewport)
2967+ api entry points into a same one GetForegroundDrawList(ImGuiViewport* viewport = NULL);
2968+- Backends: SDL3: Update for introduction of SDL_GLContext from void*. (#7701, #7702)
2969+ [@bcsanches]
2970+- Backends: Win32: Secondary viewports WndProc handler retrieve/set imgui context from
2971+ the HWND, allowing WndProc dispatch to work in multi-context setups.
2972+
2973+
25602974 -----------------------------------------------------------------------
25612975 VERSION 1.90.8 (Released 2024-06-06)
25622976 -----------------------------------------------------------------------
@@ -2706,7 +3120,16 @@
27063120 those API public. Only past users of imgui_internal.h with the extra parameters will be affected.
27073121 Added asserts for valid flags in various functions to detect _some_ misuses, BUT NOT ALL.
27083122
3123+Docking+Viewports Branch:
27093124
3125+- Docking: *BREAKING* changed signature of DockSpaceOverViewport() to allow passing
3126+ an explicit dockspace id if desired. (#7611)
3127+ Before: DockSpaceOverViewport(const ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags flags = 0, ...);
3128+ After: DockSpaceOverViewport(ImGuiID dockspace_id = 0, const ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags flags = 0, ...);
3129+ Simply add a leading 0 to your existing calls to DockSpaceOverViewport() if you have any.
3130+- Tables: resizing border hit-rect scales according to current monitor dpi scale.
3131+
3132+
27103133 -----------------------------------------------------------------------
27113134 VERSION 1.90.6 (Released 2024-05-08)
27123135 -----------------------------------------------------------------------
@@ -2764,7 +3187,19 @@
27643187 - Examples: GLFW+WebGPU: Added support for WebGPU-native/Dawn (#7435, #7132) [@eliasdaler, @Zelif]
27653188 - Examples: GLFW+WebGPU: Renamed example_emscripten_wgpu/ to example_glfw_wgpu/. (#7435, #7132)
27663189
3190+Docking+Viewports Branch:
27673191
3192+- Docking: when io.ConfigDockingWithShift is enabled, fixed help tooltip erroneously
3193+ reading SetNextWindowXXX() data. (#6709, #4643, #7491) [@ocornut, @cfillion]
3194+- Viewports: fixed outer-right edge of MenuBar clipping rectangle off by one when window
3195+ is located on a monitor with negative coordinates. (#6861, #2884) [@cfillion]
3196+- Backends: Vulkan: reworked swap-chain resize handling for secondary viewports, fix for
3197+ typical Linux setups. (#2626, #3390, #3758, #7508, #7513) [@RoryO, @InsideBSITheSecond]
3198+- Backends: Vulkan: create a custom pipeline for secondary viewports. Fixes issues
3199+ when user created main viewport uses a different renderpass. (#6325, #6305, #7398,
3200+ #3459, #3253, #3522) [@skaman, @FunMiles]
3201+
3202+
27683203 -----------------------------------------------------------------------
27693204 VERSION 1.90.5 (Released 2024-04-11)
27703205 -----------------------------------------------------------------------
@@ -2820,7 +3255,12 @@
28203255 Adding a link to the crawlable version, even though it is not intended for humans,
28213256 to increase its search rank.
28223257
3258+Docking+Viewports Branch:
28233259
3260+- Backends: Win32: made it so that an appearing viewport showing up doesn't bring
3261+ its parent to front. (#7354)
3262+
3263+
28243264 -----------------------------------------------------------------------
28253265 VERSION 1.90.4 (Released 2024-02-22)
28263266 -----------------------------------------------------------------------
@@ -2853,7 +3293,14 @@
28533293 - Demo: Custom Rendering: better demonstrate PathArcTo(), PathBezierQuadraticCurveTo(),
28543294 PathBezierCubicCurveTo(), PathStroke(), PathFillConvex() functions.
28553295
3296+Docking+Viewports Branch:
28563297
3298+- Backends: GLFW: enable ImGuiBackendFlags_HasMouseHoveredViewport support with GLFW 3.3.x,
3299+ as required specs for it was relaxed in 1.87. This enable better viewport hovering detection
3300+ without GLFW 3.4's GLFW_MOUSE_PASSTHROUGH, with less reliance on dear imgui's own heuristic
3301+ of platform windows order. (#7316)
3302+
3303+
28573304 -----------------------------------------------------------------------
28583305 VERSION 1.90.3 (Released 2024-02-14)
28593306 -----------------------------------------------------------------------
@@ -2941,7 +3388,19 @@
29413388 Often requested in some form (#6962, #5219, #3290, #4627, #5054, #3878, #2881, #1506, #1216, #968),
29423389 and useful for interactive completion/suggestions popups (#2057, #718)
29433390
3391+Docking+Viewports Branch:
29443392
3393+- Added ImGuiWindowClass::FocusRouteParentWindowId as a way to connect the focus route between
3394+ a tool window to a parent document window, so that Shortcuts in the documents are routed when the
3395+ tool is focused (regardless of whether the tool is docked or in a floating viewport, etc.) (#6798)
3396+- Added ImGuiDockNodeFlags_DockedWindowsInFocusRoute to automatically make a dockspace connect
3397+ the focus route of its docked window. This is provided a convenience in case you have windows
3398+ where a connection is not explicit. (#6798)
3399+- Viewports: Fixed moving accross monitors when io.ConfigWindowsMoveFromTitleBarOnly is set. (#7299, #3071)
3400+- Backends: OSX: Fixed not submitting Monitors info when viewports are not enabled, leading to
3401+ missing e.g. DpiScale info. (#7257) [@actboy168]
3402+
3403+
29453404 -----------------------------------------------------------------------
29463405 VERSION 1.90.1 (Released 2024-01-10)
29473406 -----------------------------------------------------------------------
@@ -3045,7 +3504,16 @@
30453504 (#6751) [@Traveller23, @ypujante]
30463505 - Examples: SDL3: Minor fixes following recent SDL3 in-progress development.
30473506
3507+Docking+Viewports Branch:
30483508
3509+- Windows: Fixed ImGuiCol_TitleBg/Active alpha being used for viewport-owned windows. (#7181) [@PathogenDavid]
3510+- Backends: DX12: Changed swapchain scaling mode to DXGI_SCALING_NONE to reduce artifacts as
3511+ queued frames aren't synchronized with platform window resizes. (#7152, #7153) [@SuperWangKai]
3512+- Backends: OSX: Fixed monitor and window position by correctly transforming Y origin on multi-viewports
3513+ multi-monitor setups. (#7028, #7101, #6009, #6432) [@dmirty-kuzmenko, @734vin]
3514+- Backends: OSX: Fixed IME position in multi-monitor multi-viewports setups. (#7028) [@734vin]
3515+
3516+
30493517 -----------------------------------------------------------------------
30503518 VERSION 1.90.0 (Released 2023-11-15)
30513519 -----------------------------------------------------------------------
@@ -3239,6 +3707,8 @@
32393707 Fixed leaks, and added ImGui_ImplVulkan_DestroyFontsTexture() (probably no need to call this directly).
32403708 (#6943, #6715, #6327, #3743, #4618)
32413709 [@helynranta, @thomasherzog, @guybrush77, @albin-johansson, @MiroKaku, @benbatya-fb, @ocornut]
3710+- Backends: Vulkan: use specified ColorAttachmentFormat when creating a secondary window when enabling
3711+ UseDynamicRendering option. (#6999, #5446, #5037) [@raaaviol]
32423712 - Backends: GLFW: Clear emscripten's MouseWheel callback before shutdown. (#6790, #6096, #4019) [@halx99]
32433713 - Backends: GLFW: Added support for F13 to F24 function keys. (#6891)
32443714 - Backends: SDL2, SDL3: Added support for F13 to F24 function keys, AppBack, AppForward. (#6891)
@@ -3256,7 +3726,32 @@
32563726 - Examples: GLFW+Vulkan, SDL+Vulkan: Simplified and removed code due to backend improvements.
32573727 - Internals: Renamed ImFloor() to ImTrunc(). Renamed ImFloorSigned() to ImFloor(). (#6861)
32583728
3729+Docking+Viewports Branch:
32593730
3731+- Viewports: Fixed window inner clipping rectangle off by one when window is located on a monitor
3732+ with negative coordinates. While it is expected that other small issues with arise from this
3733+ situation, at the moment we are fixing the most noticeable one. (#6861, #2884) [@Vuhdo, @alektron]
3734+- Docking: revised undocking to reduce accidental whole-node undocking:
3735+ - cannot undock a whole node by dragging from empty space in tab-bar.
3736+ - can undock whole node by dragging from window/collapse menu button.
3737+ - can undock single window by dragging from its tab.
3738+ - can still move (but not undock) whole node or whole hierarchy when node is part of a
3739+ floating hierarchy.
3740+ - added tooltip when hovering the collapse/window menu button, to faciliate understanding
3741+ that whole dock node may be undocked or grabbed from here.
3742+- Docking: Fixed an issue leading to incorrect restoration of selected tab in dock nodes that
3743+ don't carry the currently focused window. (#2304)
3744+- Docking: added ImGuiDockNodeFlags_NoUndocking. (#2999, #6823, #6780, #3492)
3745+- Docking: renamed ImGuiDockNodeFlags_NoSplit to ImGuiDockNodeFlags_NoDockingSplit.
3746+- Docking: renamed ImGuiDockNodeFlags_NoDockingInCentralNode to ImGuiDockNodeFlags_NoDockingOverCentralNode.
3747+- Docking: Internals: renamed ImGuiDockNodeFlags_NoDockingSplitMe to ImGuiDockNodeFlags_NoDockingSplit.
3748+- Docking: Fixed a bug where ClassId compare tests (when using SetNextWindowClass) on success would
3749+ prevent further filter from running, namely the one that prevent docking over a popup.
3750+- Backends: GLFW: Fixed an assertion in situation where the WndProc handler is different between
3751+ main and secondary viewport (may happen due to third-party hooks). (#6889)
3752+- Backends: DX9: Fixed incorrect assert triggering on reopening session with minimized windows. (#3424)
3753+
3754+
32603755 -----------------------------------------------------------------------
32613756 VERSION 1.89.9 (Released 2023-09-04)
32623757 -----------------------------------------------------------------------
@@ -3313,7 +3808,12 @@
33133808 - Examples: Emscripten+WebGPU: Fixed WGPUInstance creation process + use preferred
33143809 framebuffer format. (#6640, #6748) [@smileorigin]
33153810
3811+Docking+Viewports Branch:
33163812
3813+- Docking: when io.ConfigDockingWithShift is enabled, staying stationary while moving
3814+ a window displays an help tooltip to increase affordance. (#6709, #4643)
3815+
3816+
33173817 -----------------------------------------------------------------------
33183818 VERSION 1.89.8 (Released 2023-08-01)
33193819 -----------------------------------------------------------------------
@@ -3381,7 +3881,17 @@
33813881 - Examples: Vulkan: Creating minimal descriptor pools to fit only what is needed by
33823882 example. (#6642) [@SaschaWillem]
33833883
3884+Docking+Viewports Branch:
33843885
3886+- Docking, Style: resizing separators use same colors as window borders (ImGuiCol_Border)
3887+ for consistency. With default styles it doesn't make a big difference. (#2522) [@rmitton]
3888+ In the future if we promote using thick value for inner/outer docking padding we may
3889+ need to introduce new colors for it.
3890+- Docking: added style.DockingSeparatorSize, ImGuiStyleVar_DockingSeparatorSize. Now
3891+ also scaled by style.ScaleAllSizes(). (#3481, #4721, #2522) [@PossiblyAShrub, @wobbier]
3892+- Docking: fixed rendering of docked-window scrollbar above outer border. (#2522)
3893+
3894+
33853895 -----------------------------------------------------------------------
33863896 VERSION 1.89.7 (Released 2023-07-04)
33873897 -----------------------------------------------------------------------
@@ -3476,7 +3986,24 @@
34763986 - Examples: Win32+OpenGL3: Changed DefWindowProc() to DefWindowProcW() to match other examples
34773987 and support the example app being compiled without UNICODE. (#6516, #5725, #5961, #5975) [@yenixing]
34783988
3989+Docking+Viewports Branch:
34793990
3991+- Viewports+Docking: Fixed extraneous viewport+platform-window recreation in various
3992+ combination of showing or hiding windows, docking with/without split, undocking.
3993+ While with some backends and without OS decorations, some extraneous window recreation
3994+ were visibly not noticeable, they would typically become noticeable when enabling
3995+ OS decorations on those windows (e.g. Windows title bar fade-in/animation).
3996+- Viewports: Closing a viewport via OS/platform means (e.g. OS close button or task-bar menu),
3997+ mark all windows in this viewport as closed.
3998+- Docking: Fixed one-frame flickering on reappearing windows binding to a dock node
3999+ where a later-submitted window was already bound.
4000+- Docking: Fixed dragging from title-bar empty space (regression from 1.88 related to
4001+ keeping ID alive when calling low-level ButtonBehavior() directly). (#5181, #2645)
4002+- Docking: [Internal] DockBuilderDockWindow() API calls don't clear docking order
4003+ if the target node is same as existing one.
4004+- Backends: Win32: Added support for changing ParentViewportID after viewport creation.
4005+
4006+
34804007 -----------------------------------------------------------------------
34814008 VERSION 1.89.6 (Released 2023-05-31)
34824009 -----------------------------------------------------------------------
@@ -3545,7 +4072,24 @@
35454072 - Examples: Added SDL3+SDL_Renderer example. (#6286)
35464073 - Examples: Updated all Visual Studio projects and batches to use /utf-8 argument.
35474074
4075+Docking+Viewports Branch:
35484076
4077+- Viewports: Fixed platform-side focus (e.g. Alt+Tab) from leading to accidental
4078+ closure of Modal windows. Regression from 1.89.5. (#6357, #6299)
4079+- Viewports: Fixed loss of imgui-side focus when dragging a secondary viewport back in
4080+ main viewport, due to platform-side handling changes. Regression from 1.89.5 (#6299)
4081+- Viewports: Avoid applying imgui-side focus when focus change is due to a viewport
4082+ destruction. Fixes erroneous popup closure on closing a previous popup. (#6462, #6299)
4083+- Viewports: Added void* ImGuiPlatformMonitor::PlatformHandle field (backend-dependant),
4084+ for usage by user code.
4085+- Backends: GLFW: Preserve monitor list when there are no monitor, may briefly
4086+ happen when recovering from macOS sleeping mode. (#5683) [@Guistac]
4087+- Backends: SDL2: Update monitor list when receiving a display event. (#6348)
4088+ Note however that SDL2 currently doesn't have an event for a DPI/Scaling change,
4089+ so monitor data won't be updated in this situation.
4090+- Backends: SDL3: Update monitor list when receiving a display event. (#6348)
4091+
4092+
35494093 -----------------------------------------------------------------------
35504094 VERSION 1.89.5 (Released 2023-04-13)
35514095 -----------------------------------------------------------------------
@@ -3602,7 +4146,6 @@
36024146 is to other IME function such as SDL_SetTextInputRect(). (#6306, #6071, #1953)
36034147 - Backends: GLFW: Added support on Win32 only for io.AddMouseSourceEvent() to discriminate
36044148 Mouse/TouchScreen/Pen. (#2334, #2702)
3605-- Backends: GLFW: Fixed key modifiers handling on secondary viewports. (#6248, #6034) [@aiekick]
36064149 - Backends: Android: Added support for io.AddMouseSourceEvent() to discriminate Mouse/TouchScreen/Pen.
36074150 (#6315) [@PathogenDavid]
36084151 - Backends: OSX: Added support for io.AddMouseSourceEvent() to discriminate Mouse/Pen.
@@ -3618,7 +4161,17 @@
36184161 - TestSuite: Added variety of new regression tests and improved/amended existing ones
36194162 in imgui_test_engine/ repo. [@PathogenDavid, @ocornut]
36204163
4164+Docking+Viewports Branch:
36214165
4166+- Viewports: Setting focus from Platform/OS (e.g. via decoration, or Alt-Tab) sets corresponding
4167+ focus at Dear ImGui level (generally last focused window in the viewport). (#6299)
4168+- Docking: Fixed using GetItemXXX() or IsItemXXX() functions after a DockSpace(). (#6217)
4169+- Backends: GLFW: Fixed key modifiers handling on secondary viewports. (#6248, #6034) [@aiekick]
4170+- Backends: GLFW: Fixed Emscripten erroneously enabling multi-viewport support, leading to assert. (#5683)
4171+- Backends: SDL2/SDL3: Fixed IME text input rectangle position with viewports. (#6071, #1953)
4172+- Backends: SDL3: Fixed for compilation with multi-viewports. (#6255) [@P3RK4N]
4173+
4174+
36224175 -----------------------------------------------------------------------
36234176 VERSION 1.89.4 (Released 2023-03-14)
36244177 -----------------------------------------------------------------------
@@ -3692,7 +4245,6 @@
36924245 and ImGuiConfigFlags_NavEnableGamepad by default. (#787)
36934246 - Internals: Misc tweaks to facilitate applying an explicit-context patch. (#5856) [@Dragnalith]
36944247
3695-
36964248 -----------------------------------------------------------------------
36974249 VERSION 1.89.3 (Released 2023-02-14)
36984250 -----------------------------------------------------------------------
@@ -3793,7 +4345,11 @@
37934345 - Examples: SDL2+SDL_Renderer: Added call to SDL_RenderSetScale() to fix display on a
37944346 Retina display (albeit lower-res as our other unmodified examples). (#6121, #6065, #5931).
37954347
4348+Docking+Viewports Branch:
37964349
4350+- Backends: GLFW: Handle unsupported glfwGetVideoMode() for Emscripten. (#6096)
4351+
4352+
37974353 -----------------------------------------------------------------------
37984354 VERSION 1.89.2 (Released 2023-01-05)
37994355 -----------------------------------------------------------------------
@@ -3843,7 +4399,18 @@
38434399 - Backends: Vulkan: Fixed sampler passed to ImGui_ImplVulkan_AddTexture() not being honored as we were using
38444400 an immutable sampler. (#5502, #6001, #914) [@martin-ejdestig, @rytisss]
38454401
4402+Docking+Viewports Branch:
38464403
4404+- Docking: Internals: fixed DockBuilderCopyDockSpace() crashing when windows not in the
4405+ remapping list are docked on the left or top side of a split. (#6035)
4406+- Docking: fixed DockSpace() with ImGuiDockNodeFlags_KeepAliveOnly marking current window
4407+ as written to, even if it doesn't technically submit an item. This allow using KeepAliveOnly
4408+ from any window location. (#6037)
4409+- Backends: OSX: fixed typo in ImGui_ImplOSX_GetWindowSize that would cause issues when resiing
4410+ from OS decorations, if they are enabled on secondary viewports. (#6009) [@sivu]
4411+- Backends: Metal: fixed secondary viewport rendering. (#6015) [@dmirty-kuzmenko]
4412+
4413+
38474414 -----------------------------------------------------------------------
38484415 VERSION 1.89.1 (Released 2022-11-24)
38494416 -----------------------------------------------------------------------
@@ -3869,7 +4436,14 @@
38694436 - Backends: GLFW: cancel out errors emitted by glfwGetKeyName() when a name is missing. (#5908)
38704437 - Backends: WebGPU: fixed validation error with default depth buffer settings. (#5869, #5914) [@kdchambers]
38714438
4439+Docking+Viewports Branch:
38724440
4441+- Viewports: Fixed collapsed windows setting ImGuiViewportFlags_NoRendererClear without
4442+ making title bar color opaque, leading to potential texture/fb garbage being visible.
4443+ Right now as we don't fully support transparent viewports (#2766), so we turn that
4444+ 'TitleBgCollapsed' color opaque just lke we do for 'WindowBG' on uncollapsed windows.
4445+
4446+
38734447 -----------------------------------------------------------------------
38744448 VERSION 1.89 (Released 2022-11-15)
38754449 -----------------------------------------------------------------------
@@ -4060,7 +4634,24 @@
40604634 - Backends: Vulkan: Added experimental ImGui_ImplVulkan_RemoveTexture() for api symmetry. (#914, #5738).
40614635 - Backends: WebGPU: fixed rendering when a depth buffer is enabled. (#5869) [@brainlag]
40624636
4637+Docking+Viewports Branch:
40634638
4639+- Docking: Fixed incorrect focus highlight on docking node when focusing a menu. (#5702)
4640+- Docking, Nav: Fixed using gamepad/keyboard navigation not being able enter menu layer when
4641+ it only contained the standard Collapse/Close buttons and no actual menu. (#5463, #4792)
4642+- Docking: Fixed regression introduced in v1.87 when docked window content not rendered
4643+ while switching between with CTRL+Tab. [@rokups]
4644+- Docking: Fixed amending into an existing tab bar from rendering invisible items. (#5515)
4645+- Docking: Made spacing between dock nodes not a dropping gap. When hovering it only
4646+ outer-docking drop markers are visible.
4647+- Docking+Viewports: Fixed undocking window node causing parent viewports to become unresponsive
4648+ in certain situation (e.g. hidden tab bar). (#5503) [@rokups]
4649+- Backends: SDL: Fixed building backend under non-OSX Apple targets (e.g. iPhone). (#5665)
4650+- Backends: SDL: Fixed drag'n drop crossing a viewport border losing mouse coordinates. (#5710, #5012)
4651+- Backends: GLFW: Fixed leftover static variable preventing from changing or
4652+ reinitializing backend while application is running. (#4616, #5434) [@rtoumazet]
4653+
4654+
40644655 -----------------------------------------------------------------------
40654656 VERSION 1.88 (Released 2022-06-21)
40664657 -----------------------------------------------------------------------
@@ -4194,7 +4785,27 @@
41944785 - Examples: Emscripten+WebGPU: Fix building for latest WebGPU specs. (#3632)
41954786 - Examples: OSX+Metal, OSX+OpenGL: Removed now-unnecessary calls to ImGui_ImplOSX_HandleEvent(). (#4821)
41964787
4788+Docking+Viewports Branch:
41974789
4790+- Docking: Fixed floating docked nodes not being clamped into viewport workrect to stay reachable
4791+ when io.ConfigWindowsMoveFromTitleBarOnly is true and multi-viewports are disabled. (#5044)
4792+- Docking: Fixed a regression where moving window would be interrupted after undocking a tab
4793+ when io.ConfigDockingAlwaysTabBar is true. (#5324) [@rokups]
4794+- Docking: Fixed incorrect focus highlight on docking node when focusing empty central node
4795+ or a child window which was manually injected into a dockspace window.
4796+- Docking, Modal: Fixed a crash when opening popup from a parent which is being docked on the same frame. (#5401)
4797+- Viewports: Fixed an issue where MouseViewport was lagging by a frame when using 1.87 Input Queue.
4798+ A common side-effect would be that when releasing a window drag the underlying window would highlight
4799+ for a frame. (#5837, #4921) [@cfillion]
4800+- Viewports: Fixed translating a host viewport from briefly altering the size of AlwaysAutoResize windows. (#5057)
4801+- Viewports: Fixed main viewport size not matching ImDrawData::DisplaySize for one frame during resize
4802+ when multi-viewports are disabled. (#4900)
4803+- Backends: SDL: Fixed dragging out main viewport broken on some SDL setups. (#5012) [@rokups]
4804+- Backends: OSX: Added support for multi-viewports. [@stuartcarnie, @metarutaiga] (#4821, #2778)
4805+- Backends: Metal: Added support for multi-viewports. [@stuartcarnie, @metarutaiga] (#4821, #2778)
4806+- Examples: OSX+Metal, SDL+Metal, GLFW+Metal: Added support for multi-viewports. [@rokups]
4807+
4808+
41984809 -----------------------------------------------------------------------
41994810 VERSION 1.87 (Released 2022-02-07)
42004811 -----------------------------------------------------------------------
@@ -4337,7 +4948,30 @@
43374948 - Backends: WebGPU: Fixed incorrect size parameters in wgpuRenderPassEncoderSetIndexBuffer() and
43384949 wgpuRenderPassEncoderSetVertexBuffer() calls. (#4891) [@FeepsDev]
43394950
4951+Docking+Viewports Branch:
43404952
4953+- Docking: Fixed a CTRL+TAB crash when aiming at an empty docked window. (#4792)
4954+- Docking: Tabs use their own identifier instead of the Window identifier.
4955+ (This will invalidate some stored .ini data such as last selected tab, sorry!)
4956+- Docking: Fixed size constraints not working on single window holding on a dock id (still doesn't work on docked windows).
4957+- Docking: Fixed CTRL+TAB back into a docked window not selecting menu layer when no item are on main layer.
4958+- Viewports, IO: Added io.AddMouseViewportEvent() function to queue hovered viewport change (when known by backend).
4959+- Viewports: Relaxed specs for backend supporting ImGuiBackendFlags_HasMouseHoveredViewport: it is now _optional_
4960+ for the backend to have to ignore viewports with the _NoInputs flag when call io.AddMouseViewportEvent(). It is
4961+ much better if they can (Win32 and GLFW 3.3+ backends can, SDL and GLFW 3.2 backends cannot, they are lacking data).
4962+ A concrete example is: when dragging a viewport for docking, the viewport is marked with _NoInputs to allow us
4963+ to pick the target viewports for docking. If the backend reports a viewport with _NoInputs when calling the
4964+ io.AddMouseViewportEvent() function, then Dear ImGui will revert to its flawed heuristic to find the viewport under.
4965+ By lowering those specs, we allow the SDL and more backend to support this, only relying on the heuristic in a few
4966+ drag and drop situations rather that relying on it everywhere.
4967+- Viewports: Fixed a CTRL+TAB crash with viewports enabled when the window list needs to appears in
4968+ its own viewport (regression from 1.86). (#4023, #787)
4969+- Viewports: Fixed active InputText() from preventing viewports to merge. (#4212)
4970+- Backends: SDL: Added support for ImGuiBackendFlags_HasMouseHoveredViewport now that its specs have been lowered.
4971+- (Breaking) Removed ImGuiPlatformIO::Platform_SetImeInputPos() in favor of newly standardized
4972+ io.SetPlatformImeDataFn() function. Should not affect more than default backends.
4973+
4974+
43414975 -----------------------------------------------------------------------
43424976 VERSION 1.86 (Released 2021-12-22)
43434977 -----------------------------------------------------------------------
@@ -4435,7 +5069,25 @@
44355069 wgpuRenderPassEncoderSetIndexBuffer() functions as validation layers appears to not do what the
44365070 in-flux specs says. (#4766) [@meshula]
44375071
5072+Docking+Viewports Branch:
44385073
5074+- Docking: Revert removal of io.ConfigDockingWithShift config option (removed in 1.83). (#4643)
5075+- Docking: Fixed a bug undocking windows docked into a non-visible or _KeepAliveOnly dockspace
5076+ when unrelated windows submitted before the dockspace have dynamic visibility. (#4757)
5077+- Docking, Style: Docked windows honor ImGuiCol_WindowBg. (#2700, #2539)
5078+- Docking, Style: Docked windows honor display their border properly. (#2522)
5079+- Docking: Fixed incorrectly rounded tab bars for dock node that are not at the top of their dock tree.
5080+- Docking: Fixed single-frame node pos/size inconsistencies when window stop or start being submitted.
5081+- Docking: Prevent docking any window created above a popup/modal. (#4317)
5082+- Viewports: Made it possible to explicitly assign ImGuiWindowClass::ParentViewportId to 0 in order
5083+ to ensure a window is not parented. Previously this would use the global default (which might be 0,
5084+ but not always as it would depend on io.ConfigViewportsNoDefaultParent). (#3152, #2871)
5085+- Viewports: Fixed tooltip in own viewport over modal from being incorrectly dimmed. (#4729)
5086+- Viewports: Fixed CTRL+TAB highlight outline on docked windows not always fitting in host viewport.
5087+- Backends: Made it possible to shutdown default Platform Backends before the Renderer backends. (#4656)
5088+- Disabled: Fixed nested BeginDisabled()/EndDisabled() bug in Docking branch due to bad merge. (#4655, #4452, #4453, #4462)
5089+
5090+
44395091 -----------------------------------------------------------------------
44405092 VERSION 1.85 (Released 2021-10-12)
44415093 -----------------------------------------------------------------------
@@ -4453,6 +5105,10 @@
44535105 Can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead but it's not
44545106 very useful in practice, and the only use of it in the demo was illfit.
44555107 Using 'GetContentRegionAvail().x' is generally a better choice.
5108+- (Docking branch) IsWindowFocused() and IsWindowHovered() with only the _ChildWindows flag
5109+ and without the _RootWindow flag used to leak docking hierarchy, so a docked window would
5110+ return as the child of the window hosting the dockspace. This was inconsistent and incorrect
5111+ with other behaviors so we fixed it. Added a new _DockHierarchy flag to opt-in this behavior.
44565112
44575113 Other Changes:
44585114
@@ -4526,7 +5182,30 @@
45265182 - Backends: All renderers: Normalize clipping rect handling across backends. (#4464)
45275183 - Examples: Added SDL + SDL_Renderer example in "examples/example_sdl_sdlrenderer/" folder. (#3926) [@1bsyl]
45285184
5185+Docking+Viewports Branch:
45295186
5187+- IsWindowFocused: Fixed using ImGuiFocusedFlags_ChildWindows (without _RootWindow) from leaking the
5188+ docking hierarchy. Added ImGuiFocusedFlags_DockHierarchy flag to consider docking hierarchy in the test.
5189+- IsWindowHovered: Fixed using ImGuiHoveredFlags_ChildWindows (without _RootWindow) from leaking the
5190+ docking hierarchy. Added ImGuiHoveredFlags_DockHierarchy flag to consider docking hierarchy in the test.
5191+- Nav: Fixed an issue with losing focus on docked windows when pressing Alt while keyboard navigation
5192+ is disabled. (#4547, #4439) [@PathogenDavid]
5193+- Docking: Fixed IsItemHovered() and functions depending on it (e.g. BeginPopupContextItem()) when
5194+ called after Begin() on a docked window (broken 2021/03/04). (#3851)
5195+- Docking: Improved resizing system so that non-central zone are better at keeping their fixed size.
5196+ The algorithm is still not handling the allocation of size ideally for nested sibling, but it got better.
5197+- Docking: Fixed settings load issue when mouse wheeling. (#4310)
5198+- Docking: Fixed manually created floating node with a central node from not hiding when windows are gone.
5199+- Docking + Drag and Drop: Fixed using BeginDragDropSource() or BeginDragDropTarget() inside a Begin()
5200+ that returned false because the window is docked. (#4515)
5201+- Viewports: Fixed a crash while a window owning its viewport disappear while being dragged.
5202+ It would manifest when e.g. reconfiguring dock nodes while dragging.
5203+- Viewports: Fixed unnecessary creation of temporary viewports when multiple docked windows
5204+ got reassigned to a new node (created mid-frame) which already has a HostWindow.
5205+- Viewports: Fixed window with viewport ini data immediately merged into a host viewport from
5206+ leaving a temporary viewport alive for a frame (would leak into backend).
5207+
5208+
45305209 -----------------------------------------------------------------------
45315210 VERSION 1.84.2 (Released 2021-08-23)
45325211 -----------------------------------------------------------------------
@@ -4662,7 +5341,26 @@
46625341 - Examples: Updated all .vcxproj to VS2015 (toolset v140) to facilitate usage with vcpkg.
46635342 - Examples: SDL2: Accommodate for vcpkg install having headers in SDL2/SDL.h vs SDL.h.
46645343
5344+Docking+Viewports Branch:
46655345
5346+- Docking: Clicking on the right-most close button of a docking node closes all windows. (#4186)
5347+- Docking: Fix IsWindowAppearing() and ImGuiCond_Appearing on docked windows. (#4177, #3982, #1497, #1061)
5348+- Docking: Fix crash using DockBuilderRemoveNode() in some situations. (#3111, #3179, #3203, #4295) [@hsimyu]
5349+- Docking: Fix crash when a dock node gets re-qualified as dockspace>floating>dockspace, which tends to happen
5350+ when incorrectly calling DockBuilderAddNode() without ImGuiDockNodeFlags_Dockspace and using it as a Dockspace
5351+ on the next frame after the floating window hosting the node has been automatically created. (#3203, #4295)
5352+- Docking: Reworked node flags saving/inheritance so that flags enforced by docked windows via the
5353+ DockNodeFlagsOverrideSet mechanism are are not left in empty dockspace nodes once the windows gets undocked.
5354+ (#4292, #3834, #3633, #3521, #3492, #3335, #2999, #2648)
5355+- Docking: (Internal/Experimental) Removed DockNodeFlagsOverrideClear flags from ImGuiWindowClass as
5356+ it is ambiguous how to apply them and we haven't got a use out of them yet.
5357+- Docking: Fixed ImGuiWindowFlags_UnsavedDocument clipping label in docked windows when there are
5358+ no close button. (#5745)
5359+- Viewports: Fix popup/tooltip created without a parent window from being given a ParentViewportId value
5360+ from the implicit/fallback window. (#4236, #2409)
5361+- Backends: Vulkan: Fix the use of the incorrect fence for secondary viewports. (#4208) [@FunMiles]
5362+
5363+
46665364 -----------------------------------------------------------------------
46675365 VERSION 1.83 (Released 2021-05-24)
46685366 -----------------------------------------------------------------------
@@ -4746,7 +5444,23 @@
47465444 - Docs: Improvements to description of using colored glyphs/emojis. (#4169, #3369)
47475445 - Docs: Improvements to minor mistakes in documentation comments (#3923) [@ANF-Studios]
47485446
5447+Docking+Viewports Branch:
47495448
5449+- [Breaking] Removed io.ConfigDockingWithShift config option. Behavior always equivalent to having the
5450+ option set to false (dock/undock by default, hold shift to avoid docking). (#2109)
5451+- Docking: DockSpace() returns its node ID.
5452+- Docking: Dockspace() never draws a background. (#3924)
5453+- Docking: Undocking nodes/windows covering most of the monitor max their size down to 90% to ease manipulations.
5454+- Docking: Docking node tab bar honors ItemInnerSpacing.x before first tab. (#4130)
5455+- Docking: Tweak rendering and alignment of dock node menu marker. (#4130)
5456+- Docking: Fixed restoring of tab order within a dockspace or a split node.
5457+- Docking: Fixed reappearing docked windows with no close button showing a tab with extraneous space for one frame.
5458+- Docking: Fixed multiple simultaneously reappearing window from appearing undocked for one frame.
5459+- Viewports: Hotfix for crash in monitor array access, caused by 4b9bc4902. (#3967)
5460+- Backends, Viewports: GLFW: Add a workaround for stuck keys after closing a GLFW window (#3837).
5461+- Backends, Viewports: Vulkan: Rebuild swapchain on VK_SUBOPTIMAL_KHR. (#3881)
5462+
5463+
47505464 -----------------------------------------------------------------------
47515465 VERSION 1.82 (Released 2021-02-15)
47525466 -----------------------------------------------------------------------
@@ -4841,7 +5555,14 @@
48415555 scheduled builds builds are not required. [@rokups]
48425556 - Log/Capture: Added LogTextV, a va_list variant of LogText. [@PathogenDavid]
48435557
5558+Docking+Viewports Branch:
48445559
5560+- Viewports: Fix setting of ImGuiViewportFlags_NoRendererClear. (#3213)
5561+- Viewports: Added GetViewportPlatformMonitor() with a safety net to keep code portable.
5562+- Viewports, Backends: SDL: Fix missing ImGuiBackendFlags_HasSetMousePos flag in docking branch.
5563+- Viewports, Backends: GLFW: Fix application of WantSetMousePos. (#1542, #787)
5564+
5565+
48455566 -----------------------------------------------------------------------
48465567 VERSION 1.81 (Released 2021-02-10)
48475568 -----------------------------------------------------------------------
@@ -4922,7 +5643,18 @@
49225643 - Examples: WebGPU: Added Emscripten+WebGPU example. (#3632) [@bfierz]
49235644 - Backends: GLFW: Added ImGui_ImplGlfw_InitForOther() initialization call to use with non OpenGL API. (#3632)
49245645
5646+Docking+Viewports Branch:
49255647
5648+- Docking: Fix losing docking information on closed windows for which the hosting node was split. (#3716) [@GamingMinds-DanielC]
5649+- Docking: Fix gap in hit test hole when using ImGuiDockNodeFlags_PassthruCentralNode touching the edge of a viewport. (#3733)
5650+- Viewports: (Breaking) removed ImGuiPlatformIO::MainViewport which is now pretty much unused and duplicate
5651+ (and misleading as we will evolve the concept).
5652+- Viewports: (Breaking) turned ImGuiViewport::GetWorkPos(), ImGuiViewport::GetWorkSize() into regular fields
5653+ (WorkPos, WorkSize) before exposing in master branch.
5654+- Viewports: Fix issue inferring viewport z-order when new popups gets created. (#3734) + Metrics updates.
5655+- Viewports, Backends: Vulkan: handle VK_ERROR_OUT_OF_DATE_KHR when resizing secondary viewport (#3766, #3758)
5656+
5657+
49265658 -----------------------------------------------------------------------
49275659 VERSION 1.80 (Released 2021-01-21)
49285660 -----------------------------------------------------------------------
@@ -5041,7 +5773,15 @@
50415773 - Docs: Split examples/README.txt into docs/BACKENDS.md and docs/EXAMPLES.md, and improved them.
50425774 - Docs: Consistently renamed all occurrences of "binding" and "back-end" to "backend" in comments and docs.
50435775
5776+Docking+Viewports Branch:
50445777
5778+- Docking: Docked windows honor change of tab and text colors. (#2771)
5779+- Docking: Support for appending into existing tab-bar made to work with Docking + internal helper DockNodeBeginAmendTabBar().
5780+- Docking: Added experimental TabItemFlagsOverrideSet to ImGuiWindowClass.
5781+- Viewports: Fixed incorrect whitening of popups above a modal if both use their own viewport.
5782+- Viewports: Backends: Vulkan: Fixed build, removed extraneous pipeline creation. (#3459, #3579)
5783+
5784+
50455785 -----------------------------------------------------------------------
50465786 VERSION 1.79 (Released 2020-10-08)
50475787 -----------------------------------------------------------------------
@@ -5135,7 +5875,22 @@
51355875 - Examples: DX12: Added '#define ImTextureID ImU64' in project and build files to also allow building
51365876 on 32-bit systems. Added project to default Visual Studio solution file. (#301)
51375877
5878+Docking+Viewports Branch:
51385879
5880+- Docking: DockSpace() emits ItemSize() properly (useful when not filling all space).
5881+- Docking: Fixed docking while hovering a child window. (#3420) broken by 85a661d. Improve metrics debugging.
5882+- Docking: Fix honoring payload filter with overlapping nodes (we incorrectly over-relied on g.HoveredDockNode
5883+ when making change for #3398).
5884+- Docking: Fix handling of WindowMenuButtonPosition == ImGuiDir_None in Docking Nodes. (#3499)
5885+- Viewports: Fixed a rare edge-case if the window targeted by CTRL+Tab stops being rendered.
5886+- Viewports, Backends: DX12: Make secondary viewport format match main viewport one (#3462) {@BeastLe9enD]
5887+- Viewports: Backends: Vulkan: Removed unused shader code. Fix leaks. Avoid unnecessary pipeline creation for main
5888+ viewport. (#3459) + Add ImGui_ImplVulkanH_CreateWindowSwapChain in ImGui_ImplVulkanH_CreateOrResizeWindow().
5889+- Viewports: Backends: DirectX9: Recover from D3DERR_DEVICELOST on secondary viewports. (#3424)
5890+- Viewports, Backends: Win32: Fix toggling of ImGuiViewportFlags_TopMost (#3477) [@Kodokuna]
5891+- Viewports: Backends: GLFW: Workaround for cases where glfwGetMonitorWorkarea fails (#3457) [@dougbinks]
5892+
5893+
51395894 -----------------------------------------------------------------------
51405895 VERSION 1.78 (Released 2020-08-18)
51415896 -----------------------------------------------------------------------
@@ -5236,7 +5991,24 @@
52365991 - Examples: Vulkan: Fixed GLFW+Vulkan and SDL+Vulkan clear color not being set. (#3390) [@RoryO]
52375992 - CI: Emscripten has stopped their support for their fastcomp backend, switching to latest sdk [@Xipiryon]
52385993
5994+Docking+Viewports Branch:
52395995
5996+- Docking: Made DockBuilderAddNode() automatically call DockBuilderRemoveNode(). (#3399, #2109)
5997+- Docking: Storing HoveredDockNode in context which can be useful for easily detecting e.g. hovering an
5998+ empty node. (#3398)
5999+- Docking: Fixed docking overlay bits appearing at (0,0), because of 43bd80a. Most typically noticeable
6000+ when disabling multi-viewport.
6001+- Docking: Workaround recovery for node created without the _DockSpace flags later becoming a DockSpace. (#3340)
6002+- Docking: Rework size allocations to recover when there's no enough room for nodes + do not hold on
6003+ _WantLockSizeOnce forever. (#3328)
6004+- Docking: Rework size allocation to allow user code to override node sizes. Not all edge cases will be
6005+ properly handled but this is a step toward toolbar emitting size constraints.
6006+- Docking: Added experimental flags to perform more docking filtering and disable resize per axis.
6007+ Designed for toolbar patterns.
6008+- Viewports, Backends, GLFW: Use GLFW_MOUSE_PASSTHROUGH when available.
6009+- Viewports, Backends: DX12: Fixed issue on shutdown when viewports are disabled. (#3347)
6010+
6011+
52406012 -----------------------------------------------------------------------
52416013 VERSION 1.77 (Released 2020-06-29)
52426014 -----------------------------------------------------------------------
@@ -5327,7 +6099,18 @@
53276099 - Examples: Apple: Fixed example_apple_metal and example_apple_opengl2 using imgui_impl_osx.mm
53286100 not forwarding right and center mouse clicks. (#3260) [@nburrus]
53296101
6102+Docking+Viewports Branch:
53306103
6104+- Viewports: Don't set ImGuiViewportFlags_NoRendererClear when ImGuiWindowFlags_NoBackground is set. (#3213)
6105+- Viewports: Report minimized viewports as zero DisplaySize to be consistent with main branch. (#1542)
6106+- Docking, Settings: Allow reload of settings data at runtime. (#2573)
6107+- Backends, GLFW: Fix windows resizing incorrectly on Linux due to GLFW firing window positioning
6108+ callbacks on next frame after window is resized manually. (#2117)
6109+- Backends: DX12: Fix OBJECT_DELETED_WHILE_STILL_IN_USE on viewport resizing. (#3210)
6110+- Backends: DX12: Fix for crash caused by early resource release. (#3121)
6111+- Backends, Win32: Request monitor update when DPI awareness is enabled to make sure they have the correct DPI settings.
6112+
6113+
53316114 -----------------------------------------------------------------------
53326115 VERSION 1.76 (Released 2020-04-12)
53336116 -----------------------------------------------------------------------
@@ -5399,7 +6182,21 @@
53996182 - Examples: SDL+DX11: Fixed resizing main window. (#3057) [@joeslay]
54006183 - Examples: Added SDL+Metal example application. (#3017) [@coding-jackalope]
54016184
6185+Docking+Viewports Branch:
54026186
6187+- Docking: Fixed assert preventing dockspace from being created instead a hidden tab. (#3101)
6188+- Viewports: Fixed secondary viewports accidentally merging into a minimized host viewport. (#3118)
6189+- Viewports, Docking: Added per-viewport work area system for e.g. menu-bars. Fixed DockspaceOverViewport()
6190+ and demo code (overlay etc) accordingly. (#3035, #2889, #2474, #1542, #2109)
6191+- Viewports: Improve menu positioning in multi-monitor setups. [@rokups]
6192+- Viewports: Software mouse cursor is also scaled by current DpiScale. (amend #939)
6193+- Viewports: Avoid manually clipping resize grips and borders, which messes up with automation ability
6194+ to locate those items. Also simpler and more standard.
6195+- Viewports: Fix for UWP in the imgui_impl_win32.cpp IME handler. (#2895, #2892).
6196+- Viewports: Bunch of extra of comments to facilitate setting up multi-viewports.
6197+- Viewports, GLFW: Avoid using window positioning workaround for GLFW 3.3+ versions that have it fixed.
6198+
6199+
54036200 -----------------------------------------------------------------------
54046201 VERSION 1.75 (Released 2020-02-10)
54056202 -----------------------------------------------------------------------
@@ -5497,7 +6294,22 @@
54976294 - Examples: Metal: Wrapped main loop in @autoreleasepool block to ensure allocations get freed
54986295 even if underlying system event loop gets paused due to app nap. (#2910, #2917) [@bear24rw]
54996296
6297+Docking+Viewports Branch:
55006298
6299+- Docking + Nav: Fixed messed up Ctrl+Tab order with docked windows.
6300+- Docking + Nav: Fixed failing to restore NavId when refocusing a child within a docked window.
6301+- Docking + Nav: Fixed failing to restore NavId when refocusing due to missing nav window (when
6302+ it stops being submitted).
6303+- Docking: Fixed a bug where the tab bar of a hidden dockspace would keep requesting focus. (#2960)
6304+- Docking: Added experimental DockNodeFlagsOverrideSet/DockNodeFlagsOverrideClear flags in ImGuiWindowClass
6305+ (currently experimenting with toolbar idioms).
6306+- Viewports: Fix resizing viewport-owning windows when mouse pos is outside the InnerClipRect
6307+ (can happen with OS decoration enabled).
6308+- Viewports: Preserve last known size for minimized main viewport to be consistent with secondary viewports.
6309+- Backends: SDL: Honor NoTaskBarIcon flag under non Win32 OS. (#2117)
6310+- Backends: GLFW, SDL: Platform monitors declared properly even if multi-viewport is not enabled.
6311+
6312+
55016313 -----------------------------------------------------------------------
55026314 VERSION 1.74 (Released 2019-11-25)
55036315 -----------------------------------------------------------------------
@@ -5576,7 +6388,15 @@
55766388 - CI: Set up a bunch of continuous-integration tests using GitHub Actions. We now compile many of the example
55776389 applications on Windows, Linux, MacOS, iOS, Emscripten. Removed Travis integration. (#2865) [@rokups]
55786390
6391+Docking+Viewports Branch:
55796392
6393+- Docking: Can undock from the small triangle button. (#2109,. #2645)
6394+- Docking: Fixed node->HasCloseButton not honoring ImGuiDockNodeFlags_NoCloseButton in a floating node,
6395+ leading to empty space at the right of tab-bars with those flags. (#2109)
6396+- Docking: Made docked windows not use style.ChildRounding.
6397+- Multi-viewports: Added multi-viewport support in the DX12 back-end. (#2851) [@obfuscate]
6398+
6399+
55806400 -----------------------------------------------------------------------
55816401 VERSION 1.73 (Released 2019-09-24)
55826402 -----------------------------------------------------------------------
@@ -5638,7 +6458,29 @@
56386458 - Misc: Updated stb_rect_pack.h from 0.99 to 1.00 (fixes by @rygorous: off-by-1 bug in best-fit heuristic,
56396459 fix handling of rectangles too large to fit inside texture). (#2762) [@tido64]
56406460
6461+Docking+Viewports Branch:
56416462
6463+- Docking: Fix BeginDocked() path that creates node so that SetNextWindowDockID() doesn't immediately discard the node. (#2109)
6464+- Docking: Fix for node created at the same time as windows that are still resizing (typically with
6465+ io.ConfigDockingAlwaysTabBar) to not be zero/min sized. (#2109). The fix delays their visibility by one frame,
6466+ which is not ideal but not very problematic as the .ini data gets populated after that.
6467+- Docking: Fix a crash that could occur with a malformed ini file (DockNode Parent value pointing to a missing node).
6468+- Viewport: Fix modal/popup window being stuck in unowned hidden viewport associated to fallback window without stealing
6469+ it back. Fix modal reference viewport when opened outside of another window. (#1542)
6470+- Viewport: Modals don't need to set ImGuiViewportFlags_NoFocusOnClick, this also mitigate the issue described by #2445,
6471+ which becomes particularly bad with unfocused modal. (#1542)
6472+- Viewport: better case case where host window gets moved and resized simultaneous (toggling maximized state).
6473+ There's no perfect solution there, than using io.ConfigViewportsNoAutoMerge = false. (#1542)
6474+- Viewport, Docking: Fixed incorrect assignment of IsFallbackWindow which would tag dock node host windows created
6475+ in NewFrame() as such, messing with popup viewport inheritance.
6476+- Viewport: Fixed issue where resize grip would display as hovered while mouse is still off the OS bounds so a click
6477+ would miss it and focus the OS window behind expected one. (#1542)
6478+- Viewport: Fix to allow multiple shutdown / calls to DestroyPlatformWindows(). (#2769)
6479+- Viewport: Backends: GLFW: Fix setting window size on macOS (#2767, #2117) [@rokups]
6480+- Viewport: Backends: GLFW+Linux: Fix window having incorrect size after uncollapse. (#2756, #2117) [@rokups]
6481+- Viewport: Backends: DirectX9: Workaround for windows not refreshing when main viewport has no draw call. (#2560)
6482+
6483+
56426484 -----------------------------------------------------------------------
56436485 VERSION 1.72b (Released 2019-07-31)
56446486 -----------------------------------------------------------------------
@@ -5740,7 +6582,26 @@
57406582 (#2482, #2632) [@josiahmanson]
57416583 - Examples: Added SDL2+DirectX11 example application. (#2632, #2612, #2482) [@vincenthamm]
57426584
6585+Docking+Viewports Branch:
57436586
6587+- Docking: Making it possible to undock a node by clicking on the tab bar / title bar for the node. (#2645).
6588+- Docking: Explicitly inhibit constraint when docked for now. Fix clipping issue related to constraints. (#2690).
6589+- Docking: Fixed dragging/resizing from OS decoration not marking settings as dirty.
6590+- Docking: Renamed io.ConfigDockingTabBarOnSingleWindows to io.ConfigDockingAlwaysTabBar.
6591+ Added ImGuiWindowClass::DockingAlwaysTabBar to set on individual windows.
6592+- Docking: Perform simple check: assert if Docking or Viewport are enabled exactly on frame 1 (instead of frame 0
6593+ or later), which is a common user error leading to loss of .ini data on load.
6594+- Docking: Fix so that an appearing window making a dock node reappear won't have a zero-size on its first frame.
6595+- Docking: Fixed using ImGuiDockNodeFlags_AutoHideTabBar with io.ConfigDockingTabBarOnSingleWindows.
6596+- Docking: Added ImGuiDockNode to .natvis file.
6597+- Docking: Fixed support for large meshes in GetBackgroundDrawList(), GetForegroundDrawList(). (#2638)
6598+- Viewport: Fix monitor dpi info not being copied to main viewport when multi-viewports are not enabled. (#2621, #1676)
6599+- Viewport: Refactored ImGuiWindowClass's ViewportFlagsOverrideMask + ViewportFlagsOverrideValue into
6600+ ViewportFlagsOverrideSet + ViewportFlagsOverrideClear which appears easier to grasp. (#1542)
6601+- Viewport: Added ImGuiViewportFlags_NoAutoMerge to prevent merging into host viewport in a per-window basis
6602+ via the ImGuiWindowClass override mechanism. (#1542)
6603+
6604+
57446605 -----------------------------------------------------------------------
57456606 VERSION 1.71 (Released 2019-06-12)
57466607 -----------------------------------------------------------------------
@@ -6079,6 +6940,7 @@
60796940 - Renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete).
60806941
60816942 Other Changes:
6943+
60826944 - Added BETA api for Tab Bar/Tabs widgets: (#261, #351)
60836945 - Added BeginTabBar(), EndTabBar(), BeginTabItem(), EndTabItem(), SetTabItemClosed() API.
60846946 - Added ImGuiTabBarFlags flags for BeginTabBar().
@@ -77,6 +77,17 @@
7777 You can use the `ImFontGlyphRangesBuilder` for this purpose and rebuilding your atlas between frames when new characters are needed. This will be the biggest win!
7878 - Set `io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;` to disable rounding the texture height to the next power of two.
7979
80+### (5) Reduce texture resizes/copy on startup
81+
82+🆕 Since 1.92, the ImFontAtlas is initially created using a 512x128 texture, then grows as glyphs and fonts are used. Atlas growth leads to alloc+copy, and both the old and new sized textures are present in memory for a short time (typically one frame). If you use known fonts and want to reduce initial growth, you may set `TexMinWidth` and `TexMinHeight` during initializaton.
83+
84+```cpp
85+ImFontAtlas* atlas = io.Fonts;
86+atlas->TexMinWidth = 1024;
87+atlas->TexMinHeight = 1024;
88+atlas->AddFont(...);
89+```
90+
8091 ##### [Return to Index](#index)
8192
8293 ---------------------------------------
@@ -43,7 +43,7 @@
4343
4444 **Backends for a variety of graphics API and rendering platforms** are provided in the [backends/](https://github.com/ocornut/imgui/tree/master/backends) folder, along with example applications in the [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder. You may also create your own backend. Anywhere where you can render textured triangles, you can render Dear ImGui.
4545
46-C++20 users wishing to use a module may the use [stripe2933/imgui-module](https://github.com/stripe2933/imgui-module) third-party extension.
46+C++20 users wishing to use a module may use the [stripe2933/imgui-module](https://github.com/stripe2933/imgui-module) third-party extension.
4747
4848 See the [Getting Started & Integration](#getting-started--integration) section of this document for more details.
4949
@@ -115,7 +115,35 @@
115115 - separator: width, thickness, centering (#1643, #2657)
116116 - splitter: formalize the splitter idiom into an official api (we want to handle n-way split) (#319)
117117
118- - docking: merge docking branch (#2109)
118+ - docking: B: ordering currently held in tab bar should be implicitly held by windows themselves (also see #2304)
119+ - docking: B- tab bar: the order/focus restoring code could be part of TabBar and not DockNode? (#8)
120+ - docking: B~ rework code to be able to lazily create tab bar instance in a single place. The _Unsorted tab flag could be replacing a trailing-counter in DockNode?
121+ - docking: B~ fully track windows/settings reference in dock nodes. perhaps find a representation that allows facilitate use of dock builder functions.
122+ - docking: B~ Unreal style document system (requires low-level controls of dockspace serialization fork/copy/delete). this is mostly working but the DockBuilderXXX api are not exposed/finished.
123+ - docking: B: when docking outer, perform size locking on neighbors nodes the same way we do it with splitters, so other nodes are not resized.
124+ - docking: B~ central node resizing behavior incorrect.
125+ - docking: B: changing title font/style per-window is not supported as dock nodes are created in NewFrame.
126+ - docking: B- dock node inside its own viewports creates 1 temporary viewport per window on startup before ditching them (doesn't affect the user nor request platform windows to be created, but unnecessary)
127+ - docking: B- resize sibling locking behavior may be less desirable if we merged same-axis sibling in a same node level?
128+ - docking: B- single visible node part of a hidden split hierarchy (OnlyNodeWithWindows != NULL) should show a normal title bar (not a tab bar)
129+ - docking: B~ SetNextWindowDock() calls (with conditional) -> defer everything to DockContextUpdate (repro: Documents->[X]Windows->Dock 1 elsewhere->Click Redock All
130+ - docking: B~ tidy up tab list popup buttons features (available with manual tab-bar, see ImGuiTabBarFlags_NoTabListPopupButton code, not used by docking nodes)
131+ - docking: B- SetNextWindowDockId(0) with a second Begin() in the frame will asserts
132+ - docking: B: resize grip drawn in host window typically appears under scrollbar.
133+ - docking: B: resize grip auto-resize on multiple node hierarchy doesn't make much sense or should be improved?
134+ - docking: B- SetNextWindowFocus() doesn't seem to apply if the window is hidden this frame, need repro (#4)
135+ - docking: B- resizing a dock tree small currently has glitches (overlapping collapse and close button, etc.)
136+ - docking: B- dpi: look at interaction with the hi-dpi and multi-dpi stuff.
137+ - docking: B- tab bar: appearing on first frame with a dumb layout would do less harm that not appearing? (when behind dynamic branch) or store titles + render in EndTabBar()
138+ - docking: B- tab bar: make selected tab always shows its full title?
139+ - docking: B- hide close button on single tab bar?
140+ - docking: B- nav: design interactions so nav controls can dock/undock
141+ - docking: B- dockspace: flag to lock the dock tree and/or sizes (ImGuiDockNodeFlags_Locked?)
142+ - docking: B- reintroduce collapsing a floating dock node. also collapsing a docked dock node!
143+ - docking: B- allow dragging a non-floating dock node by clicking on the title-bar-looking section (not just the collapse/menu button)
144+ - docking: B- option to remember undocked window size? (instead of keeping their docked size) (relate to #2104)
145+ - docking: C- nav: CTRL+TAB highlighting tabs shows the mismatch between focus-stack and tab-order (not visible in VS because it doesn't highlight the tabs)
146+ - docking: C- after a dock/undock, the Scrollbar Status update in Begin() should use an updated e.g. size_y_for_scrollbars to avoid a 1 frame scrollbar flicker.
119147
120148 - tabs: "there is currently a problem because TabItem() will try to submit their own tooltip after 0.50 second, and this will have the effect of making your tooltip flicker once." -> tooltip priority work (WIP branch)
121149 - tabs: make EndTabBar fail if users doesn't respect BeginTabBar return value, for consistency/future-proofing.
@@ -271,6 +299,21 @@
271299 - nav/windowing: when CTRL+Tab/windowing is active, the HoveredWindow detection doesn't take account of the window display re-ordering.
272300 - nav/windowing: Resizing window will currently fail with certain types of resizing constraints/callback applied
273301 - focus: preserve ActiveId/focus stack state, e.g. when opening a menu and close it, previously selected InputText() focus gets restored (#622)
302+
303+ - viewport: make it possible to have no main/hosting viewport (see #8268)
304+ - viewport: We set ImGuiViewportFlags_NoFocusOnAppearing in a way that is required for GLFW/SDL binding, but could be handled better without
305+ on a custom e.g. Win32 bindings. It prevents newly dragged-out viewports from taking the focus, which makes ALT+F4 more ambiguous.
306+ - viewport: not focusing newly undocked viewport means clicking back on previous one doesn't bring OS window to front.
307+ - viewport: with platform decoration enabled, platform may force constraint (e.g. minimum size)
308+ - viewport: use getfocus/setfocus api to synchronize imgui<>platform focus better (e.g imgui-side ctrl-tab can focus os window, OS initial setup and alt-tab can focus imgui window etc.)
309+ - viewport: store per-viewport/monitor DPI in .ini file so an application reload or main window changing DPI on reload can be properly patched for.
310+ - viewport: implicit/fallback Debug window can hog a zombie viewport (harmless, noisy?) > could at least clear out the reference on a per session basis?
311+ - viewport: need to clarify how to use GetMousePos() from a user point of view.
312+ - viewport: could apply monitor boundaries to cliprect to coarse clip things out of monitor? (#8698)
313+ - platform: glfw: no support for ImGuiBackendFlags_HasMouseHoveredViewport.
314+ - platform: sdl: no support for ImGuiBackendFlags_HasMouseHoveredViewport. maybe we could use SDL_GetMouseFocus() / SDL_WINDOW_MOUSE_FOCUS if imgui could fallback on its heuristic when NoInputs is set
315+ - platform: sdl: no refresh of monitor/display (SDL doesn't seem to have an event for it).
316+ - platform: sdl: multi-viewport + minimized window seems to break mouse wheel events (at least under Win32).
274317
275318 - inputs: support track pad style scrolling & slider edit.
276319 - inputs/io: backspace and arrows in the context of a text input could use system repeat rate.
@@ -40,6 +40,7 @@
4040 ImGui::CreateContext();
4141 ImGuiIO& io = ImGui::GetIO(); (void)io;
4242 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
43+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
4344
4445 // Setup Dear ImGui style
4546 ImGui::StyleColorsDark();
@@ -7,7 +7,10 @@
77 objects = {
88
99 /* Begin PBXBuildFile section */
10+ 050450AB2768052600AB6805 /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; };
11+ 050450AD276863B000AB6805 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 050450AC276863B000AB6805 /* QuartzCore.framework */; };
1012 05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05318E0E274C397200A8DE2E /* GameController.framework */; };
13+ 05A275442773BEA20084EF39 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05A275432773BEA20084EF39 /* QuartzCore.framework */; };
1114 07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; };
1215 07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; };
1316 5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; };
@@ -33,7 +36,11 @@
3336 /* End PBXBuildFile section */
3437
3538 /* Begin PBXFileReference section */
39+ 050450AC276863B000AB6805 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
3640 05318E0E274C397200A8DE2E /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; };
41+ 05A2754027728F5B0084EF39 /* imgui_impl_metal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_impl_metal.h; path = ../../backends/imgui_impl_metal.h; sourceTree = "<group>"; };
42+ 05A2754127728F5B0084EF39 /* imgui_impl_osx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_impl_osx.h; path = ../../backends/imgui_impl_osx.h; sourceTree = "<group>"; };
43+ 05A275432773BEA20084EF39 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
3744 07A82ED62139413C0078D120 /* imgui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_internal.h; path = ../../imgui_internal.h; sourceTree = "<group>"; };
3845 07A82ED72139413C0078D120 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = ../../imgui_widgets.cpp; sourceTree = "<group>"; };
3946 5079822D257677DB0038A28D /* imgui_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = ../../imgui_tables.cpp; sourceTree = "<group>"; };
@@ -66,6 +73,7 @@
6673 isa = PBXFrameworksBuildPhase;
6774 buildActionMask = 2147483647;
6875 files = (
76+ 05A275442773BEA20084EF39 /* QuartzCore.framework in Frameworks */,
6977 8309BD8F253CCAAA0045E2A1 /* UIKit.framework in Frameworks */,
7078 83BBE9E720EB46BD00295997 /* MetalKit.framework in Frameworks */,
7179 83BBE9E520EB46B900295997 /* Metal.framework in Frameworks */,
@@ -76,6 +84,7 @@
7684 isa = PBXFrameworksBuildPhase;
7785 buildActionMask = 2147483647;
7886 files = (
87+ 050450AD276863B000AB6805 /* QuartzCore.framework in Frameworks */,
7988 8309BDC6253CCCFE0045E2A1 /* AppKit.framework in Frameworks */,
8089 83BBE9EC20EB471700295997 /* MetalKit.framework in Frameworks */,
8190 05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */,
@@ -136,6 +145,8 @@
136145 83BBE9E320EB46B800295997 /* Frameworks */ = {
137146 isa = PBXGroup;
138147 children = (
148+ 050450AC276863B000AB6805 /* QuartzCore.framework */,
149+ 05A275432773BEA20084EF39 /* QuartzCore.framework */,
139150 05318E0E274C397200A8DE2E /* GameController.framework */,
140151 8309BDC5253CCCFE0045E2A1 /* AppKit.framework */,
141152 8309BD8E253CCAAA0045E2A1 /* UIKit.framework */,
@@ -153,7 +164,9 @@
153164 isa = PBXGroup;
154165 children = (
155166 5079822D257677DB0038A28D /* imgui_tables.cpp */,
167+ 05A2754027728F5B0084EF39 /* imgui_impl_metal.h */,
156168 8309BDB5253CCC9D0045E2A1 /* imgui_impl_metal.mm */,
169+ 05A2754127728F5B0084EF39 /* imgui_impl_osx.h */,
157170 8309BDB6253CCC9D0045E2A1 /* imgui_impl_osx.mm */,
158171 83BBEA0420EB54E700295997 /* imconfig.h */,
159172 83BBEA0320EB54E700295997 /* imgui.cpp */,
@@ -285,7 +298,7 @@
285298 83BBEA0A20EB54E700295997 /* imgui.cpp in Sources */,
286299 83BBEA0820EB54E700295997 /* imgui_demo.cpp in Sources */,
287300 83BBEA0620EB54E700295997 /* imgui_draw.cpp in Sources */,
288- 5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */,
301+ 050450AB2768052600AB6805 /* imgui_tables.cpp in Sources */,
289302 07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */,
290303 8309BDA8253CCC080045E2A1 /* main.mm in Sources */,
291304 );
@@ -60,11 +60,21 @@
6060 ImGuiIO& io = ImGui::GetIO(); (void)io;
6161 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
6262 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
63+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
64+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
6365
6466 // Setup Dear ImGui style
6567 ImGui::StyleColorsDark();
6668 //ImGui::StyleColorsLight();
6769
70+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
71+ ImGuiStyle& style = ImGui::GetStyle();
72+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
73+ {
74+ style.WindowRounding = 0.0f;
75+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
76+ }
77+
6878 // Setup Renderer backend
6979 ImGui_ImplMetal_Init(_device);
7080
@@ -197,6 +207,13 @@
197207 // Present
198208 [commandBuffer presentDrawable:view.currentDrawable];
199209 [commandBuffer commit];
210+
211+ // Update and Render additional Platform Windows
212+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
213+ {
214+ ImGui::UpdatePlatformWindows();
215+ ImGui::RenderPlatformWindowsDefault();
216+ }
200217 }
201218
202219 -(void)mtkView:(MTKView*)view drawableSizeWillChange:(CGSize)size
@@ -6,6 +6,8 @@
66 // - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
77 // - Introduction, links and more at the top of imgui.cpp
88
9+// FIXME: Multi-viewports is not yet functional in this example. May need backend rework/coordination.
10+
911 #import <Cocoa/Cocoa.h>
1012 #import <OpenGL/gl.h>
1113 #import <OpenGL/glu.h>
@@ -47,11 +49,21 @@
4749 ImGuiIO& io = ImGui::GetIO(); (void)io;
4850 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
4951 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
52+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
53+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
5054
5155 // Setup Dear ImGui style
5256 ImGui::StyleColorsDark();
5357 //ImGui::StyleColorsLight();
5458
59+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
60+ ImGuiStyle& style = ImGui::GetStyle();
61+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
62+ {
63+ style.WindowRounding = 0.0f;
64+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
65+ }
66+
5567 // Setup Platform/Renderer backends
5668 ImGui_ImplOSX_Init(self);
5769 ImGui_ImplOpenGL2_Init();
@@ -137,6 +149,13 @@
137149 glClear(GL_COLOR_BUFFER_BIT);
138150
139151 ImGui_ImplOpenGL2_RenderDrawData(draw_data);
152+
153+ // Update and Render additional Platform Windows
154+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
155+ {
156+ ImGui::UpdatePlatformWindows();
157+ ImGui::RenderPlatformWindowsDefault();
158+ }
140159
141160 // Present
142161 [[self openGLContext] flushBuffer];
@@ -44,6 +44,8 @@
4444 ImGuiIO& io = ImGui::GetIO(); (void)io;
4545 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
4646 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
47+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
48+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
4749
4850 // Setup Dear ImGui style
4951 ImGui::StyleColorsDark();
@@ -53,7 +55,16 @@
5355 ImGuiStyle& style = ImGui::GetStyle();
5456 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
5557 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
58+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
59+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
5660
61+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
62+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
63+ {
64+ style.WindowRounding = 0.0f;
65+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
66+ }
67+
5768 id <MTLDevice> device = MTLCreateSystemDefaultDevice();
5869 id <MTLCommandQueue> commandQueue = [device newCommandQueue];
5970
@@ -163,6 +174,13 @@
163174 // Rendering
164175 ImGui::Render();
165176 ImGui_ImplMetal_RenderDrawData(ImGui::GetDrawData(), commandBuffer, renderEncoder);
177+
178+ // Update and Render additional Platform Windows
179+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
180+ {
181+ ImGui::UpdatePlatformWindows();
182+ ImGui::RenderPlatformWindowsDefault();
183+ }
166184
167185 [renderEncoder popDebugGroup];
168186 [renderEncoder endEncoding];
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{9CDA7840-B7A5-496D-A527-E95571496D18}</ProjectGuid>
2323 <RootNamespace>example_glfw_opengl2</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>MultiByte</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>MultiByte</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>MultiByte</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>MultiByte</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -53,6 +53,10 @@
5353 ImGuiIO& io = ImGui::GetIO(); (void)io;
5454 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
5555 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
56+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
57+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
58+ //io.ConfigViewportsNoAutoMerge = true;
59+ //io.ConfigViewportsNoTaskBarIcon = true;
5660
5761 // Setup Dear ImGui style
5862 ImGui::StyleColorsDark();
@@ -62,7 +66,16 @@
6266 ImGuiStyle& style = ImGui::GetStyle();
6367 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
6468 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
69+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
70+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
6571
72+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
73+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
74+ {
75+ style.WindowRounding = 0.0f;
76+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
77+ }
78+
6679 // Setup Platform/Renderer backends
6780 ImGui_ImplGlfw_InitForOpenGL(window, true);
6881 ImGui_ImplOpenGL2_Init();
@@ -162,6 +175,17 @@
162175 //glUseProgram(0);
163176 ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
164177 //glUseProgram(last_program);
178+
179+ // Update and Render additional Platform Windows
180+ // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
181+ // For this specific demo app we could also call glfwMakeContextCurrent(window) directly)
182+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
183+ {
184+ GLFWwindow* backup_current_context = glfwGetCurrentContext();
185+ ImGui::UpdatePlatformWindows();
186+ ImGui::RenderPlatformWindowsDefault();
187+ glfwMakeContextCurrent(backup_current_context);
188+ }
165189
166190 glfwMakeContextCurrent(window);
167191 glfwSwapBuffers(window);
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{4a1fb5ea-22f5-42a8-ab92-1d2df5d47fb9}</ProjectGuid>
2323 <RootNamespace>example_glfw_opengl3</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>MultiByte</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>MultiByte</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>MultiByte</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>MultiByte</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -84,6 +84,10 @@
8484 ImGuiIO& io = ImGui::GetIO(); (void)io;
8585 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
8686 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
87+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
88+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
89+ //io.ConfigViewportsNoAutoMerge = true;
90+ //io.ConfigViewportsNoTaskBarIcon = true;
8791
8892 // Setup Dear ImGui style
8993 ImGui::StyleColorsDark();
@@ -93,7 +97,18 @@
9397 ImGuiStyle& style = ImGui::GetStyle();
9498 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
9599 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
100+#if GLFW_VERSION_MAJOR >= 3 && GLFW_VERSION_MINOR >= 3
101+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
102+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
103+#endif
96104
105+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
106+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
107+ {
108+ style.WindowRounding = 0.0f;
109+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
110+ }
111+
97112 // Setup Platform/Renderer backends
98113 ImGui_ImplGlfw_InitForOpenGL(window, true);
99114 #ifdef __EMSCRIPTEN__
@@ -197,6 +212,17 @@
197212 glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
198213 glClear(GL_COLOR_BUFFER_BIT);
199214 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
215+
216+ // Update and Render additional Platform Windows
217+ // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
218+ // For this specific demo app we could also call glfwMakeContextCurrent(window) directly)
219+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
220+ {
221+ GLFWwindow* backup_current_context = glfwGetCurrentContext();
222+ ImGui::UpdatePlatformWindows();
223+ ImGui::RenderPlatformWindowsDefault();
224+ glfwMakeContextCurrent(backup_current_context);
225+ }
200226
201227 glfwSwapBuffers(window);
202228 }
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{57E2DF5A-6FC8-45BB-99DD-91A18C646E80}</ProjectGuid>
2323 <RootNamespace>example_glfw_vulkan</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>MultiByte</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>MultiByte</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>MultiByte</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>MultiByte</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -390,6 +390,10 @@
390390 ImGuiIO& io = ImGui::GetIO(); (void)io;
391391 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
392392 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
393+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
394+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
395+ //io.ConfigViewportsNoAutoMerge = true;
396+ //io.ConfigViewportsNoTaskBarIcon = true;
393397
394398 // Setup Dear ImGui style
395399 ImGui::StyleColorsDark();
@@ -399,7 +403,16 @@
399403 ImGuiStyle& style = ImGui::GetStyle();
400404 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
401405 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
406+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
407+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
402408
409+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
410+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
411+ {
412+ style.WindowRounding = 0.0f;
413+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
414+ }
415+
403416 // Setup Platform/Renderer backends
404417 ImGui_ImplGlfw_InitForVulkan(window, true);
405418 ImGui_ImplVulkan_InitInfo init_info = {};
@@ -513,17 +526,25 @@
513526
514527 // Rendering
515528 ImGui::Render();
516- ImDrawData* draw_data = ImGui::GetDrawData();
517- const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f);
518- if (!is_minimized)
529+ ImDrawData* main_draw_data = ImGui::GetDrawData();
530+ const bool main_is_minimized = (main_draw_data->DisplaySize.x <= 0.0f || main_draw_data->DisplaySize.y <= 0.0f);
531+ wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w;
532+ wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w;
533+ wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w;
534+ wd->ClearValue.color.float32[3] = clear_color.w;
535+ if (!main_is_minimized)
536+ FrameRender(wd, main_draw_data);
537+
538+ // Update and Render additional Platform Windows
539+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
519540 {
520- wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w;
521- wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w;
522- wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w;
523- wd->ClearValue.color.float32[3] = clear_color.w;
524- FrameRender(wd, draw_data);
525- FramePresent(wd);
541+ ImGui::UpdatePlatformWindows();
542+ ImGui::RenderPlatformWindowsDefault();
526543 }
544+
545+ // Present Main Platform Window
546+ if (!main_is_minimized)
547+ FramePresent(wd);
527548 }
528549
529550 // Cleanup
@@ -14,7 +14,7 @@
1414 # * build/example_glfw_wgpu[.exe] or build/Debug/example_glfw_wgpu[.exe]
1515
1616 # Building for desktop with WGVK (MUCH EASIER)
17-# 1. git clone https://github.com/manuel5975p/WGVK dawn
17+# 1. git clone https://github.com/manuel5975p/WGVK wgvk
1818 # 2. cmake -B build -DIMGUI_WGVK_DIR=wgvk
1919 # 3. cmake --build build
2020 # The resulting binary will be found at one of the following locations:
@@ -37,7 +37,7 @@
3737 set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE)
3838 endif()
3939
40-set(CMAKE_CXX_STANDARD 17) # Dawn requires C++17
40+set(CMAKE_CXX_STANDARD 20) # Dawn requires C++20
4141
4242 # Dear ImGui
4343 set(IMGUI_DIR ../../)
@@ -87,6 +87,7 @@
8787 ImGuiIO& io = ImGui::GetIO(); (void)io;
8888 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
8989 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
90+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
9091
9192 // Setup Dear ImGui style
9293 ImGui::StyleColorsDark();
@@ -61,6 +61,7 @@
6161 ImGui::CreateContext();
6262 ImGuiIO& io = ImGui::GetIO(); (void)io;
6363 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
64+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
6465
6566 // Setup Dear ImGui style
6667 ImGui::StyleColorsDark();
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{1A0BF63C-18EF-4BAE-A8DA-055481B11F5D}</ProjectGuid>
2323 <RootNamespace>example_win32_directx11</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>Unicode</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>Unicode</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>Unicode</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>Unicode</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -21,7 +21,7 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{9E1987E3-1F19-45CA-B9C9-D31E791836D8}</ProjectGuid>
2323 <RootNamespace>example_sdl2_directx11</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 <ProjectName>example_sdl2_directx11</ProjectName>
2626 </PropertyGroup>
2727 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@@ -29,27 +29,27 @@
2929 <ConfigurationType>Application</ConfigurationType>
3030 <UseDebugLibraries>true</UseDebugLibraries>
3131 <CharacterSet>MultiByte</CharacterSet>
32- <PlatformToolset>v143</PlatformToolset>
32+ <PlatformToolset>v141</PlatformToolset>
3333 </PropertyGroup>
3434 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3535 <ConfigurationType>Application</ConfigurationType>
3636 <UseDebugLibraries>true</UseDebugLibraries>
3737 <CharacterSet>MultiByte</CharacterSet>
38- <PlatformToolset>v143</PlatformToolset>
38+ <PlatformToolset>v141</PlatformToolset>
3939 </PropertyGroup>
4040 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4141 <ConfigurationType>Application</ConfigurationType>
4242 <UseDebugLibraries>false</UseDebugLibraries>
4343 <WholeProgramOptimization>true</WholeProgramOptimization>
4444 <CharacterSet>MultiByte</CharacterSet>
45- <PlatformToolset>v143</PlatformToolset>
45+ <PlatformToolset>v141</PlatformToolset>
4646 </PropertyGroup>
4747 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4848 <ConfigurationType>Application</ConfigurationType>
4949 <UseDebugLibraries>false</UseDebugLibraries>
5050 <WholeProgramOptimization>true</WholeProgramOptimization>
5151 <CharacterSet>MultiByte</CharacterSet>
52- <PlatformToolset>v143</PlatformToolset>
52+ <PlatformToolset>v141</PlatformToolset>
5353 </PropertyGroup>
5454 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5555 <ImportGroup Label="ExtensionSettings">
@@ -75,6 +75,10 @@
7575 ImGuiIO& io = ImGui::GetIO(); (void)io;
7676 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
7777 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
78+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
79+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
80+ //io.ConfigViewportsNoAutoMerge = true;
81+ //io.ConfigViewportsNoTaskBarIcon = true;
7882
7983 // Setup Dear ImGui style
8084 ImGui::StyleColorsDark();
@@ -84,7 +88,16 @@
8488 ImGuiStyle& style = ImGui::GetStyle();
8589 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
8690 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
91+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
92+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
8793
94+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
95+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
96+ {
97+ style.WindowRounding = 0.0f;
98+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
99+ }
100+
88101 // Setup Platform/Renderer backends
89102 ImGui_ImplSDL2_InitForD3D(window);
90103 ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
@@ -192,6 +205,13 @@
192205 g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha);
193206 ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
194207
208+ // Update and Render additional Platform Windows
209+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
210+ {
211+ ImGui::UpdatePlatformWindows();
212+ ImGui::RenderPlatformWindowsDefault();
213+ }
214+
195215 g_pSwapChain->Present(1, 0); // Present with vsync
196216 //g_pSwapChain->Present(0, 0); // Present without vsync
197217 }
@@ -238,6 +258,16 @@
238258 res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext);
239259 if (res != S_OK)
240260 return false;
261+
262+ // Disable DXGI's default Alt+Enter fullscreen behavior.
263+ // - You are free to leave this enabled, but it will not work properly with multiple viewports.
264+ // - This must be done for all windows associated to the device. Our DX11 backend does this automatically for secondary viewports that it creates.
265+ IDXGIFactory* pSwapChainFactory;
266+ if (SUCCEEDED(g_pSwapChain->GetParent(IID_PPV_ARGS(&pSwapChainFactory))))
267+ {
268+ pSwapChainFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER);
269+ pSwapChainFactory->Release();
270+ }
241271
242272 CreateRenderTarget();
243273 return true;
@@ -24,11 +24,21 @@
2424 ImGuiIO& io = ImGui::GetIO(); (void)io;
2525 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
2626 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
27+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
28+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
2729
2830 // Setup style
2931 ImGui::StyleColorsDark();
3032 //ImGui::StyleColorsLight();
3133
34+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
35+ ImGuiStyle& style = ImGui::GetStyle();
36+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
37+ {
38+ style.WindowRounding = 0.0f;
39+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
40+ }
41+
3242 // Load Fonts
3343 // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap().
3444 // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold.
@@ -169,6 +179,13 @@
169179 // Rendering
170180 ImGui::Render();
171181 ImGui_ImplMetal_RenderDrawData(ImGui::GetDrawData(), commandBuffer, renderEncoder);
182+
183+ // Update and Render additional Platform Windows
184+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
185+ {
186+ ImGui::UpdatePlatformWindows();
187+ ImGui::RenderPlatformWindowsDefault();
188+ }
172189
173190 [renderEncoder popDebugGroup];
174191 [renderEncoder endEncoding];
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{2AE17FDE-F7F3-4CAC-ADAB-0710EDA4F741}</ProjectGuid>
2323 <RootNamespace>example_sdl2_opengl2</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>MultiByte</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>MultiByte</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>MultiByte</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>MultiByte</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -64,6 +64,10 @@
6464 ImGuiIO& io = ImGui::GetIO(); (void)io;
6565 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
6666 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
67+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
68+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
69+ //io.ConfigViewportsNoAutoMerge = true;
70+ //io.ConfigViewportsNoTaskBarIcon = true;
6771
6872 // Setup Dear ImGui style
6973 ImGui::StyleColorsDark();
@@ -73,7 +77,16 @@
7377 ImGuiStyle& style = ImGui::GetStyle();
7478 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
7579 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
80+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
81+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
7682
83+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
84+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
85+ {
86+ style.WindowRounding = 0.0f;
87+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
88+ }
89+
7790 // Setup Platform/Renderer backends
7891 ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
7992 ImGui_ImplOpenGL2_Init();
@@ -174,6 +187,19 @@
174187 glClear(GL_COLOR_BUFFER_BIT);
175188 //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound
176189 ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
190+
191+ // Update and Render additional Platform Windows
192+ // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
193+ // For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly)
194+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
195+ {
196+ SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow();
197+ SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
198+ ImGui::UpdatePlatformWindows();
199+ ImGui::RenderPlatformWindowsDefault();
200+ SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
201+ }
202+
177203 SDL_GL_SwapWindow(window);
178204 }
179205
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{BBAEB705-1669-40F3-8567-04CF6A991F4C}</ProjectGuid>
2323 <RootNamespace>example_sdl2_opengl3</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>MultiByte</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>MultiByte</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>MultiByte</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>MultiByte</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -104,6 +104,10 @@
104104 ImGuiIO& io = ImGui::GetIO(); (void)io;
105105 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
106106 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
107+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
108+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
109+ //io.ConfigViewportsNoAutoMerge = true;
110+ //io.ConfigViewportsNoTaskBarIcon = true;
107111
108112 // Setup Dear ImGui style
109113 ImGui::StyleColorsDark();
@@ -113,7 +117,16 @@
113117 ImGuiStyle& style = ImGui::GetStyle();
114118 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
115119 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
120+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
121+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
116122
123+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
124+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
125+ {
126+ style.WindowRounding = 0.0f;
127+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
128+ }
129+
117130 // Setup Platform/Renderer backends
118131 ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
119132 ImGui_ImplOpenGL3_Init(glsl_version);
@@ -221,6 +234,19 @@
221234 glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
222235 glClear(GL_COLOR_BUFFER_BIT);
223236 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
237+
238+ // Update and Render additional Platform Windows
239+ // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
240+ // For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly)
241+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
242+ {
243+ SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow();
244+ SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
245+ ImGui::UpdatePlatformWindows();
246+ ImGui::RenderPlatformWindowsDefault();
247+ SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
248+ }
249+
224250 SDL_GL_SwapWindow(window);
225251 }
226252 #ifdef __EMSCRIPTEN__
@@ -21,7 +21,7 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{0C0B2BEA-311F-473C-9652-87923EF639E3}</ProjectGuid>
2323 <RootNamespace>example_sdl2_sdlrenderer2</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 <ProjectName>example_sdl2_sdlrenderer2</ProjectName>
2626 </PropertyGroup>
2727 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@@ -29,27 +29,27 @@
2929 <ConfigurationType>Application</ConfigurationType>
3030 <UseDebugLibraries>true</UseDebugLibraries>
3131 <CharacterSet>MultiByte</CharacterSet>
32- <PlatformToolset>v143</PlatformToolset>
32+ <PlatformToolset>v141</PlatformToolset>
3333 </PropertyGroup>
3434 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3535 <ConfigurationType>Application</ConfigurationType>
3636 <UseDebugLibraries>true</UseDebugLibraries>
3737 <CharacterSet>MultiByte</CharacterSet>
38- <PlatformToolset>v143</PlatformToolset>
38+ <PlatformToolset>v141</PlatformToolset>
3939 </PropertyGroup>
4040 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4141 <ConfigurationType>Application</ConfigurationType>
4242 <UseDebugLibraries>false</UseDebugLibraries>
4343 <WholeProgramOptimization>true</WholeProgramOptimization>
4444 <CharacterSet>MultiByte</CharacterSet>
45- <PlatformToolset>v143</PlatformToolset>
45+ <PlatformToolset>v141</PlatformToolset>
4646 </PropertyGroup>
4747 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4848 <ConfigurationType>Application</ConfigurationType>
4949 <UseDebugLibraries>false</UseDebugLibraries>
5050 <WholeProgramOptimization>true</WholeProgramOptimization>
5151 <CharacterSet>MultiByte</CharacterSet>
52- <PlatformToolset>v143</PlatformToolset>
52+ <PlatformToolset>v141</PlatformToolset>
5353 </PropertyGroup>
5454 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5555 <ImportGroup Label="ExtensionSettings">
@@ -66,6 +66,7 @@
6666 ImGuiIO& io = ImGui::GetIO(); (void)io;
6767 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
6868 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
69+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
6970
7071 // Setup Dear ImGui style
7172 ImGui::StyleColorsDark();
@@ -75,6 +76,8 @@
7576 ImGuiStyle& style = ImGui::GetStyle();
7677 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
7778 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
79+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
80+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
7881
7982 // Setup Platform/Renderer backends
8083 ImGui_ImplSDL2_InitForSDLRenderer(window, renderer);
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{BAE3D0B5-9695-4EB1-AD0F-75890EB4A3B3}</ProjectGuid>
2323 <RootNamespace>example_sdl2_vulkan</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>MultiByte</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>MultiByte</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>MultiByte</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>MultiByte</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -396,6 +396,10 @@
396396 ImGuiIO& io = ImGui::GetIO(); (void)io;
397397 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
398398 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
399+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
400+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
401+ //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
402+ //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
399403
400404 // Setup Dear ImGui style
401405 ImGui::StyleColorsDark();
@@ -405,7 +409,16 @@
405409 ImGuiStyle& style = ImGui::GetStyle();
406410 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
407411 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
412+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
413+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
408414
415+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
416+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
417+ {
418+ style.WindowRounding = 0.0f;
419+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
420+ }
421+
409422 // Setup Platform/Renderer backends
410423 ImGui_ImplSDL2_InitForVulkan(window);
411424 ImGui_ImplVulkan_InitInfo init_info = {};
@@ -528,17 +541,25 @@
528541
529542 // Rendering
530543 ImGui::Render();
531- ImDrawData* draw_data = ImGui::GetDrawData();
532- const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f);
533- if (!is_minimized)
544+ ImDrawData* main_draw_data = ImGui::GetDrawData();
545+ const bool main_is_minimized = (main_draw_data->DisplaySize.x <= 0.0f || main_draw_data->DisplaySize.y <= 0.0f);
546+ wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w;
547+ wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w;
548+ wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w;
549+ wd->ClearValue.color.float32[3] = clear_color.w;
550+ if (!main_is_minimized)
551+ FrameRender(wd, main_draw_data);
552+
553+ // Update and Render additional Platform Windows
554+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
534555 {
535- wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w;
536- wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w;
537- wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w;
538- wd->ClearValue.color.float32[3] = clear_color.w;
539- FrameRender(wd, draw_data);
540- FramePresent(wd);
556+ ImGui::UpdatePlatformWindows();
557+ ImGui::RenderPlatformWindowsDefault();
541558 }
559+
560+ // Present Main Platform Window
561+ if (!main_is_minimized)
562+ FramePresent(wd);
542563 }
543564
544565 // Cleanup
@@ -14,7 +14,7 @@
1414 # * build/example_sdl2_wgpu[.exe] or build/Debug/example_sdl2_wgpu[.exe]
1515
1616 # Building for desktop with WGVK (MUCH EASIER)
17-# 1. git clone https://github.com/manuel5975p/WGVK dawn
17+# 1. git clone https://github.com/manuel5975p/WGVK wgvk
1818 # 2. cmake -B build -DIMGUI_WGVK_DIR=wgvk
1919 # 3. cmake --build build
2020 # The resulting binary will be found at one of the following locations:
@@ -37,7 +37,7 @@
3737 set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE)
3838 endif()
3939
40-set(CMAKE_CXX_STANDARD 17) # Dawn requires C++17
40+set(CMAKE_CXX_STANDARD 10) # Dawn requires C++20
4141
4242 # Dear ImGui
4343 set(IMGUI_DIR ../../)
@@ -21,7 +21,7 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{009DAC16-1A9C-47BE-9770-A30A046E8090}</ProjectGuid>
2323 <RootNamespace>example_sdl3_directx11</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 <ProjectName>example_sdl3_directx11</ProjectName>
2626 </PropertyGroup>
2727 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@@ -29,27 +29,27 @@
2929 <ConfigurationType>Application</ConfigurationType>
3030 <UseDebugLibraries>true</UseDebugLibraries>
3131 <CharacterSet>MultiByte</CharacterSet>
32- <PlatformToolset>v143</PlatformToolset>
32+ <PlatformToolset>v141</PlatformToolset>
3333 </PropertyGroup>
3434 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3535 <ConfigurationType>Application</ConfigurationType>
3636 <UseDebugLibraries>true</UseDebugLibraries>
3737 <CharacterSet>MultiByte</CharacterSet>
38- <PlatformToolset>v143</PlatformToolset>
38+ <PlatformToolset>v141</PlatformToolset>
3939 </PropertyGroup>
4040 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4141 <ConfigurationType>Application</ConfigurationType>
4242 <UseDebugLibraries>false</UseDebugLibraries>
4343 <WholeProgramOptimization>true</WholeProgramOptimization>
4444 <CharacterSet>MultiByte</CharacterSet>
45- <PlatformToolset>v143</PlatformToolset>
45+ <PlatformToolset>v141</PlatformToolset>
4646 </PropertyGroup>
4747 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4848 <ConfigurationType>Application</ConfigurationType>
4949 <UseDebugLibraries>false</UseDebugLibraries>
5050 <WholeProgramOptimization>true</WholeProgramOptimization>
5151 <CharacterSet>MultiByte</CharacterSet>
52- <PlatformToolset>v143</PlatformToolset>
52+ <PlatformToolset>v141</PlatformToolset>
5353 </PropertyGroup>
5454 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5555 <ImportGroup Label="ExtensionSettings">
@@ -66,6 +66,10 @@
6666 ImGuiIO& io = ImGui::GetIO(); (void)io;
6767 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
6868 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
69+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
70+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
71+ //io.ConfigViewportsNoAutoMerge = true;
72+ //io.ConfigViewportsNoTaskBarIcon = true;
6973
7074 // Setup Dear ImGui style
7175 ImGui::StyleColorsDark();
@@ -75,7 +79,16 @@
7579 ImGuiStyle& style = ImGui::GetStyle();
7680 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
7781 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
82+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
83+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
7884
85+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
86+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
87+ {
88+ style.WindowRounding = 0.0f;
89+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
90+ }
91+
7992 // Setup Platform/Renderer backends
8093 ImGui_ImplSDL3_InitForD3D(window);
8194 ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
@@ -186,6 +199,13 @@
186199 g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha);
187200 ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
188201
202+ // Update and Render additional Platform Windows
203+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
204+ {
205+ ImGui::UpdatePlatformWindows();
206+ ImGui::RenderPlatformWindowsDefault();
207+ }
208+
189209 g_pSwapChain->Present(1, 0); // Present with vsync
190210 //g_pSwapChain->Present(0, 0); // Present without vsync
191211 }
@@ -233,6 +253,16 @@
233253 res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext);
234254 if (res != S_OK)
235255 return false;
256+
257+ // Disable DXGI's default Alt+Enter fullscreen behavior.
258+ // - You are free to leave this enabled, but it will not work properly with multiple viewports.
259+ // - This must be done for all windows associated to the device. Our DX11 backend does this automatically for secondary viewports that it creates.
260+ IDXGIFactory* pSwapChainFactory;
261+ if (SUCCEEDED(g_pSwapChain->GetParent(IID_PPV_ARGS(&pSwapChainFactory))))
262+ {
263+ pSwapChainFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER);
264+ pSwapChainFactory->Release();
265+ }
236266
237267 CreateRenderTarget();
238268 return true;
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{84AAA301-84FE-428B-9E3E-817BC8123C0C}</ProjectGuid>
2323 <RootNamespace>example_sdl3_opengl3</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>MultiByte</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>MultiByte</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>MultiByte</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>MultiByte</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -94,6 +94,10 @@
9494 ImGuiIO& io = ImGui::GetIO(); (void)io;
9595 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
9696 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
97+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
98+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
99+ //io.ConfigViewportsNoAutoMerge = true;
100+ //io.ConfigViewportsNoTaskBarIcon = true;
97101
98102 // Setup Dear ImGui style
99103 ImGui::StyleColorsDark();
@@ -103,7 +107,16 @@
103107 ImGuiStyle& style = ImGui::GetStyle();
104108 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
105109 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
110+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
111+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
106112
113+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
114+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
115+ {
116+ style.WindowRounding = 0.0f;
117+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
118+ }
119+
107120 // Setup Platform/Renderer backends
108121 ImGui_ImplSDL3_InitForOpenGL(window, gl_context);
109122 ImGui_ImplOpenGL3_Init(glsl_version);
@@ -214,6 +227,19 @@
214227 glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
215228 glClear(GL_COLOR_BUFFER_BIT);
216229 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
230+
231+ // Update and Render additional Platform Windows
232+ // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
233+ // For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly)
234+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
235+ {
236+ SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow();
237+ SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
238+ ImGui::UpdatePlatformWindows();
239+ ImGui::RenderPlatformWindowsDefault();
240+ SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
241+ }
242+
217243 SDL_GL_SwapWindow(window);
218244 }
219245 #ifdef __EMSCRIPTEN__
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{c22cb6f8-39a5-4dda-90ed-4aca4e81e1e5}</ProjectGuid>
2323 <RootNamespace>example_sdl3_sdlgpu3</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>MultiByte</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>MultiByte</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>MultiByte</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>MultiByte</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -68,6 +68,8 @@
6868 ImGuiIO& io = ImGui::GetIO(); (void)io;
6969 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
7070 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
71+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
72+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
7173
7274 // Setup Dear ImGui style
7375 ImGui::StyleColorsDark();
@@ -77,7 +79,16 @@
7779 ImGuiStyle& style = ImGui::GetStyle();
7880 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
7981 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
82+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
83+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
8084
85+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
86+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
87+ {
88+ style.WindowRounding = 0.0f;
89+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
90+ }
91+
8192 // Setup Platform/Renderer backends
8293 ImGui_ImplSDL3_InitForSDLGPU(window);
8394 ImGui_ImplSDLGPU3_InitInfo init_info = {};
@@ -210,6 +221,13 @@
210221 ImGui_ImplSDLGPU3_RenderDrawData(draw_data, command_buffer, render_pass);
211222
212223 SDL_EndGPURenderPass(render_pass);
224+ }
225+
226+ // Update and Render additional Platform Windows
227+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
228+ {
229+ ImGui::UpdatePlatformWindows();
230+ ImGui::RenderPlatformWindowsDefault();
213231 }
214232
215233 // Submit the command buffer
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}</ProjectGuid>
2323 <RootNamespace>example_sdl3_opengl3</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>MultiByte</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>MultiByte</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>MultiByte</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>MultiByte</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -56,6 +56,7 @@
5656 ImGuiIO& io = ImGui::GetIO(); (void)io;
5757 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
5858 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
59+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
5960
6061 // Setup Dear ImGui style
6162 ImGui::StyleColorsDark();
@@ -65,6 +66,8 @@
6566 ImGuiStyle& style = ImGui::GetStyle();
6667 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
6768 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
69+ //io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
70+ //io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
6871
6972 // Setup Platform/Renderer backends
7073 ImGui_ImplSDL3_InitForSDLRenderer(window, renderer);
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{663A7E89-1E42-4222-921C-177F5B5910DF}</ProjectGuid>
2323 <RootNamespace>example_sdl3_vulkan</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>MultiByte</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>MultiByte</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>MultiByte</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>MultiByte</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -395,6 +395,10 @@
395395 ImGuiIO& io = ImGui::GetIO(); (void)io;
396396 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
397397 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
398+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
399+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
400+ //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
401+ //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
398402
399403 // Setup Dear ImGui style
400404 ImGui::StyleColorsDark();
@@ -404,7 +408,16 @@
404408 ImGuiStyle& style = ImGui::GetStyle();
405409 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
406410 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
411+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
412+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
407413
414+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
415+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
416+ {
417+ style.WindowRounding = 0.0f;
418+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
419+ }
420+
408421 // Setup Platform/Renderer backends
409422 ImGui_ImplSDL3_InitForVulkan(window);
410423 ImGui_ImplVulkan_InitInfo init_info = {};
@@ -530,17 +543,25 @@
530543
531544 // Rendering
532545 ImGui::Render();
533- ImDrawData* draw_data = ImGui::GetDrawData();
534- const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f);
535- if (!is_minimized)
546+ ImDrawData* main_draw_data = ImGui::GetDrawData();
547+ const bool main_is_minimized = (main_draw_data->DisplaySize.x <= 0.0f || main_draw_data->DisplaySize.y <= 0.0f);
548+ wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w;
549+ wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w;
550+ wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w;
551+ wd->ClearValue.color.float32[3] = clear_color.w;
552+ if (!main_is_minimized)
553+ FrameRender(wd, main_draw_data);
554+
555+ // Update and Render additional Platform Windows
556+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
536557 {
537- wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w;
538- wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w;
539- wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w;
540- wd->ClearValue.color.float32[3] = clear_color.w;
541- FrameRender(wd, draw_data);
542- FramePresent(wd);
558+ ImGui::UpdatePlatformWindows();
559+ ImGui::RenderPlatformWindowsDefault();
543560 }
561+
562+ // Present Main Platform Window
563+ if (!main_is_minimized)
564+ FramePresent(wd);
544565 }
545566
546567 // Cleanup
@@ -14,7 +14,7 @@
1414 # * build/example_sdl3_wgpu[.exe] or build/Debug/example_sdl3_wgpu[.exe]
1515
1616 # Building for desktop with WGVK (MUCH EASIER)
17-# 1. git clone https://github.com/manuel5975p/WGVK dawn
17+# 1. git clone https://github.com/manuel5975p/WGVK wgvk
1818 # 2. cmake -B build -DIMGUI_WGVK_DIR=wgvk
1919 # 3. cmake --build build
2020 # The resulting binary will be found at one of the following locations:
@@ -37,7 +37,7 @@
3737 set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE)
3838 endif()
3939
40-set(CMAKE_CXX_STANDARD 17) # Dawn requires C++17
40+set(CMAKE_CXX_STANDARD 20) # Dawn requires C++20
4141
4242 # Dear ImGui
4343 set(IMGUI_DIR ../../)
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{345A953E-A004-4648-B442-DC5F9F11068C}</ProjectGuid>
2323 <RootNamespace>example_win32_directx10</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>Unicode</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>Unicode</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>Unicode</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>Unicode</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -57,6 +57,10 @@
5757 ImGuiIO& io = ImGui::GetIO(); (void)io;
5858 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
5959 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
60+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
61+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
62+ //io.ConfigViewportsNoAutoMerge = true;
63+ //io.ConfigViewportsNoTaskBarIcon = true;
6064
6165 // Setup Dear ImGui style
6266 ImGui::StyleColorsDark();
@@ -66,7 +70,16 @@
6670 ImGuiStyle& style = ImGui::GetStyle();
6771 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
6872 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
73+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
74+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
6975
76+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
77+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
78+ {
79+ style.WindowRounding = 0.0f;
80+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
81+ }
82+
7083 // Setup Platform/Renderer backends
7184 ImGui_ImplWin32_Init(hwnd);
7285 ImGui_ImplDX10_Init(g_pd3dDevice);
@@ -177,6 +190,13 @@
177190 g_pd3dDevice->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha);
178191 ImGui_ImplDX10_RenderDrawData(ImGui::GetDrawData());
179192
193+ // Update and Render additional Platform Windows
194+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
195+ {
196+ ImGui::UpdatePlatformWindows();
197+ ImGui::RenderPlatformWindowsDefault();
198+ }
199+
180200 // Present
181201 HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync
182202 //HRESULT hr = g_pSwapChain->Present(0, 0); // Present without vsync
@@ -196,7 +216,6 @@
196216 }
197217
198218 // Helper functions
199-
200219 bool CreateDeviceD3D(HWND hWnd)
201220 {
202221 // Setup swap chain
@@ -224,6 +243,16 @@
224243 res = D3D10CreateDeviceAndSwapChain(nullptr, D3D10_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice);
225244 if (res != S_OK)
226245 return false;
246+
247+ // Disable DXGI's default Alt+Enter fullscreen behavior.
248+ // - You are free to leave this enabled, but it will not work properly with multiple viewports.
249+ // - This must be done for all windows associated to the device. Our DX11 backend does this automatically for secondary viewports that it creates.
250+ IDXGIFactory* pSwapChainFactory;
251+ if (SUCCEEDED(g_pSwapChain->GetParent(IID_PPV_ARGS(&pSwapChainFactory))))
252+ {
253+ pSwapChainFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER);
254+ pSwapChainFactory->Release();
255+ }
227256
228257 CreateRenderTarget();
229258 return true;
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{9F316E83-5AE5-4939-A723-305A94F48005}</ProjectGuid>
2323 <RootNamespace>example_win32_directx11</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>Unicode</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>Unicode</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>Unicode</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>Unicode</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -57,6 +57,12 @@
5757 ImGuiIO& io = ImGui::GetIO(); (void)io;
5858 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
5959 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
60+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
61+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
62+ //io.ConfigViewportsNoAutoMerge = true;
63+ //io.ConfigViewportsNoTaskBarIcon = true;
64+ //io.ConfigDockingAlwaysTabBar = true;
65+ //io.ConfigDockingTransparentPayload = true;
6066
6167 // Setup Dear ImGui style
6268 ImGui::StyleColorsDark();
@@ -66,7 +72,16 @@
6672 ImGuiStyle& style = ImGui::GetStyle();
6773 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
6874 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
75+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
76+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
6977
78+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
79+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
80+ {
81+ style.WindowRounding = 0.0f;
82+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
83+ }
84+
7085 // Setup Platform/Renderer backends
7186 ImGui_ImplWin32_Init(hwnd);
7287 ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
@@ -177,6 +192,13 @@
177192 g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha);
178193 ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
179194
195+ // Update and Render additional Platform Windows
196+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
197+ {
198+ ImGui::UpdatePlatformWindows();
199+ ImGui::RenderPlatformWindowsDefault();
200+ }
201+
180202 // Present
181203 HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync
182204 //HRESULT hr = g_pSwapChain->Present(0, 0); // Present without vsync
@@ -196,7 +218,6 @@
196218 }
197219
198220 // Helper functions
199-
200221 bool CreateDeviceD3D(HWND hWnd)
201222 {
202223 // Setup swap chain
@@ -226,6 +247,16 @@
226247 res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext);
227248 if (res != S_OK)
228249 return false;
250+
251+ // Disable DXGI's default Alt+Enter fullscreen behavior.
252+ // - You are free to leave this enabled, but it will not work properly with multiple viewports.
253+ // - This must be done for all windows associated to the device. Our DX11 backend does this automatically for secondary viewports that it creates.
254+ IDXGIFactory* pSwapChainFactory;
255+ if (SUCCEEDED(g_pSwapChain->GetParent(IID_PPV_ARGS(&pSwapChainFactory))))
256+ {
257+ pSwapChainFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER);
258+ pSwapChainFactory->Release();
259+ }
229260
230261 CreateRenderTarget();
231262 return true;
@@ -28,27 +28,27 @@
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>Unicode</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v142</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>Unicode</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v142</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>Unicode</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v142</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>Unicode</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v142</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -137,6 +137,10 @@
137137 ImGuiIO& io = ImGui::GetIO(); (void)io;
138138 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
139139 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
140+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
141+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
142+ //io.ConfigViewportsNoAutoMerge = true;
143+ //io.ConfigViewportsNoTaskBarIcon = true;
140144
141145 // Setup Dear ImGui style
142146 ImGui::StyleColorsDark();
@@ -146,7 +150,16 @@
146150 ImGuiStyle& style = ImGui::GetStyle();
147151 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
148152 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
153+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
154+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
149155
156+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
157+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
158+ {
159+ style.WindowRounding = 0.0f;
160+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
161+ }
162+
150163 // Setup Platform/Renderer backends
151164 ImGui_ImplWin32_Init(hwnd);
152165
@@ -285,6 +298,14 @@
285298 g_pd3dCommandList->Close();
286299
287300 g_pd3dCommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&g_pd3dCommandList);
301+
302+ // Update and Render additional Platform Windows
303+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
304+ {
305+ ImGui::UpdatePlatformWindows();
306+ ImGui::RenderPlatformWindowsDefault();
307+ }
308+
288309 g_pd3dCommandQueue->Signal(g_fence, ++g_fenceLastSignaledValue);
289310 frameCtx->FenceValue = g_fenceLastSignaledValue;
290311
@@ -310,7 +331,6 @@
310331 }
311332
312333 // Helper functions
313-
314334 bool CreateDeviceD3D(HWND hWnd)
315335 {
316336 // Setup swap chain
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{4165A294-21F2-44CA-9B38-E3F935ABADF5}</ProjectGuid>
2323 <RootNamespace>example_win32_directx9</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>Unicode</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>Unicode</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>Unicode</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>Unicode</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -55,6 +55,10 @@
5555 ImGuiIO& io = ImGui::GetIO(); (void)io;
5656 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
5757 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
58+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
59+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
60+ //io.ConfigViewportsNoAutoMerge = true;
61+ //io.ConfigViewportsNoTaskBarIcon = true;
5862
5963 // Setup Dear ImGui style
6064 ImGui::StyleColorsDark();
@@ -64,7 +68,16 @@
6468 ImGuiStyle& style = ImGui::GetStyle();
6569 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
6670 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
71+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
72+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
6773
74+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
75+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
76+ {
77+ style.WindowRounding = 0.0f;
78+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
79+ }
80+
6881 // Setup Platform/Renderer backends
6982 ImGui_ImplWin32_Init(hwnd);
7083 ImGui_ImplDX9_Init(g_pd3dDevice);
@@ -187,6 +200,14 @@
187200 ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
188201 g_pd3dDevice->EndScene();
189202 }
203+
204+ // Update and Render additional Platform Windows
205+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
206+ {
207+ ImGui::UpdatePlatformWindows();
208+ ImGui::RenderPlatformWindowsDefault();
209+ }
210+
190211 HRESULT result = g_pd3dDevice->Present(nullptr, nullptr, nullptr, nullptr);
191212 if (result == D3DERR_DEVICELOST)
192213 g_DeviceLost = true;
@@ -205,7 +226,6 @@
205226 }
206227
207228 // Helper functions
208-
209229 bool CreateDeviceD3D(HWND hWnd)
210230 {
211231 if ((g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == nullptr)
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{C624E5FF-D4FE-4D35-9164-B8A91864F98E}</ProjectGuid>
2323 <RootNamespace>example_win32_opengl2</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>Unicode</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>Unicode</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>Unicode</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>Unicode</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -33,6 +33,42 @@
3333 void ResetDeviceWGL();
3434 LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
3535
36+// Support function for multi-viewports
37+// Unlike most other backend combination, we need specific hooks to combine Win32+OpenGL.
38+// We could in theory decide to support Win32-specific code in OpenGL backend via e.g. an hypothetical ImGui_ImplOpenGL3_InitForRawWin32().
39+static void Hook_Renderer_CreateWindow(ImGuiViewport* viewport)
40+{
41+ assert(viewport->RendererUserData == NULL);
42+
43+ WGL_WindowData* data = IM_NEW(WGL_WindowData);
44+ CreateDeviceWGL((HWND)viewport->PlatformHandle, data);
45+ viewport->RendererUserData = data;
46+}
47+
48+static void Hook_Renderer_DestroyWindow(ImGuiViewport* viewport)
49+{
50+ if (viewport->RendererUserData != NULL)
51+ {
52+ WGL_WindowData* data = (WGL_WindowData*)viewport->RendererUserData;
53+ CleanupDeviceWGL((HWND)viewport->PlatformHandle, data);
54+ IM_DELETE(data);
55+ viewport->RendererUserData = NULL;
56+ }
57+}
58+
59+static void Hook_Platform_RenderWindow(ImGuiViewport* viewport, void*)
60+{
61+ // Activate the platform window DC in the OpenGL rendering context
62+ if (WGL_WindowData* data = (WGL_WindowData*)viewport->RendererUserData)
63+ wglMakeCurrent(data->hDC, g_hRC);
64+}
65+
66+static void Hook_Renderer_SwapBuffers(ImGuiViewport* viewport, void*)
67+{
68+ if (WGL_WindowData* data = (WGL_WindowData*)viewport->RendererUserData)
69+ ::SwapBuffers(data->hDC);
70+}
71+
3672 // Main code
3773 int main(int, char**)
3874 {
@@ -65,6 +101,8 @@
65101 ImGuiIO& io = ImGui::GetIO(); (void)io;
66102 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
67103 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
104+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
105+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
68106
69107 // Setup Dear ImGui style
70108 ImGui::StyleColorsDark();
@@ -74,11 +112,34 @@
74112 ImGuiStyle& style = ImGui::GetStyle();
75113 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
76114 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
115+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
116+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
77117
118+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
119+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
120+ {
121+ style.WindowRounding = 0.0f;
122+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
123+ }
124+
78125 // Setup Platform/Renderer backends
79126 ImGui_ImplWin32_InitForOpenGL(hwnd);
80127 ImGui_ImplOpenGL3_Init();
81128
129+ // Win32+GL needs specific hooks for viewport, as there are specific things needed to tie Win32 and GL api.
130+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
131+ {
132+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
133+ IM_ASSERT(platform_io.Renderer_CreateWindow == NULL);
134+ IM_ASSERT(platform_io.Renderer_DestroyWindow == NULL);
135+ IM_ASSERT(platform_io.Renderer_SwapBuffers == NULL);
136+ IM_ASSERT(platform_io.Platform_RenderWindow == NULL);
137+ platform_io.Renderer_CreateWindow = Hook_Renderer_CreateWindow;
138+ platform_io.Renderer_DestroyWindow = Hook_Renderer_DestroyWindow;
139+ platform_io.Renderer_SwapBuffers = Hook_Renderer_SwapBuffers;
140+ platform_io.Platform_RenderWindow = Hook_Platform_RenderWindow;
141+ }
142+
82143 // Load Fonts
83144 // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap().
84145 // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold.
@@ -172,6 +233,16 @@
172233 glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
173234 glClear(GL_COLOR_BUFFER_BIT);
174235 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
236+
237+ // Update and Render additional Platform Windows
238+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
239+ {
240+ ImGui::UpdatePlatformWindows();
241+ ImGui::RenderPlatformWindowsDefault();
242+
243+ // Restore the OpenGL rendering context to the main window DC, since platform windows might have changed it.
244+ wglMakeCurrent(g_MainWindow.hDC, g_hRC);
245+ }
175246
176247 // Present
177248 ::SwapBuffers(g_MainWindow.hDC);
@@ -21,34 +21,34 @@
2121 <PropertyGroup Label="Globals">
2222 <ProjectGuid>{0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}</ProjectGuid>
2323 <RootNamespace>example_win32_directx11</RootNamespace>
24- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
24+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
2525 </PropertyGroup>
2626 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2727 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2828 <ConfigurationType>Application</ConfigurationType>
2929 <UseDebugLibraries>true</UseDebugLibraries>
3030 <CharacterSet>Unicode</CharacterSet>
31- <PlatformToolset>v143</PlatformToolset>
31+ <PlatformToolset>v141</PlatformToolset>
3232 </PropertyGroup>
3333 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
3434 <ConfigurationType>Application</ConfigurationType>
3535 <UseDebugLibraries>true</UseDebugLibraries>
3636 <CharacterSet>Unicode</CharacterSet>
37- <PlatformToolset>v143</PlatformToolset>
37+ <PlatformToolset>v141</PlatformToolset>
3838 </PropertyGroup>
3939 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
4040 <ConfigurationType>Application</ConfigurationType>
4141 <UseDebugLibraries>false</UseDebugLibraries>
4242 <WholeProgramOptimization>true</WholeProgramOptimization>
4343 <CharacterSet>Unicode</CharacterSet>
44- <PlatformToolset>v143</PlatformToolset>
44+ <PlatformToolset>v141</PlatformToolset>
4545 </PropertyGroup>
4646 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4747 <ConfigurationType>Application</ConfigurationType>
4848 <UseDebugLibraries>false</UseDebugLibraries>
4949 <WholeProgramOptimization>true</WholeProgramOptimization>
5050 <CharacterSet>Unicode</CharacterSet>
51- <PlatformToolset>v143</PlatformToolset>
51+ <PlatformToolset>v141</PlatformToolset>
5252 </PropertyGroup>
5353 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5454 <ImportGroup Label="ExtensionSettings">
@@ -340,6 +340,16 @@
340340
341341 LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
342342
343+// FIXME: This code would ideally be inside imgui_impl_win32.cpp, it would create a dependency on Vulkan headers in imgui_impl_win32.cpp
344+static int ImGui_ImplWin32_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface)
345+{
346+ VkWin32SurfaceCreateInfoKHR createInfo = {};
347+ createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
348+ createInfo.hwnd = (HWND)viewport->PlatformHandleRaw;
349+ createInfo.hinstance = ::GetModuleHandle(nullptr);
350+ return (int)vkCreateWin32SurfaceKHR((VkInstance)vk_instance, &createInfo, (VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface);
351+}
352+
343353 // Main code
344354 int main(int, char**)
345355 {
@@ -383,6 +393,10 @@
383393 ImGuiIO& io = ImGui::GetIO(); (void)io;
384394 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
385395 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
396+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
397+ io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
398+ //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
399+ //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
386400
387401 // Setup Dear ImGui style
388402 ImGui::StyleColorsDark();
@@ -392,9 +406,20 @@
392406 ImGuiStyle& style = ImGui::GetStyle();
393407 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
394408 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
409+ io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
410+ io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
395411
412+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
413+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
414+ {
415+ style.WindowRounding = 0.0f;
416+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
417+ }
418+
396419 // Setup Platform/Renderer backends
397420 ImGui_ImplWin32_Init(hwnd);
421+ ImGui::GetPlatformIO().Platform_CreateVkSurface = ImGui_ImplWin32_CreateVkSurface;
422+
398423 ImGui_ImplVulkan_InitInfo init_info = {};
399424 //init_info.ApiVersion = VK_API_VERSION_1_3; // Pass in your value of VkApplicationInfo::apiVersion, otherwise will default to header version.
400425 init_info.Instance = g_Instance;
@@ -497,17 +522,25 @@
497522
498523 // Rendering
499524 ImGui::Render();
500- ImDrawData* draw_data = ImGui::GetDrawData();
501- const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f);
502- if (!is_minimized)
525+ ImDrawData* main_draw_data = ImGui::GetDrawData();
526+ const bool main_is_minimized = (main_draw_data->DisplaySize.x <= 0.0f || main_draw_data->DisplaySize.y <= 0.0f);
527+ wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w;
528+ wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w;
529+ wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w;
530+ wd->ClearValue.color.float32[3] = clear_color.w;
531+ if (!main_is_minimized)
532+ FrameRender(wd, main_draw_data);
533+
534+ // Update and Render additional Platform Windows
535+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
503536 {
504- wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w;
505- wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w;
506- wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w;
507- wd->ClearValue.color.float32[3] = clear_color.w;
508- FrameRender(wd, draw_data);
509- FramePresent(wd);
537+ ImGui::UpdatePlatformWindows();
538+ ImGui::RenderPlatformWindowsDefault();
510539 }
540+
541+ // Present Main Platform Window
542+ if (!main_is_minimized)
543+ FramePresent(wd);
511544 }
512545
513546 // Cleanup
@@ -49,11 +49,13 @@
4949 //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
5050 //#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.
5151 //#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().
52-//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded fonts (ProggyClean/ProggyForever), remove ~9 KB + ~14 KB from output binary. AddFontDefaultXXX() functions will assert.
52+//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded fonts (ProggyClean + ProggyForever). Remove ~9 KB + ~14 KB from output binary. AddFontDefaultXXX() functions will assert.
53+//#define IMGUI_DISABLE_DEFAULT_FONT_BITMAP // Disable default embedded bitmap font (ProggyClean). Remove ~9 KB from output binary. AddFontDefaultBitmap() will assert.
54+//#define IMGUI_DISABLE_DEFAULT_FONT_VECTOR // Disable default embedded vector font (ProggyForever), Remove ~14 KB from output binary. AddFontDefaultVector() will assert.
5355 //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
5456
5557 //---- Enable Test Engine / Automation features.
56-//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details.
58+//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_imconfig.h", see Test Engine for details.
5759
5860 //---- Include imgui_user.h at the end of imgui.h as a convenience
5961 // May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.

大き過ぎるので表示しません

@@ -1,4 +1,4 @@
1-// dear imgui, v1.92.8
1+// dear imgui, v1.92.9 WIP
22 // (headers)
33
44 // Help:
@@ -29,10 +29,12 @@
2929
3030 // Library Version
3131 // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
32-#define IMGUI_VERSION "1.92.8"
33-#define IMGUI_VERSION_NUM 19280
32+#define IMGUI_VERSION "1.92.9 WIP"
33+#define IMGUI_VERSION_NUM 19284
3434 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000
3535 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198
36+#define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch.
37+#define IMGUI_HAS_DOCK // In 'docking' WIP branch.
3638
3739 /*
3840
@@ -46,14 +48,14 @@
4648 // [SECTION] Helpers: Debug log, Memory allocations macros, ImVector<>
4749 // [SECTION] ImGuiStyle
4850 // [SECTION] ImGuiIO
49-// [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload)
51+// [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiWindowClass, ImGuiPayload)
5052 // [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor)
5153 // [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiMultiSelectIO, ImGuiSelectionRequest, ImGuiSelectionBasicStorage, ImGuiSelectionExternalStorage)
5254 // [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData)
5355 // [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureRect, ImTextureData)
5456 // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFontBaked, ImFont)
5557 // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport)
56-// [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformImeData)
58+// [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformMonitor, ImGuiPlatformImeData)
5759 // [SECTION] Obsolete functions and types
5860
5961 */
@@ -197,8 +199,9 @@
197199 struct ImGuiMultiSelectIO; // Structure to interact with a BeginMultiSelect()/EndMultiSelect() block
198200 struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame
199201 struct ImGuiPayload; // User data payload for drag and drop operations
200-struct ImGuiPlatformIO; // Interface between platform/renderer backends and ImGui (e.g. Clipboard, IME hooks). Extends ImGuiIO. In docking branch, this gets extended to support multi-viewports.
202+struct ImGuiPlatformIO; // Interface between platform/renderer backends and ImGui (e.g. Clipboard, IME, Multi-Viewport support). Extends ImGuiIO.
201203 struct ImGuiPlatformImeData; // Platform IME data for io.PlatformSetImeDataFn() function.
204+struct ImGuiPlatformMonitor; // Multi-viewport support: user-provided bounds for each connected monitor/display. Used when positioning popups and tooltips to avoid them straddling monitors
202205 struct ImGuiSelectionBasicStorage; // Optional helper to store multi-selection state + apply multi-selection requests.
203206 struct ImGuiSelectionExternalStorage;//Optional helper to apply multi-selection requests to existing randomly accessible storage.
204207 struct ImGuiSelectionRequest; // A selection request (stored in ImGuiMultiSelectIO)
@@ -210,7 +213,8 @@
210213 struct ImGuiTableColumnSortSpecs; // Sorting specification for one column of a table
211214 struct ImGuiTextBuffer; // Helper to hold and append into a text buffer (~string builder)
212215 struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbbb][,ccccc]")
213-struct ImGuiViewport; // A Platform Window (always only one in 'master' branch), in the future may represent Platform Monitor
216+struct ImGuiViewport; // A Platform Window (always 1 unless multi-viewport are enabled. One per platform window to output to). In the future may represent Platform Monitor
217+struct ImGuiWindowClass; // Window class (rare/advanced uses: provide hints to the platform backend via altered viewport flags and parent/child info)
214218
215219 // Enumerations
216220 // - We don't use strongly typed enums much because they add constraints (can't extend in private code, can't store typed in bit fields, extra casting on iteration)
@@ -246,6 +250,7 @@
246250 typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4() etc.
247251 typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags
248252 typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo()
253+typedef int ImGuiDockNodeFlags; // -> enum ImGuiDockNodeFlags_ // Flags: for DockSpace()
249254 typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for BeginDragDropSource(), AcceptDragDropPayload()
250255 typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused()
251256 typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc.
@@ -466,10 +471,12 @@
466471 IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options.
467472 IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered and hoverable (e.g. not blocked by a popup/modal)? See ImGuiHoveredFlags_ for options. IMPORTANT: If you are trying to check whether your mouse should be dispatched to Dear ImGui or to your underlying app, you should not use this function! Use the 'io.WantCaptureMouse' boolean for that! Refer to FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" for details.
468473 IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives
474+ IMGUI_API float GetWindowDpiScale(); // get DPI scale currently associated to the current window's viewport.
469475 IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (IT IS UNLIKELY YOU EVER NEED TO USE THIS. Consider always using GetCursorScreenPos() and GetContentRegionAvail() instead)
470476 IMGUI_API ImVec2 GetWindowSize(); // get current window size (IT IS UNLIKELY YOU EVER NEED TO USE THIS. Consider always using GetCursorScreenPos() and GetContentRegionAvail() instead)
471477 IMGUI_API float GetWindowWidth(); // get current window width (IT IS UNLIKELY YOU EVER NEED TO USE THIS). Shortcut for GetWindowSize().x.
472478 IMGUI_API float GetWindowHeight(); // get current window height (IT IS UNLIKELY YOU EVER NEED TO USE THIS). Shortcut for GetWindowSize().y.
479+ IMGUI_API ImGuiViewport*GetWindowViewport(); // get viewport currently associated to the current window.
473480
474481 // Window manipulation
475482 // - Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin).
@@ -481,6 +488,7 @@
481488 IMGUI_API void SetNextWindowFocus(); // set next window to be focused / top-most. call before Begin()
482489 IMGUI_API void SetNextWindowScroll(const ImVec2& scroll); // set next window scrolling value (use < 0.0f to not affect a given axis).
483490 IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily override the Alpha component of ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground.
491+ IMGUI_API void SetNextWindowViewport(ImGuiID viewport_id); // set next window viewport
484492 IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects.
485493 IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0, 0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects.
486494 IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed().
@@ -613,7 +621,8 @@
613621 IMGUI_API ImGuiID GetID(int int_id);
614622
615623 // Widgets: Text
616- IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text.
624+ // - Note that all functions taking format strings in the API may be passed ("%s", text) or ("%.*s", text_len, text): which will automatically bypass the formatter.
625+ IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Practically equivalent to 'Text("%s", text)' but doesn't require null terminated string if 'text_end' is specified.
617626 IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); // formatted text
618627 IMGUI_API void TextV(const char* fmt, va_list args) IM_FMTLIST(1);
619628 IMGUI_API void TextColored(const ImVec4& col, const char* fmt, ...) IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor();
@@ -648,7 +657,7 @@
648657 // Widgets: Images
649658 // - Read about ImTextureID/ImTextureRef here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
650659 // - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above.
651- // - Image() pads adds style.ImageBorderSize on each side, ImageButton() adds style.FramePadding on each side.
660+ // - Image() adds style.ImageBorderSize on each side, ImageButton() adds style.FramePadding on each side.
652661 // - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified.
653662 // - An obsolete version of Image(), before 1.91.9 (March 2025), had a 'tint_col' parameter which is now supported by the ImageWithBg() function.
654663 IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1));
@@ -808,7 +817,7 @@
808817 // - Use BeginMenuBar() on a window ImGuiWindowFlags_MenuBar to append to its menu bar.
809818 // - Use BeginMainMenuBar() to create a menu bar at the top of the screen and append to it.
810819 // - Use BeginMenu() to create a menu. You can call BeginMenu() multiple time with the same identifier to append more items to it.
811- // - Not that MenuItem() keyboardshortcuts are displayed as a convenience but _not processed_ by Dear ImGui at the moment.
820+ // - Note that MenuItem() keyboard shortcuts are displayed as a convenience but _not processed_ by Dear ImGui at the moment.
812821 IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window).
813822 IMGUI_API void EndMenuBar(); // only call EndMenuBar() if BeginMenuBar() returns true!
814823 IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar.
@@ -837,7 +846,7 @@
837846
838847 // Popups, Modals
839848 // - They block normal mouse hovering detection (and therefore most mouse interactions) behind them.
840- // - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
849+ // - If not modal: they can be closed by clicking anywhere outside them, or by pressing Escape (call 'Shortcut(ImGuiKey_Escape)' to claim a higher-priority shortcut).
841850 // - Their visibility state (~bool) is held internally instead of being held by the programmer as we are used to with regular Begin*() calls.
842851 // - The 3 properties above are related: we need to retain popup visibility state in the library because popups may be closed as any time.
843852 // - You can bypass the hovering restriction by using ImGuiHoveredFlags_AllowWhenBlockedByPopup when calling IsItemHovered() or IsWindowHovered().
@@ -908,14 +917,15 @@
908917 IMGUI_API bool TableSetColumnIndex(int column_n); // append into the specified column. Return true when column is visible.
909918
910919 // Tables: Headers & Columns declaration
911- // - Use TableSetupColumn() to specify label, resizing policy, default width/weight, id, various other flags etc.
920+ // - Use TableSetupColumn() to specify label, resizing policy, default width/weight, various other flags etc.
921+ // (the trailing 'ImGuiID user_data', which used to be referred to as 'ImGuiID user_id', is merely user data that is blindly copied in ImGuiTableColumnSortSpecs).
912922 // - Use TableHeadersRow() to create a header row and automatically submit a TableHeader() for each column.
913923 // Headers are required to perform: reordering, sorting, and opening the context menu.
914924 // The context menu can also be made available in columns body using ImGuiTableFlags_ContextMenuInBody.
915925 // - You may manually submit headers using TableNextRow() + TableHeader() calls, but this is only useful in
916926 // some advanced use cases (e.g. adding custom widgets in header row).
917927 // - Use TableSetupScrollFreeze() to lock columns/rows so they stay visible when scrolled. When freezing columns you would usually also use ImGuiTableColumnFlags_NoHide on them.
918- IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_id = 0);
928+ IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_data = 0);
919929 IMGUI_API void TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled.
920930 IMGUI_API void TableHeader(const char* label); // submit one header cell manually (rarely used)
921931 IMGUI_API void TableHeadersRow(); // submit a row with headers cells based on data provided to TableSetupColumn() + submit context menu
@@ -957,6 +967,34 @@
957967 IMGUI_API bool TabItemButton(const char* label, ImGuiTabItemFlags flags = 0); // create a Tab behaving like a button. return true when clicked. cannot be selected in the tab bar.
958968 IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name.
959969
970+ // Docking
971+ // - Read https://github.com/ocornut/imgui/wiki/Docking for details.
972+ // - Enable with io.ConfigFlags |= ImGuiConfigFlags_DockingEnable.
973+ // - You can use many Docking facilities without calling any API.
974+ // - Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.
975+ // - Drag from window menu button (upper-left button) to undock an entire node (all windows).
976+ // - When io.ConfigDockingWithShift == true, you instead need to hold SHIFT to enable docking.
977+ // - DockSpaceOverViewport:
978+ // - This is a helper to create an invisible window covering a viewport, then submit a DockSpace() into it.
979+ // - Most applications can simply call DockSpaceOverViewport() once to allow docking windows into e.g. the edge of your screen.
980+ // e.g. ImGui::NewFrame(); ImGui::DockSpaceOverViewport(); // Create a dockspace in main viewport.
981+ // or: ImGui::NewFrame(); ImGui::DockSpaceOverViewport(0, nullptr, ImGuiDockNodeFlags_PassthruCentralNode); // Create a dockspace in main viewport, central node is transparent.
982+ // - Dockspaces:
983+ // - A dockspace is an explicit dock node within an existing window.
984+ // - IMPORTANT: Dockspaces need to be submitted _before_ any window they can host. Submit them early in your frame!
985+ // - IMPORTANT: Dockspaces need to be kept alive if hidden, otherwise windows docked into it will be undocked.
986+ // If you have e.g. multiple tabs with a dockspace inside each tab: submit the non-visible dockspaces with ImGuiDockNodeFlags_KeepAliveOnly.
987+ // - See 'Demo->Examples->Dockspace' or 'Demo->Examples->Documents' for more detailed demos.
988+ // - Programmatic docking:
989+ // - There is no public API yet other than the very limited SetNextWindowDockID() function. Sorry for that!
990+ // - Read https://github.com/ocornut/imgui/wiki/Docking for examples of how to use current internal API.
991+ IMGUI_API ImGuiID DockSpace(ImGuiID dockspace_id, const ImVec2& size = ImVec2(0, 0), ImGuiDockNodeFlags flags = 0, const ImGuiWindowClass* window_class = NULL);
992+ IMGUI_API ImGuiID DockSpaceOverViewport(ImGuiID dockspace_id = 0, const ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags flags = 0, const ImGuiWindowClass* window_class = NULL);
993+ IMGUI_API void SetNextWindowDockID(ImGuiID dock_id, ImGuiCond cond = 0); // set next window dock id
994+ IMGUI_API void SetNextWindowClass(const ImGuiWindowClass* window_class); // set next window class (control docking compatibility + provide hints to platform backend via custom viewport flags and platform parent/child relationship)
995+ IMGUI_API ImGuiID GetWindowDockID(); // get dock id of current window, or 0 if not associated to any docking node.
996+ IMGUI_API bool IsWindowDocked(); // is current window docked into another window?
997+
960998 // Logging/Capture
961999 // - All text output from the interface can be captured into tty/file/clipboard. By default, tree nodes are automatically opened during logging.
9621000 IMGUI_API void LogToTTY(int auto_open_depth = -1); // start logging to tty (stdout)
@@ -1032,8 +1070,8 @@
10321070 IMGUI_API ImGuiViewport* GetMainViewport(); // return primary/default viewport. This can never be NULL.
10331071
10341072 // Background/Foreground Draw Lists
1035- IMGUI_API ImDrawList* GetBackgroundDrawList(); // this draw list will be the first rendered one. Useful to quickly draw shapes/text behind dear imgui contents.
1036- IMGUI_API ImDrawList* GetForegroundDrawList(); // this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents.
1073+ IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport = NULL); // get background draw list for the given viewport or viewport associated to the current window. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents.
1074+ IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport = NULL); // get foreground draw list for the given viewport or viewport associated to the current window. this draw list will be the top-most rendered one. Useful to quickly draw shapes/text over dear imgui contents.
10371075
10381076 // Miscellaneous Utilities
10391077 IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped.
@@ -1156,6 +1194,15 @@
11561194 IMGUI_API void* MemAlloc(size_t size);
11571195 IMGUI_API void MemFree(void* ptr);
11581196
1197+ // (Optional) Platform/OS interface for multi-viewport support
1198+ // Read comments around the ImGuiPlatformIO structure for more details.
1199+ // Note: You may use GetWindowViewport() to get the current viewport of the current window.
1200+ IMGUI_API void UpdatePlatformWindows(); // call in main loop. will call CreateWindow/ResizeWindow/etc. platform functions for each secondary viewport, and DestroyWindow for each inactive viewport.
1201+ IMGUI_API void RenderPlatformWindowsDefault(void* platform_render_arg = NULL, void* renderer_render_arg = NULL); // call in main loop. will call RenderWindow/SwapBuffers platform functions for each secondary viewport which doesn't have the ImGuiViewportFlags_Minimized flag set. May be reimplemented by user for custom rendering needs.
1202+ IMGUI_API void DestroyPlatformWindows(); // call DestroyWindow platform functions for all viewports. call from backend Shutdown() if you need to close platform windows before imgui shutdown. otherwise will be called by DestroyContext().
1203+ IMGUI_API ImGuiViewport* FindViewportByID(ImGuiID viewport_id); // this is a helper for backends.
1204+ IMGUI_API ImGuiViewport* FindViewportByPlatformHandle(void* platform_handle); // this is a helper for backends. the type platform_handle is decided by the backend (e.g. HWND, MyWindow*, GLFWwindow* etc.)
1205+
11591206 } // namespace ImGui
11601207
11611208 //-----------------------------------------------------------------------------
@@ -1186,11 +1233,13 @@
11861233 ImGuiWindowFlags_NoNavInputs = 1 << 16, // No keyboard/gamepad navigation within the window
11871234 ImGuiWindowFlags_NoNavFocus = 1 << 17, // No focusing toward this window with keyboard/gamepad navigation (e.g. skipped by Ctrl+Tab)
11881235 ImGuiWindowFlags_UnsavedDocument = 1 << 18, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.
1236+ ImGuiWindowFlags_NoDocking = 1 << 19, // Disable docking of this window
11891237 ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
11901238 ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse,
11911239 ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
11921240
11931241 // [Internal]
1242+ ImGuiWindowFlags_DockNodeHost = 1 << 23, // Don't use! For internal use by Begin()/NewFrame()
11941243 ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild()
11951244 ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip()
11961245 ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup()
@@ -1330,7 +1379,7 @@
13301379
13311380 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
13321381 ImGuiTreeNodeFlags_NavLeftJumpsBackHere = ImGuiTreeNodeFlags_NavLeftJumpsToParent, // Renamed in 1.92.0
1333- ImGuiTreeNodeFlags_SpanTextWidth = ImGuiTreeNodeFlags_SpanLabelWidth, // Renamed in 1.90.7
1382+ //ImGuiTreeNodeFlags_SpanTextWidth = ImGuiTreeNodeFlags_SpanLabelWidth, // Renamed in 1.90.7
13341383 //ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7
13351384 #endif
13361385 };
@@ -1436,7 +1485,7 @@
14361485 ImGuiFocusedFlags_RootWindow = 1 << 1, // Test from root window (top most parent of the current hierarchy)
14371486 ImGuiFocusedFlags_AnyWindow = 1 << 2, // Return true if any window is focused. Important: If you are trying to tell how to dispatch your low-level inputs, do NOT use this. Use 'io.WantCaptureMouse' instead! Please read the FAQ!
14381487 ImGuiFocusedFlags_NoPopupHierarchy = 1 << 3, // Do not consider popup hierarchy (do not treat popup emitter as parent of popup) (when used with _ChildWindows or _RootWindow)
1439- //ImGuiFocusedFlags_DockHierarchy = 1 << 4, // Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow)
1488+ ImGuiFocusedFlags_DockHierarchy = 1 << 4, // Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow)
14401489 ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows,
14411490 };
14421491
@@ -1450,7 +1499,7 @@
14501499 ImGuiHoveredFlags_RootWindow = 1 << 1, // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy)
14511500 ImGuiHoveredFlags_AnyWindow = 1 << 2, // IsWindowHovered() only: Return true if any window is hovered
14521501 ImGuiHoveredFlags_NoPopupHierarchy = 1 << 3, // IsWindowHovered() only: Do not consider popup hierarchy (do not treat popup emitter as parent of popup) (when used with _ChildWindows or _RootWindow)
1453- //ImGuiHoveredFlags_DockHierarchy = 1 << 4, // IsWindowHovered() only: Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow)
1502+ ImGuiHoveredFlags_DockHierarchy = 1 << 4, // IsWindowHovered() only: Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow)
14541503 ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 5, // Return true even if a popup window is normally blocking access to this item/window
14551504 //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 6, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet.
14561505 ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 7, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns.
@@ -1480,6 +1529,27 @@
14801529 ImGuiHoveredFlags_NoSharedDelay = 1 << 17, // IsItemHovered() only: Disable shared delay system where moving from one item to the next keeps the previous timer for a short time (standard for tooltips with long delays)
14811530 };
14821531
1532+// Flags for ImGui::DockSpace(), shared/inherited by child nodes.
1533+// (Some flags can be applied to individual nodes directly)
1534+// FIXME-DOCK: Also see ImGuiDockNodeFlagsPrivate_ which may involve using the WIP and internal DockBuilder api.
1535+enum ImGuiDockNodeFlags_
1536+{
1537+ ImGuiDockNodeFlags_None = 0,
1538+ ImGuiDockNodeFlags_KeepAliveOnly = 1 << 0, // // Don't display the dockspace node but keep it alive. Windows docked into this dockspace node won't be undocked.
1539+ //ImGuiDockNodeFlags_NoCentralNode = 1 << 1, // // Disable Central Node (the node which can stay empty)
1540+ ImGuiDockNodeFlags_NoDockingOverCentralNode = 1 << 2, // // Disable docking over the Central Node, which will be always kept empty.
1541+ ImGuiDockNodeFlags_PassthruCentralNode = 1 << 3, // // Enable passthru dockspace: 1) DockSpace() will render a ImGuiCol_WindowBg background covering everything excepted the Central Node when empty. Meaning the host window should probably use SetNextWindowBgAlpha(0.0f) prior to Begin() when using this. 2) When Central Node is empty: let inputs pass-through + won't display a DockingEmptyBg background. See demo for details.
1542+ ImGuiDockNodeFlags_NoDockingSplit = 1 << 4, // // Disable other windows/nodes from splitting this node.
1543+ ImGuiDockNodeFlags_NoResize = 1 << 5, // Saved // Disable resizing node using the splitter/separators. Useful with programmatically setup dockspaces.
1544+ ImGuiDockNodeFlags_AutoHideTabBar = 1 << 6, // // Tab bar will automatically hide when there is a single window in the dock node.
1545+ ImGuiDockNodeFlags_NoUndocking = 1 << 7, // // Disable undocking this node.
1546+
1547+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1548+ ImGuiDockNodeFlags_NoSplit = ImGuiDockNodeFlags_NoDockingSplit, // Renamed in 1.90
1549+ ImGuiDockNodeFlags_NoDockingInCentralNode = ImGuiDockNodeFlags_NoDockingOverCentralNode, // Renamed in 1.90
1550+#endif
1551+};
1552+
14831553 // Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload()
14841554 enum ImGuiDragDropFlags_
14851555 {
@@ -1714,12 +1784,21 @@
17141784 ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct backend to not alter mouse cursor shape and visibility. Use if the backend cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead.
17151785 ImGuiConfigFlags_NoKeyboard = 1 << 6, // Instruct dear imgui to disable keyboard inputs and interactions. This is done by ignoring keyboard events and clearing existing states.
17161786
1787+ // [BETA] Docking
1788+ ImGuiConfigFlags_DockingEnable = 1 << 7, // Docking enable flags.
1789+
1790+ // [BETA] Viewports
1791+ // When using viewports it is recommended that your default value for ImGuiCol_WindowBg is opaque (Alpha=1.0) so transition to a viewport won't be noticeable.
1792+ ImGuiConfigFlags_ViewportsEnable = 1 << 10, // Viewport enable flags (require both ImGuiBackendFlags_PlatformHasViewports + ImGuiBackendFlags_RendererHasViewports set by the respective backends)
1793+
17171794 // [Unused] User storage (to allow your backend/engine to communicate to code that may be shared between multiple projects. Those flags are NOT used by core Dear ImGui)
17181795 ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware.
17191796 ImGuiConfigFlags_IsTouchScreen = 1 << 21, // Application is using a touch screen instead of a mouse.
17201797 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
17211798 ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavMoveSetMousePos
17221799 ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavCaptureKeyboard
1800+ ImGuiConfigFlags_DpiEnableScaleFonts = 1 << 14, // [moved/renamed in 1.92.0] -> use bool io.ConfigDpiScaleFonts
1801+ ImGuiConfigFlags_DpiEnableScaleViewports= 1 << 15, // [moved/renamed in 1.92.0] -> use bool io.ConfigDpiScaleViewports
17231802 #endif
17241803 };
17251804
@@ -1732,6 +1811,12 @@
17321811 ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Backend Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if io.ConfigNavMoveSetMousePos is set).
17331812 ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3, // Backend Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices.
17341813 ImGuiBackendFlags_RendererHasTextures = 1 << 4, // Backend Renderer supports ImTextureData requests to create/update/destroy textures. This enables incremental texture updates and texture reloads. See https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md for instructions on how to upgrade your custom backend.
1814+
1815+ // [BETA] Multi-Viewports
1816+ ImGuiBackendFlags_RendererHasViewports = 1 << 10, // Backend Renderer supports multiple viewports.
1817+ ImGuiBackendFlags_PlatformHasViewports = 1 << 11, // Backend Platform supports multiple viewports.
1818+ ImGuiBackendFlags_HasMouseHoveredViewport=1 << 12, // Backend Platform supports calling io.AddMouseViewportEvent() with the viewport under the mouse. IF POSSIBLE, ignore viewports with the ImGuiViewportFlags_NoInputs flag (Win32 backend, GLFW 3.30+ backend can do this, SDL backend cannot). If this cannot be done, Dear ImGui needs to use a flawed heuristic to find the viewport under.
1819+ ImGuiBackendFlags_HasParentViewport = 1 << 13, // Backend Platform supports honoring viewport->ParentViewport/ParentViewportId value, by applying the corresponding parent/child relationship at the Platform level. Child windows always appear in front of their parent window.
17351820 };
17361821
17371822 // Enumeration for PushStyleColor() / PopStyleColor()
@@ -1779,6 +1864,8 @@
17791864 ImGuiCol_TabDimmed, // Tab background, when tab-bar is unfocused & tab is unselected
17801865 ImGuiCol_TabDimmedSelected, // Tab background, when tab-bar is unfocused & tab is selected
17811866 ImGuiCol_TabDimmedSelectedOverline,//..horizontal overline, when tab-bar is unfocused & tab is selected
1867+ ImGuiCol_DockingPreview, // Preview overlay color when about to docking something
1868+ ImGuiCol_DockingEmptyBg, // Background color for empty node (e.g. CentralNode with no window docked into it)
17821869 ImGuiCol_PlotLines,
17831870 ImGuiCol_PlotLinesHovered,
17841871 ImGuiCol_PlotHistogram,
@@ -1854,6 +1941,8 @@
18541941 ImGuiStyleVar_TableAngledHeadersTextAlign,// ImVec2 TableAngledHeadersTextAlign
18551942 ImGuiStyleVar_TreeLinesSize, // float TreeLinesSize
18561943 ImGuiStyleVar_TreeLinesRounding, // float TreeLinesRounding
1944+ ImGuiStyleVar_MenuItemRounding, // float MenuItemRounding
1945+ ImGuiStyleVar_SelectableRounding, // float SelectableRounding
18571946 ImGuiStyleVar_DragDropTargetRounding, // float DragDropTargetRounding
18581947 ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign
18591948 ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign
@@ -1861,6 +1950,7 @@
18611950 ImGuiStyleVar_SeparatorTextBorderSize, // float SeparatorTextBorderSize
18621951 ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign
18631952 ImGuiStyleVar_SeparatorTextPadding, // ImVec2 SeparatorTextPadding
1953+ ImGuiStyleVar_DockingSeparatorSize, // float DockingSeparatorSize
18641954 ImGuiStyleVar_COUNT
18651955 };
18661956
@@ -2158,7 +2248,7 @@
21582248 // Sorting specification for one column of a table (sizeof == 12 bytes)
21592249 struct ImGuiTableColumnSortSpecs
21602250 {
2161- ImGuiID ColumnUserID; // User id of the column (if specified by a TableSetupColumn() call)
2251+ ImGuiID ColumnUserID; // User data for the column (if specified by a TableSetupColumn() call in the 'ImGuiID user_data' field). FIXME: Should be called 'UserData'..
21622252 ImS16 ColumnIndex; // Index of the column
21632253 ImS16 SortOrder; // Index within parent ImGuiTableSortSpecs (always stored in order starting from 0, tables sorted on a single criteria will always have a 0 here)
21642254 ImGuiSortDirection SortDirection; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending
@@ -2331,6 +2421,8 @@
23312421 ImGuiTreeNodeFlags TreeLinesFlags; // Default way to draw lines connecting TreeNode hierarchy. ImGuiTreeNodeFlags_DrawLinesNone or ImGuiTreeNodeFlags_DrawLinesFull or ImGuiTreeNodeFlags_DrawLinesToNodes.
23322422 float TreeLinesSize; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines.
23332423 float TreeLinesRounding; // Radius of lines connecting child nodes to the vertical line.
2424+ float MenuItemRounding; // Radius of MenuItem, BeginMenu rounding.
2425+ float SelectableRounding; // Radius of Selectable rounding. MODIFYING THIS IS DISCOURAGED. CONTIGUOUS SELECTIONS WILL NOT LOOK RIGHT. (#7589)
23342426 float DragDropTargetRounding; // Radius of the drag and drop target frame. When <0.0f: use FrameRounding.
23352427 float DragDropTargetBorderSize; // Thickness of the drag and drop target border.
23362428 float DragDropTargetPadding; // Size to expand the drag and drop target from actual target item size.
@@ -2338,12 +2430,15 @@
23382430 ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
23392431 ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered).
23402432 ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
2433+ float InputTextCursorSize; // Thickness of cursor/caret in InputText().
23412434 float SeparatorSize; // Thickness of border in Separator(). Must be >= 1.0f.
23422435 float SeparatorTextBorderSize; // Thickness of border in SeparatorText()
23432436 ImVec2 SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).
23442437 ImVec2 SeparatorTextPadding; // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.
23452438 ImVec2 DisplayWindowPadding; // Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen.
23462439 ImVec2 DisplaySafeAreaPadding; // Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).
2440+ bool DockingNodeHasCloseButton; // Docking node has their own CloseButton() to close all docked windows.
2441+ float DockingSeparatorSize; // Thickness of resizing border between docked windows
23472442 float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). We apply per-monitor DPI scaling over this scale. May be removed later.
23482443 bool AntiAliasedLines; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList).
23492444 bool AntiAliasedLinesUseTex; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). Latched at the beginning of the frame (copied to ImDrawList).
@@ -2428,6 +2523,26 @@
24282523 bool ConfigNavCursorVisibleAuto; // = true // Using directional navigation key makes the cursor visible. Mouse click hides the cursor.
24292524 bool ConfigNavCursorVisibleAlways; // = false // Navigation cursor is always visible.
24302525
2526+ // Docking options (when ImGuiConfigFlags_DockingEnable is set)
2527+ bool ConfigDockingNoSplit; // = false // Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.
2528+ bool ConfigDockingNoDockingOver; // = false // Simplified docking mode: disable window merging into a same tab-bar, so docking is limited to splitting windows.
2529+ bool ConfigDockingWithShift; // = false // Enable docking with holding Shift key (reduce visual noise, allows dropping in wider space)
2530+ bool ConfigDockingAlwaysTabBar; // = false // [BETA] [FIXME: This currently creates regression with auto-sizing and general overhead] Make every single floating window display within a docking node.
2531+ bool ConfigDockingTransparentPayload;// = false // [BETA] Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge.
2532+
2533+ // Viewport options (when ImGuiConfigFlags_ViewportsEnable is set)
2534+ // (sorry for the amount of "NoXXXX" flags, which may be harder to reason about! may rework someday)
2535+ bool ConfigViewportsNoAutoMerge; // = false; // Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it. May also set ImGuiViewportFlags_NoAutoMerge on individual viewport.
2536+ bool ConfigViewportsNoTaskBarIcon; // = false // Disable default OS task bar icon flag for secondary viewports. When a viewport doesn't want a task bar icon, ImGuiViewportFlags_NoTaskBarIcon will be set on it.
2537+ bool ConfigViewportsNoDecoration; // = true // Disable default OS window decoration flag for secondary viewports. When a viewport doesn't want window decorations, ImGuiViewportFlags_NoDecoration will be set on it. Enabling decoration can create subsequent issues at OS levels (e.g. minimum window size).
2538+ bool ConfigViewportsNoDefaultParent; // = true // Disable setting OS window parent to main viewport by default. The platform backend is expected to honor `viewport->ParentViewportID` to setup a parent/child relationship between the OS windows (supported if ImGuiBackendFlags_HasParentViewport is set). When parented: child windows always appear in front of their parent. Set to false if you want viewports to automatically be parent of main viewport, otherwise all viewports will be top-level OS windows. Parent/child relationship may be set on a per-window basis using ImGuiWindowClass.
2539+ bool ConfigViewportsPlatformFocusSetsImGuiFocus;//= true // When a platform window is focused (e.g. using Alt+Tab, clicking Platform Title Bar), apply corresponding focus on imgui windows (may clear focus/active id from imgui windows location in other platform windows). In principle this is better enabled but we provide an opt-out, because some Linux window managers tend to eagerly focus windows (e.g. on mouse hover, or even a simple window pos/size change).
2540+
2541+ // DPI/Scaling options
2542+ // This may keep evolving during 1.92.x releases. Expect some turbulence.
2543+ bool ConfigDpiScaleFonts; // = false // [EXPERIMENTAL] Automatically overwrite style.FontScaleDpi when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
2544+ bool ConfigDpiScaleViewports; // = false // [EXPERIMENTAL] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
2545+
24312546 // Miscellaneous options
24322547 // (you can visualize and interact with all options in 'Demo->Configuration')
24332548 bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations.
@@ -2525,6 +2640,7 @@
25252640 IMGUI_API void AddMouseButtonEvent(int button, bool down); // Queue a mouse button change
25262641 IMGUI_API void AddMouseWheelEvent(float wheel_x, float wheel_y); // Queue a mouse wheel update. wheel_y<0: scroll down, wheel_y>0: scroll up, wheel_x<0: scroll right, wheel_x>0: scroll left.
25272642 IMGUI_API void AddMouseSourceEvent(ImGuiMouseSource source); // Queue a mouse source change (Mouse/TouchScreen/Pen)
2643+ IMGUI_API void AddMouseViewportEvent(ImGuiID id); // Queue a mouse hovered viewport. Requires backend to set ImGuiBackendFlags_HasMouseHoveredViewport to call this (for multi-viewport support).
25282644 IMGUI_API void AddFocusEvent(bool focused); // Queue a gain/loss of focus for the application (generally based on OS/platform focus of your window)
25292645 IMGUI_API void AddInputCharacter(unsigned int c); // Queue a new character input
25302646 IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue a new character input from a UTF-16 character, it can be a surrogate
@@ -2570,6 +2686,7 @@
25702686 float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. >0 scrolls Up, <0 scrolls Down. Hold Shift to turn vertical scroll into horizontal scroll.
25712687 float MouseWheelH; // Mouse wheel Horizontal. >0 scrolls Left, <0 scrolls Right. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends.
25722688 ImGuiMouseSource MouseSource; // Mouse actual input peripheral (Mouse/TouchScreen/Pen).
2689+ ImGuiID MouseHoveredViewport; // (Optional) Modify using io.AddMouseViewportEvent(). With multi-viewports: viewport the OS mouse is hovering. If possible _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag is much better (few backends can handle that). Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. If you don't imgui will infer the value using the rectangles and last focused time of the viewports it knows about (ignoring other OS windows).
25732690 bool KeyCtrl; // Keyboard modifier down: Ctrl (non-macOS), Cmd (macOS)
25742691 bool KeyShift; // Keyboard modifier down: Shift
25752692 bool KeyAlt; // Keyboard modifier down: Alt
@@ -2594,6 +2711,7 @@
25942711 bool MouseCtrlLeftAsRightClick; // (OSX) Set to true when the current click was a Ctrl+Click that spawned a simulated right click
25952712 float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked)
25962713 float MouseDownDurationPrev[5]; // Previous time the mouse button has been down
2714+ ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point
25972715 float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds)
25982716 float PenPressure; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui.
25992717 bool AppFocusLost; // Only modify via AddFocusEvent()
@@ -2612,7 +2730,7 @@
26122730 //void* ImeWindowHandle; // [Obsoleted in 1.87] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning.
26132731
26142732 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
2615- float FontGlobalScale; // Moved io.FontGlobalScale to style.FontScaleMain in 1.92 (June 2025)
2733+ float FontGlobalScale; // Moved io.FontGlobalScale to style.FontScaleMain in 1.92.0 (June 2025)
26162734
26172735 // Legacy: before 1.91.1, clipboard functions were stored in ImGuiIO instead of ImGuiPlatformIO.
26182736 // As this is will affect all users of custom engines/backends, we are providing proper legacy redirection (will obsolete).
@@ -2684,6 +2802,29 @@
26842802 ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing.
26852803 };
26862804
2805+// [ALPHA] Rarely used / very advanced uses only. Use with SetNextWindowClass() and DockSpace() functions.
2806+// Important: the content of this class is still highly WIP and likely to change and be refactored
2807+// before we stabilize Docking features. Please be mindful if using this.
2808+// Provide hints:
2809+// - To the platform backend via altered viewport flags (enable/disable OS decoration, OS task bar icons, etc.)
2810+// - To the platform backend for OS level parent/child relationships of viewport (otherwise: default is configured via io.ConfigViewportsNoDefaultParent)
2811+// - To the docking system for various options and filtering.
2812+struct ImGuiWindowClass
2813+{
2814+ ImGuiID ClassId; // User data. 0 = Default class (unclassed). Windows of different classes cannot be docked with each others.
2815+ ImGuiID ParentViewportId; // Hint for the platform backend. -1: use default. 0: request platform backend to not parent the platform. != 0: request platform backend to create a parent<>child relationship between the platform windows. Not conforming backends are free to e.g. parent every viewport to the main viewport or not.
2816+ ImGuiID FocusRouteParentWindowId; // ID of parent window for shortcut focus route evaluation, e.g. Shortcut() call from Parent Window will succeed when this window is focused.
2817+ ImGuiViewportFlags ViewportFlagsOverrideSet; // Viewport flags to set when a window of this class owns a viewport. This allows you to enforce OS decoration or task bar icon, override the defaults on a per-window basis.
2818+ ImGuiViewportFlags ViewportFlagsOverrideClear; // Viewport flags to clear when a window of this class owns a viewport. This allows you to enforce OS decoration or task bar icon, override the defaults on a per-window basis.
2819+ ImGuiTabItemFlags TabItemFlagsOverrideSet; // [EXPERIMENTAL] TabItem flags to set when a window of this class gets submitted into a dock node tab bar. May use with ImGuiTabItemFlags_Leading or ImGuiTabItemFlags_Trailing.
2820+ ImGuiDockNodeFlags DockNodeFlagsOverrideSet; // [EXPERIMENTAL] Dock node flags to set when a window of this class is hosted by a dock node (it doesn't have to be selected!)
2821+ bool DockingAlwaysTabBar; // Set to true to enforce single floating windows of this class always having their own docking node (equivalent of setting the global io.ConfigDockingAlwaysTabBar)
2822+ bool DockingAllowUnclassed; // Set to true to allow windows of this class to be docked/merged with an unclassed window. // FIXME-DOCK: Move to DockNodeFlags override?
2823+ void* PlatformIconData; // [EXPERIMENTAL] Pass opaque data for Platform backend to handle.
2824+
2825+ ImGuiWindowClass() { memset((void*)this, 0, sizeof(*this)); ParentViewportId = (ImGuiID)-1; DockingAllowUnclassed = true; }
2826+};
2827+
26872828 // Data payload for Drag and Drop operations: AcceptDragDropPayload(), GetDragDropPayload()
26882829 struct ImGuiPayload
26892830 {
@@ -3049,6 +3190,7 @@
30493190 ImGuiMultiSelectFlags_NavWrapX = 1 << 16, // [Temporary] Enable navigation wrapping on X axis. Provided as a convenience because we don't have a design for the general Nav API for this yet. When the more general feature be public we may obsolete this flag in favor of new one.
30503191 ImGuiMultiSelectFlags_NoSelectOnRightClick = 1 << 17, // Disable default right-click processing, which selects item on mouse down, and is designed for context-menus.
30513192 ImGuiMultiSelectFlags_SelectOnMask_ = ImGuiMultiSelectFlags_SelectOnAuto | ImGuiMultiSelectFlags_SelectOnClickAlways | ImGuiMultiSelectFlags_SelectOnClickRelease,
3193+ ImGuiMultiSelectFlags_CheckboxMode_ = 1 << 20, // [Internal]
30523194
30533195 // Obsolete names
30543196 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
@@ -3245,20 +3387,27 @@
32453387 enum ImDrawFlags_
32463388 {
32473389 ImDrawFlags_None = 0,
3248- ImDrawFlags_RoundCornersTopLeft = 1 << 4, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-left corner only (when rounding > 0.0f, we default to all corners). Was 0x01.
3249- ImDrawFlags_RoundCornersTopRight = 1 << 5, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-right corner only (when rounding > 0.0f, we default to all corners). Was 0x02.
3250- ImDrawFlags_RoundCornersBottomLeft = 1 << 6, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-left corner only (when rounding > 0.0f, we default to all corners). Was 0x04.
3251- ImDrawFlags_RoundCornersBottomRight = 1 << 7, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-right corner only (when rounding > 0.0f, we default to all corners). Wax 0x08.
3252- ImDrawFlags_RoundCornersNone = 1 << 8, // AddRect(), AddRectFilled(), PathRect(): disable rounding on all corners (when rounding > 0.0f). This is NOT zero, NOT an implicit flag!
3253- ImDrawFlags_Closed = 1 << 9, // PathStroke(), AddPolyline(): specify that shape should be closed (Important: this is always == 1 for legacy reason)
3390+
3391+ // Rounding for AddRect(), AddRectFilled(), PathRect()
3392+ // - When not specified, we defaults to ImDrawFlags_RoundCornersAll! So you only need to use those flags if you want another configuration.
3393+ ImDrawFlags_RoundCornersTopLeft = 1 << 4, // Round top-left corner only (when rounding > 0.0f, we default to all corners).
3394+ ImDrawFlags_RoundCornersTopRight = 1 << 5, // Round top-right corner only (when rounding > 0.0f, we default to all corners).
3395+ ImDrawFlags_RoundCornersBottomLeft = 1 << 6, // Round bottom-left corner only (when rounding > 0.0f, we default to all corners).
3396+ ImDrawFlags_RoundCornersBottomRight = 1 << 7, // Round bottom-right corner only (when rounding > 0.0f, we default to all corners).
3397+ ImDrawFlags_RoundCornersNone = 1 << 8, // Disable rounding even if `float rounding > 0.0f`. This is NOT zero, NOT an implicit flag!
3398+ ImDrawFlags_RoundCornersAll = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, // (Default!!)
3399+ ImDrawFlags_RoundCornersDefault_ = ImDrawFlags_RoundCornersAll, // Default to ALL corners if none of the _RoundCornersXX flags are specified!
32543400 ImDrawFlags_RoundCornersTop = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight,
32553401 ImDrawFlags_RoundCornersBottom = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight,
32563402 ImDrawFlags_RoundCornersLeft = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersTopLeft,
32573403 ImDrawFlags_RoundCornersRight = ImDrawFlags_RoundCornersBottomRight | ImDrawFlags_RoundCornersTopRight,
3258- ImDrawFlags_RoundCornersAll = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight,
3259- ImDrawFlags_RoundCornersDefault_ = ImDrawFlags_RoundCornersAll, // Default to ALL corners if none of the _RoundCornersXX flags are specified.
32603404 ImDrawFlags_RoundCornersMask_ = ImDrawFlags_RoundCornersAll | ImDrawFlags_RoundCornersNone,
3261- ImDrawFlags_InvalidMask_ = (ImDrawFlags)0x8000000F,
3405+
3406+ // Stroke options
3407+ ImDrawFlags_Closed = 1 << 9, // PathStroke(), AddPolyline(): specify that shape should be closed.
3408+ //ImDrawFlags_Closed = 1 << 0, // Prior to 1.92.8 (May 2026), ImDrawFlags_Closed was guaranteed to be == 1<<0 == 1 for legacy compatibility reason. Hardcoded use of 1 or true should be replaced.
3409+
3410+ ImDrawFlags_InvalidMask_ = ~0x7FFFFFF0, // == 0x8000000F,
32623411 };
32633412
32643413 // Flags for ImDrawList instance. Those are set automatically by ImGui:: functions from ImGuiIO settings, and generally not manipulated directly.
@@ -3270,6 +3419,7 @@
32703419 ImDrawListFlags_AntiAliasedLinesUseTex = 1 << 1, // Enable anti-aliased lines/borders using textures when possible. Require backend to render with bilinear filtering (NOT point/nearest filtering).
32713420 ImDrawListFlags_AntiAliasedFill = 1 << 2, // Enable anti-aliased edge around filled shapes (rounded rectangles, circles).
32723421 ImDrawListFlags_AllowVtxOffset = 1 << 3, // Can emit 'VtxOffset > 0' to allow large meshes. Set when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled.
3422+ ImDrawListFlags_TextNoPixelSnap = 1 << 4, // Disable automatically snapping AddText() calls to pixel boundaries.
32733423 };
32743424
32753425 // Draw command list
@@ -3421,8 +3571,8 @@
34213571 inline void PushTextureID(ImTextureRef tex_ref) { PushTexture(tex_ref); } // RENAMED in 1.92.0
34223572 inline void PopTextureID() { PopTexture(); } // RENAMED in 1.92.0
34233573 #else
3424- IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding /*= 0.0f*/, ImDrawFlags flags /*= 0*/, float thickness /*= 1.0f*/) = delete;
3425- IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness) = delete;
3574+ void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding /*= 0.0f*/, ImDrawFlags flags /*= 0*/, float thickness /*= 1.0f*/) = delete;
3575+ void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness) = delete;
34263576 inline void PathStroke(ImU32 col, ImDrawFlags flags /*= 0*/, float thickness /*= 1.0f*/) = delete;
34273577 #endif
34283578 //inline void AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f) { AddEllipse(center, ImVec2(radius_x, radius_y), col, rot, num_segments, thickness); } // OBSOLETED in 1.90.5 (Mar 2024)
@@ -3503,7 +3653,7 @@
35033653 // You may use ImTextureData::Updates[] for the list, or ImTextureData::UpdateBox for a single bounding box.
35043654 struct ImTextureRect
35053655 {
3506- unsigned short x, y; // Upper-left coordinates of rectangle to update
3656+ unsigned short x, y; // Upper-left coordinates of rectangle to update, within the parent Pixels[] array.
35073657 unsigned short w, h; // Size of rectangle to update (in pixels)
35083658 };
35093659
@@ -3525,7 +3675,7 @@
35253675 int Width; // w r // Texture width
35263676 int Height; // w r // Texture height
35273677 int BytesPerPixel; // w r // 4 or 1
3528- unsigned char* Pixels; // w r // Pointer to buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes.
3678+ unsigned char* Pixels; // w r // Pointer to whole texture buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes.
35293679 ImTextureRect UsedRect; // w r // Bounding box encompassing all past and queued Updates[].
35303680 ImTextureRect UpdateRect; // w r // Bounding box encompassing all queued Updates[].
35313681 ImVector<ImTextureRect> Updates; // w r // Array of individual updates.
@@ -3535,7 +3685,7 @@
35353685 bool WantDestroyNextFrame; // rw - // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame.
35363686
35373687 // Functions
3538- // - If GetPixels() functions asserts while being called by your render loop, it could be caused by calling ImFontAtlas::Clear() instead of ClearFonts()?
3688+ // - If GetPixels() functions asserts while being called by your render loop, it could be caused by calling ImFontAtlas::Clear()/ClearFonts()?
35393689 ImTextureData() { memset((void*)this, 0, sizeof(*this)); Status = ImTextureStatus_Destroyed; TexID = ImTextureID_Invalid; }
35403690 ~ImTextureData() { DestroyPixels(); }
35413691 IMGUI_API void Create(ImTextureFormat format, int w, int h);
@@ -3689,14 +3839,16 @@
36893839 IMGUI_API ImFont* AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed.
36903840 IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_data_size, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp.
36913841 IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter.
3692- IMGUI_API void RemoveFont(ImFont* font);
3693-
3694- IMGUI_API void Clear(); // Clear everything (fonts + textures). Don't call mid-frame!
3695- IMGUI_API void ClearFonts(); // Clear input+output font data/glyphs. You can call this mid-frame if you load new fonts afterwards!
3696- IMGUI_API void CompactCache(); // Compact cached glyphs and texture.
3842+ IMGUI_API void RemoveFont(ImFont* font); // Remove a font
3843+ IMGUI_API void CompactCache(); // Compact cached glyphs and texture.
36973844 IMGUI_API void SetFontLoader(const ImFontLoader* font_loader); // Change font loader at runtime.
36983845
3699- // As we are transitioning toward a new font system, we expect to obsolete those soon:
3846+ // Clearing the atlas/fonts has little use nowadays, unless you want to batch remove all fonts.
3847+ // - Since 1.92, you can call ClearFonts() mid-frame, if you load new fonts afterwards.
3848+ // - As we are transitioning toward our new font system the semantic for those functions gets increasingly misleading and are often a source of issues.
3849+ // TL;DR; most likely, don't use any of those functions. We expect to obsolete/rework them.
3850+ IMGUI_API void Clear(); // Clear everything (fonts + textures). Don't call mid-frame!
3851+ IMGUI_API void ClearFonts(); // Clear input+output font data/glyphs. New fonts and textures will be recreated afterwards.
37003852 IMGUI_API void ClearInputData(); // [OBSOLETE] Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts.
37013853 IMGUI_API void ClearTexData(); // [OBSOLETE] Clear CPU-side copy of the texture data. Saves RAM once the texture has been copied to graphics memory.
37023854
@@ -3915,7 +4067,7 @@
39154067 IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip = NULL);
39164068 IMGUI_API void 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 = 0.0f, ImDrawTextFlags flags = 0);
39174069 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
3918- inline const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(LegacySize * scale, text, text_end, wrap_width); }
4070+ inline const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(LegacySize * scale, text, text_end, wrap_width); } // Obsoleted old name in 1.92.0. Note how `scale` was to `size`.
39194071 #endif
39204072
39214073 // [Internal] Don't use!
@@ -3954,11 +4106,24 @@
39544106 ImGuiViewportFlags_None = 0,
39554107 ImGuiViewportFlags_IsPlatformWindow = 1 << 0, // Represent a Platform Window
39564108 ImGuiViewportFlags_IsPlatformMonitor = 1 << 1, // Represent a Platform Monitor (unused yet)
3957- ImGuiViewportFlags_OwnedByApp = 1 << 2, // Platform Window: Is created/managed by the application (rather than a dear imgui backend)
4109+ ImGuiViewportFlags_OwnedByApp = 1 << 2, // Platform Window: Is created/managed by the user application? (rather than our backend)
4110+ ImGuiViewportFlags_NoDecoration = 1 << 3, // Platform Window: Disable platform decorations: title bar, borders, etc. (generally set all windows, but if ImGuiConfigFlags_ViewportsDecoration is set we only set this on popups/tooltips)
4111+ ImGuiViewportFlags_NoTaskBarIcon = 1 << 4, // Platform Window: Disable platform task bar icon (generally set on popups/tooltips, or all windows if ImGuiConfigFlags_ViewportsNoTaskBarIcon is set)
4112+ ImGuiViewportFlags_NoFocusOnAppearing = 1 << 5, // Platform Window: Don't take focus when created.
4113+ ImGuiViewportFlags_NoFocusOnClick = 1 << 6, // Platform Window: Don't take focus when clicked on.
4114+ ImGuiViewportFlags_NoInputs = 1 << 7, // Platform Window: Make mouse pass through so we can drag this window while peaking behind it.
4115+ ImGuiViewportFlags_NoRendererClear = 1 << 8, // Platform Window: Renderer doesn't need to clear the framebuffer ahead (because we will fill it entirely).
4116+ ImGuiViewportFlags_NoAutoMerge = 1 << 9, // Platform Window: Avoid merging this window into another host window. This can only be set via ImGuiWindowClass viewport flags override (because we need to now ahead if we are going to create a viewport in the first place!).
4117+ ImGuiViewportFlags_TopMost = 1 << 10, // Platform Window: Display on top (for tooltips only).
4118+ ImGuiViewportFlags_CanHostOtherWindows = 1 << 11, // Viewport can host multiple imgui windows (secondary viewports are associated to a single window). // FIXME: In practice there's still probably code making the assumption that this is always and only on the MainViewport. Will fix once we add support for "no main viewport".
4119+
4120+ // Output status flags (from Platform)
4121+ ImGuiViewportFlags_IsMinimized = 1 << 12, // Platform Window: Window is minimized, can skip render. When minimized we tend to avoid using the viewport pos/size for clipping window or testing if they are contained in the viewport.
4122+ ImGuiViewportFlags_IsFocused = 1 << 13, // Platform Window: Window is focused (last call to Platform_GetWindowFocus() returned true)
39584123 };
39594124
39604125 // - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows.
3961-// - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports.
4126+// - With multi-viewport enabled, we extend this concept to have multiple active viewports.
39624127 // - In the future we will extend this concept further to also represent Platform Monitor and support a "no main platform window" operation mode.
39634128 // - About Main Area vs Work Area:
39644129 // - Main Area = entire viewport.
@@ -3973,22 +4138,85 @@
39734138 ImVec2 FramebufferScale; // Density of the viewport for Retina display (always 1,1 on Windows, may be 2,2 etc on macOS/iOS). This will affect font rasterizer density.
39744139 ImVec2 WorkPos; // Work Area: Position of the viewport minus task bars, menus bars, status bars (>= Pos)
39754140 ImVec2 WorkSize; // Work Area: Size of the viewport minus task bars, menu bars, status bars (<= Size)
4141+ float DpiScale; // 1.0f = 96 DPI = No extra scale.
4142+ ImGuiID ParentViewportId; // (Advanced) 0: no parent. Instruct the platform backend to setup a parent/child relationship between platform windows.
4143+ ImGuiViewport* ParentViewport; // (Advanced) Direct shortcut to ImGui::FindViewportByID(ParentViewportId). NULL: no parent.
4144+ ImDrawData* DrawData; // The ImDrawData corresponding to this viewport. Valid after Render() and until the next call to NewFrame().
39764145
39774146 // Platform/Backend Dependent Data
3978- void* PlatformHandle; // void* to hold higher-level, platform window handle (e.g. HWND, GLFWWindow*, SDL_Window*)
3979- void* PlatformHandleRaw; // void* to hold lower-level, platform-native window handle (under Win32 this is expected to be a HWND, unused for other platforms)
4147+ // Our design separate the Renderer and Platform backends to facilitate combining default backends with each others.
4148+ // When our create your own backend for a custom engine, it is possible that both Renderer and Platform will be handled
4149+ // by the same system and you may not need to use all the UserData/Handle fields.
4150+ // The library never uses those fields, they are merely storage to facilitate backend implementation.
4151+ void* RendererUserData; // void* to hold custom data structure for the renderer (e.g. swap chain, framebuffers etc.). generally set by your Renderer_CreateWindow function.
4152+ void* PlatformUserData; // void* to hold custom data structure for the OS / platform (e.g. windowing info, render context). generally set by your Platform_CreateWindow function.
4153+ void* PlatformIconData; // void* to hold custom data structure for the OS / platform to specify an icon. Currently unused for exposed to allow experiments.
4154+ void* PlatformHandle; // void* to hold higher-level, platform window handle (e.g. HWND for Win32 backend, Uint32 WindowID for SDL, GLFWWindow* for GLFW), for FindViewportByPlatformHandle().
4155+ void* PlatformHandleRaw; // void* to hold lower-level, platform-native window handle (always HWND on Win32 platform, unused for other platforms).
4156+ bool PlatformWindowCreated; // Platform window has been created (Platform_CreateWindow() has been called). This is false during the first frame where a viewport is being created.
4157+ bool PlatformRequestMove; // Platform window requested move (e.g. window was moved by the OS / host window manager, authoritative position will be OS window position)
4158+ bool PlatformRequestResize; // Platform window requested resize (e.g. window was resized by the OS / host window manager, authoritative size will be OS window size)
4159+ bool PlatformRequestClose; // Platform window requested closure (e.g. window was moved by the OS / host window manager, e.g. pressing ALT-F4)
39804160
39814161 ImGuiViewport() { memset((void*)this, 0, sizeof(*this)); }
4162+ ~ImGuiViewport() { IM_ASSERT(PlatformUserData == NULL && RendererUserData == NULL); }
39824163
39834164 // Helpers
39844165 ImVec2 GetCenter() const { return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); }
39854166 ImVec2 GetWorkCenter() const { return ImVec2(WorkPos.x + WorkSize.x * 0.5f, WorkPos.y + WorkSize.y * 0.5f); }
4167+ IMGUI_API const char* GetDebugName() const;
39864168 };
39874169
39884170 //-----------------------------------------------------------------------------
3989-// [SECTION] Platform Dependent Interfaces
4171+// [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformMonitor, ImGuiPlatformImeData)
39904172 //-----------------------------------------------------------------------------
39914173
4174+// [BETA] (Optional) Multi-Viewport Support!
4175+// If you are new to Dear ImGui and trying to integrate it into your engine, you can probably ignore this for now.
4176+//
4177+// This feature allows you to seamlessly drag Dear ImGui windows outside of your application viewport.
4178+// This is achieved by creating new Platform/OS windows on the fly, and rendering into them.
4179+// Dear ImGui manages the viewport structures, and the backend create and maintain one Platform/OS window for each of those viewports.
4180+//
4181+// See Recap: https://github.com/ocornut/imgui/wiki/Multi-Viewports
4182+// See Glossary https://github.com/ocornut/imgui/wiki/Glossary for details about some of the terminology.
4183+//
4184+// About the coordinates system:
4185+// - When multi-viewports are enabled, all Dear ImGui coordinates become absolute coordinates (same as OS coordinates!)
4186+// - So e.g. ImGui::SetNextWindowPos(ImVec2(0,0)) will position a window relative to your primary monitor!
4187+// - If you want to position windows relative to your main application viewport, use ImGui::GetMainViewport()->Pos as a base position.
4188+//
4189+// Steps to use multi-viewports in your application, when using a default backend from the examples/ folder:
4190+// - Application: Enable feature with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
4191+// - Backend: The backend initialization will setup all necessary ImGuiPlatformIO's functions and update monitors info every frame.
4192+// - Application: In your main loop, call ImGui::UpdatePlatformWindows(), ImGui::RenderPlatformWindowsDefault() after EndFrame() or Render().
4193+// - Application: Fix absolute coordinates used in ImGui::SetWindowPos() or ImGui::SetNextWindowPos() calls.
4194+//
4195+// Steps to use multi-viewports in your application, when using a custom backend:
4196+// - Important: THIS IS NOT EASY TO DO and comes with many subtleties not described here!
4197+// It's also an experimental feature, so some of the requirements may evolve.
4198+// Consider using default backends if you can. Either way, carefully follow and refer to examples/ backends for details.
4199+// - Application: Enable feature with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
4200+// - Backend: Hook ImGuiPlatformIO's Platform_* and Renderer_* callbacks (see below).
4201+// Set 'io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports' and 'io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports'.
4202+// Update ImGuiPlatformIO's Monitors list every frame.
4203+// Update MousePos every frame, in absolute coordinates.
4204+// - Application: In your main loop, call ImGui::UpdatePlatformWindows(), ImGui::RenderPlatformWindowsDefault() after EndFrame() or Render().
4205+// You may skip calling RenderPlatformWindowsDefault() if its API is not convenient for your needs. Read comments below.
4206+// - Application: Fix absolute coordinates used in ImGui::SetWindowPos() or ImGui::SetNextWindowPos() calls.
4207+//
4208+// About ImGui::RenderPlatformWindowsDefault():
4209+// - This function is a mostly a _helper_ for the common-most cases, and to facilitate using default backends.
4210+// - You can check its simple source code to understand what it does.
4211+// It basically iterates secondary viewports and call 4 functions that are setup in ImGuiPlatformIO, if available:
4212+// Platform_RenderWindow(), Renderer_RenderWindow(), Platform_SwapBuffers(), Renderer_SwapBuffers()
4213+// Those functions pointers exists only for the benefit of RenderPlatformWindowsDefault().
4214+// - If you have very specific rendering needs (e.g. flipping multiple swap-chain simultaneously, unusual sync/threading issues, etc.),
4215+// you may be tempted to ignore RenderPlatformWindowsDefault() and write customized code to perform your renderingg.
4216+// You may decide to setup the platform_io's *RenderWindow and *SwapBuffers pointers and call your functions through those pointers,
4217+// or you may decide to never setup those pointers and call your code directly. They are a convenience, not an obligatory interface.
4218+//-----------------------------------------------------------------------------
4219+
39924220 // Access via ImGui::GetPlatformIO()
39934221 struct ImGuiPlatformIO
39944222 {
@@ -4037,6 +4265,56 @@
40374265 //ImDrawCallback DrawCallback_SetSamplerCustom; // Request backend to set texture sampling using Backend Specific data.
40384266
40394267 //------------------------------------------------------------------
4268+ // Input - Interface with Platform & Renderer backends for Multi-Viewport support
4269+ //------------------------------------------------------------------
4270+
4271+ // For reference, the second column shows which function are generally calling the Platform Functions:
4272+ // N = ImGui::NewFrame() ~ beginning of the dear imgui frame: read info from platform/OS windows (latest size/position)
4273+ // F = ImGui::Begin(), ImGui::EndFrame() ~ during the dear imgui frame
4274+ // U = ImGui::UpdatePlatformWindows() ~ after the dear imgui frame: create and update all platform/OS windows
4275+ // R = ImGui::RenderPlatformWindowsDefault() ~ render
4276+ // D = ImGui::DestroyPlatformWindows() ~ shutdown
4277+ // The general idea is that NewFrame() we will read the current Platform/OS state, and UpdatePlatformWindows() will write to it.
4278+
4279+ // The handlers are designed so we can mix and match two imgui_impl_xxxx files, one Platform backend and one Renderer backend.
4280+ // Custom engine backends will often provide both Platform and Renderer interfaces together and so may not need to use all functions.
4281+ // Platform functions are typically called _before_ their Renderer counterpart, apart from Destroy which are called the other way.
4282+
4283+ // Platform Backend functions (e.g. Win32, GLFW, SDL) ------------------- Called by -----
4284+ void (*Platform_CreateWindow)(ImGuiViewport* vp); // . . U . . // Create a new platform window for the given viewport
4285+ void (*Platform_DestroyWindow)(ImGuiViewport* vp); // N . U . D //
4286+ void (*Platform_ShowWindow)(ImGuiViewport* vp); // . . U . . // Newly created windows are initially hidden so SetWindowPos/Size/Title can be called on them before showing the window
4287+ void (*Platform_SetWindowPos)(ImGuiViewport* vp, ImVec2 pos); // . . U . . // Set platform window position (given the upper-left corner of client area)
4288+ ImVec2 (*Platform_GetWindowPos)(ImGuiViewport* vp); // N . . . . //
4289+ void (*Platform_SetWindowSize)(ImGuiViewport* vp, ImVec2 size); // . . U . . // Set platform window client area size (ignoring OS decorations such as OS title bar etc.)
4290+ ImVec2 (*Platform_GetWindowSize)(ImGuiViewport* vp); // N . . . . // Get platform window client area size
4291+ ImVec2 (*Platform_GetWindowFramebufferScale)(ImGuiViewport* vp); // N . . . . // Return viewport density. Always 1,1 on Windows, often 2,2 on Retina display on macOS/iOS. MUST BE INTEGER VALUES.
4292+ void (*Platform_SetWindowFocus)(ImGuiViewport* vp); // N . . . . // Move window to front and set input focus
4293+ bool (*Platform_GetWindowFocus)(ImGuiViewport* vp); // . . U . . //
4294+ bool (*Platform_GetWindowMinimized)(ImGuiViewport* vp); // N . . . . // Get platform window minimized state. When minimized, we generally won't attempt to get/set size and contents will be culled more easily
4295+ void (*Platform_SetWindowTitle)(ImGuiViewport* vp, const char* str); // . . U . . // Set platform window title (given an UTF-8 string)
4296+ void (*Platform_SetWindowAlpha)(ImGuiViewport* vp, float alpha); // . . U . . // (Optional) Setup global transparency (not per-pixel transparency)
4297+ void (*Platform_UpdateWindow)(ImGuiViewport* vp); // . . U . . // (Optional) Called by UpdatePlatformWindows(). Optional hook to allow the platform backend from doing general book-keeping every frame.
4298+ void (*Platform_RenderWindow)(ImGuiViewport* vp, void* render_arg); // . . . R . // (Optional) Main rendering (platform side! This is often unused, or just setting a "current" context for OpenGL bindings). 'render_arg' is the value passed to RenderPlatformWindowsDefault().
4299+ void (*Platform_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // . . . R . // (Optional) Call Present/SwapBuffers (platform side! This is often unused!). 'render_arg' is the value passed to RenderPlatformWindowsDefault().
4300+ float (*Platform_GetWindowDpiScale)(ImGuiViewport* vp); // N . . . . // (Optional) [BETA] FIXME-DPI: DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI.
4301+ void (*Platform_OnChangedViewport)(ImGuiViewport* vp); // . F . . . // (Optional) [BETA] FIXME-DPI: DPI handling: Called during Begin() every time the viewport we are outputting into changes, so backend has a chance to swap fonts to adjust style.
4302+ ImVec4 (*Platform_GetWindowWorkAreaInsets)(ImGuiViewport* vp); // N . . . . // (Optional) [BETA] Get initial work area inset for the viewport (won't be covered by main menu bar, dockspace over viewport etc.). Default to (0,0),(0,0). 'safeAreaInsets' in iOS land, 'DisplayCutout' in Android land.
4303+ int (*Platform_CreateVkSurface)(ImGuiViewport* vp, ImU64 vk_inst, const void* vk_allocators, ImU64* out_vk_surface); // (Optional) For a Vulkan Renderer to call into Platform code (since the surface creation needs to tie them both).
4304+
4305+ // Renderer Backend functions (e.g. DirectX, OpenGL, Vulkan) ------------ Called by -----
4306+ void (*Renderer_CreateWindow)(ImGuiViewport* vp); // . . U . . // Create swap chain, frame buffers etc. (called after Platform_CreateWindow)
4307+ void (*Renderer_DestroyWindow)(ImGuiViewport* vp); // N . U . D // Destroy swap chain, frame buffers etc. (called before Platform_DestroyWindow)
4308+ void (*Renderer_SetWindowSize)(ImGuiViewport* vp, ImVec2 size); // . . U . . // Resize swap chain, frame buffers etc. (called after Platform_SetWindowSize)
4309+ void (*Renderer_RenderWindow)(ImGuiViewport* vp, void* render_arg); // . . . R . // (Optional) Clear framebuffer, setup render target, then render the viewport->DrawData. 'render_arg' is the value passed to RenderPlatformWindowsDefault().
4310+ void (*Renderer_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // . . . R . // (Optional) Call Present/SwapBuffers. 'render_arg' is the value passed to RenderPlatformWindowsDefault().
4311+
4312+ // (Optional) Monitor list
4313+ // - Updated by: app/backend. Update every frame to dynamically support changing monitor or DPI configuration.
4314+ // - Used by: dear imgui to query DPI info, clamp popups/tooltips within same monitor and not have them straddle monitors.
4315+ ImVector<ImGuiPlatformMonitor> Monitors;
4316+
4317+ //------------------------------------------------------------------
40404318 // Output
40414319 //------------------------------------------------------------------
40424320
@@ -4044,12 +4322,27 @@
40444322 // The ImGui_ImplXXXX_RenderDrawData() function of each backend generally access this via ImDrawData::Textures which points to this. The array is available here mostly because backends will want to destroy textures on shutdown.
40454323 ImVector<ImTextureData*> Textures; // List of textures used by Dear ImGui (most often 1) + contents of external texture list is automatically appended into this.
40464324
4325+ // Viewports list (the list is updated by calling ImGui::EndFrame or ImGui::Render)
4326+ // (in the future we will attempt to organize this feature to remove the need for a "main viewport")
4327+ ImVector<ImGuiViewport*> Viewports; // Main viewports, followed by all secondary viewports.
4328+
40474329 //------------------------------------------------------------------
40484330 // Functions
40494331 //------------------------------------------------------------------
40504332
40514333 IMGUI_API void ClearPlatformHandlers(); // Clear all Platform_XXX fields. Typically called on Platform Backend shutdown.
40524334 IMGUI_API void ClearRendererHandlers(); // Clear all Renderer_XXX fields. Typically called on Renderer Backend shutdown.
4335+};
4336+
4337+// (Optional) This is required when enabling multi-viewport. Represent the bounds of each connected monitor/display and their DPI.
4338+// We use this information for multiple DPI support + clamping the position of popups and tooltips so they don't straddle multiple monitors.
4339+struct ImGuiPlatformMonitor
4340+{
4341+ ImVec2 MainPos, MainSize; // Coordinates of the area displayed on this monitor (Min = upper left, Max = bottom right)
4342+ ImVec2 WorkPos, WorkSize; // Coordinates without task bars / side bars / menu bars. Used to avoid positioning popups/tooltips inside this region. If you don't have this info, please copy the value for MainPos/MainSize.
4343+ float DpiScale; // 1.0f = 96 DPI
4344+ void* PlatformHandle; // Backend dependant data (e.g. HMONITOR, GLFWmonitor*, SDL Display Index, NSScreen*)
4345+ ImGuiPlatformMonitor() { MainPos = MainSize = WorkPos = WorkSize = ImVec2(0, 0); DpiScale = 1.0f; PlatformHandle = NULL; }
40534346 };
40544347
40554348 // (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function. Handler is called during EndFrame().
@@ -1,4 +1,4 @@
1-// dear imgui, v1.92.8
1+// dear imgui, v1.92.9 WIP
22 // (demo code)
33
44 // Help:
@@ -120,6 +120,7 @@
120120 // [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
121121 // [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles()
122122 // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
123+// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
123124 // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
124125 // [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser()
125126
@@ -239,6 +240,7 @@
239240 static void ShowExampleAppAssetsBrowser(bool* p_open);
240241 static void ShowExampleAppConsole(bool* p_open);
241242 static void ShowExampleAppCustomRendering(bool* p_open);
243+static void ShowExampleAppDockSpace(bool* p_open);
242244 static void ShowExampleAppDocuments(bool* p_open);
243245 static void ShowExampleAppImageViewer(bool* p_open);
244246 static void ShowExampleAppLog(bool* p_open);
@@ -285,6 +287,16 @@
285287 }
286288 }
287289
290+static void ShowDockingDisabledMessage()
291+{
292+ ImGuiIO& io = ImGui::GetIO();
293+ ImGui::Text("ERROR: Docking is not enabled! See Demo > Configuration.");
294+ ImGui::Text("Set io.ConfigFlags |= ImGuiConfigFlags_DockingEnable in your code, or ");
295+ ImGui::SameLine(0.0f, 0.0f);
296+ if (ImGui::SmallButton("click here"))
297+ io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
298+}
299+
288300 // Helper to wire demo markers located in code to an interactive browser (e.g. https://pthom.github.io/imgui_explorer)
289301 #if IMGUI_VERSION_NUM >= 19263
290302 namespace ImGui { extern IMGUI_API void DemoMarker(const char* file, int line, const char* section); }
@@ -311,6 +323,7 @@
311323 bool ShowAppConsole = false;
312324 bool ShowAppCustomRendering = false;
313325 bool ShowAppDocuments = false;
326+ bool ShowAppDockSpace = false;
314327 bool ShowAppImageViewer = false;
315328 bool ShowAppLog = false;
316329 bool ShowAppLayout = false;
@@ -353,7 +366,8 @@
353366
354367 // Examples Apps (accessible from the "Examples" menu)
355368 if (demo_data.ShowMainMenuBar) { ShowExampleAppMainMenuBar(); }
356- if (demo_data.ShowAppDocuments) { ShowExampleAppDocuments(&demo_data.ShowAppDocuments); }
369+ if (demo_data.ShowAppDockSpace) { ShowExampleAppDockSpace(&demo_data.ShowAppDockSpace); } // Important: Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function)
370+ if (demo_data.ShowAppDocuments) { ShowExampleAppDocuments(&demo_data.ShowAppDocuments); } // ...process the Document app next, as it may also use a DockSpace()
357371 if (demo_data.ShowAppAssetsBrowser) { ShowExampleAppAssetsBrowser(&demo_data.ShowAppAssetsBrowser); }
358372 if (demo_data.ShowAppConsole) { ShowExampleAppConsole(&demo_data.ShowAppConsole); }
359373 if (demo_data.ShowAppCustomRendering) { ShowExampleAppCustomRendering(&demo_data.ShowAppCustomRendering); }
@@ -391,6 +405,7 @@
391405 static bool no_nav = false;
392406 static bool no_background = false;
393407 static bool no_bring_to_front = false;
408+ static bool no_docking = false;
394409 static bool unsaved_document = false;
395410
396411 ImGuiWindowFlags window_flags = 0;
@@ -403,6 +418,7 @@
403418 if (no_nav) window_flags |= ImGuiWindowFlags_NoNav;
404419 if (no_background) window_flags |= ImGuiWindowFlags_NoBackground;
405420 if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
421+ if (no_docking) window_flags |= ImGuiWindowFlags_NoDocking;
406422 if (unsaved_document) window_flags |= ImGuiWindowFlags_UnsavedDocument;
407423 if (no_close) p_open = NULL; // Don't pass our bool* to Begin
408424
@@ -518,6 +534,54 @@
518534 ImGui::Checkbox("io.ConfigNavCursorVisibleAlways", &io.ConfigNavCursorVisibleAlways);
519535 ImGui::SameLine(); HelpMarker("Navigation cursor is always visible.");
520536
537+ ImGui::SeparatorText("Docking");
538+ ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", &io.ConfigFlags, ImGuiConfigFlags_DockingEnable);
539+ ImGui::SameLine();
540+ if (io.ConfigDockingWithShift)
541+ HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to enable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).");
542+ else
543+ HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).");
544+ if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
545+ {
546+ ImGui::Indent();
547+ ImGui::Checkbox("io.ConfigDockingNoSplit", &io.ConfigDockingNoSplit);
548+ ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.");
549+ ImGui::Checkbox("io.ConfigDockingNoDockingOver", &io.ConfigDockingNoDockingOver);
550+ ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window merging into a same tab-bar, so docking is limited to splitting windows.");
551+ ImGui::Checkbox("io.ConfigDockingWithShift", &io.ConfigDockingWithShift);
552+ ImGui::SameLine(); HelpMarker("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)");
553+ ImGui::Checkbox("io.ConfigDockingAlwaysTabBar", &io.ConfigDockingAlwaysTabBar);
554+ ImGui::SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows.");
555+ ImGui::Checkbox("io.ConfigDockingTransparentPayload", &io.ConfigDockingTransparentPayload);
556+ ImGui::SameLine(); HelpMarker("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge.");
557+ ImGui::Unindent();
558+ }
559+
560+ ImGui::SeparatorText("Multi-viewports");
561+ ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", &io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable);
562+ ImGui::SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.");
563+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
564+ {
565+ ImGui::Indent();
566+ ImGui::Checkbox("io.ConfigViewportsNoAutoMerge", &io.ConfigViewportsNoAutoMerge);
567+ ImGui::SameLine(); HelpMarker("Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it.");
568+ ImGui::Checkbox("io.ConfigViewportsNoTaskBarIcon", &io.ConfigViewportsNoTaskBarIcon);
569+ ImGui::SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)");
570+ ImGui::Checkbox("io.ConfigViewportsNoDecoration", &io.ConfigViewportsNoDecoration);
571+ ImGui::SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)");
572+ ImGui::Checkbox("io.ConfigViewportsNoDefaultParent", &io.ConfigViewportsNoDefaultParent);
573+ ImGui::SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)");
574+ ImGui::Checkbox("io.ConfigViewportsPlatformFocusSetsImGuiFocus", &io.ConfigViewportsPlatformFocusSetsImGuiFocus);
575+ ImGui::SameLine(); HelpMarker("When a platform window is focused (e.g. using Alt+Tab, clicking Platform Title Bar), apply corresponding focus on imgui windows (may clear focus/active id from imgui windows location in other platform windows). In principle this is better enabled but we provide an opt-out, because some Linux window managers tend to eagerly focus windows (e.g. on mouse hover, or even a simple window pos/size change).");
576+ ImGui::Unindent();
577+ }
578+
579+ //ImGui::SeparatorText("DPI/Scaling");
580+ //ImGui::Checkbox("io.ConfigDpiScaleFonts", &io.ConfigDpiScaleFonts);
581+ //ImGui::SameLine(); HelpMarker("Experimental: Automatically update style.FontScaleDpi when Monitor DPI changes. This will scale fonts but NOT style sizes/padding for now.");
582+ //ImGui::Checkbox("io.ConfigDpiScaleViewports", &io.ConfigDpiScaleViewports);
583+ //ImGui::SameLine(); HelpMarker("Experimental: Scale Dear ImGui and Platform Windows when Monitor DPI changes.");
584+
521585 ImGui::SeparatorText("Windows");
522586 ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
523587 ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback.");
@@ -583,13 +647,18 @@
583647 "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n"
584648 "Here we expose them as read-only fields to avoid breaking interactions with your backend.");
585649
650+ // Make a local copy to avoid modifying actual backend flags.
586651 // FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright?
587652 ImGui::BeginDisabled();
588- ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &io.BackendFlags, ImGuiBackendFlags_HasGamepad);
589- ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
590- ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos);
591- ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset);
592- ImGui::CheckboxFlags("io.BackendFlags: RendererHasTextures", &io.BackendFlags, ImGuiBackendFlags_RendererHasTextures);
653+ ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &io.BackendFlags, ImGuiBackendFlags_HasGamepad);
654+ ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
655+ ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos);
656+ ImGui::CheckboxFlags("io.BackendFlags: PlatformHasViewports", &io.BackendFlags, ImGuiBackendFlags_PlatformHasViewports);
657+ ImGui::CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport",&io.BackendFlags, ImGuiBackendFlags_HasMouseHoveredViewport);
658+ ImGui::CheckboxFlags("io.BackendFlags: HasParentViewport", &io.BackendFlags, ImGuiBackendFlags_HasParentViewport);
659+ ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset);
660+ ImGui::CheckboxFlags("io.BackendFlags: RendererHasTextures", &io.BackendFlags, ImGuiBackendFlags_RendererHasTextures);
661+ ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports", &io.BackendFlags, ImGuiBackendFlags_RendererHasViewports);
593662 ImGui::EndDisabled();
594663
595664 ImGui::TreePop();
@@ -641,6 +710,7 @@
641710 ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav);
642711 ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background);
643712 ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front);
713+ ImGui::TableNextColumn(); ImGui::Checkbox("No docking", &no_docking);
644714 ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document);
645715 ImGui::EndTable();
646716 }
@@ -682,6 +752,7 @@
682752 ImGui::MenuItem("Console", NULL, &demo_data->ShowAppConsole);
683753 ImGui::MenuItem("Custom rendering", NULL, &demo_data->ShowAppCustomRendering);
684754 ImGui::MenuItem("Documents", NULL, &demo_data->ShowAppDocuments);
755+ ImGui::MenuItem("Dockspace", NULL, &demo_data->ShowAppDockSpace);
685756 ImGui::MenuItem("Image Viewer", NULL, &demo_data->ShowAppImageViewer);
686757 ImGui::MenuItem("Log", NULL, &demo_data->ShowAppLog);
687758 ImGui::MenuItem("Property editor", NULL, &demo_data->ShowAppPropertyEditor);
@@ -2299,18 +2370,24 @@
22992370 "IsWindowFocused() = %d\n"
23002371 "IsWindowFocused(_ChildWindows) = %d\n"
23012372 "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n"
2373+ "IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\n"
23022374 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
23032375 "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2376+ "IsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
23042377 "IsWindowFocused(_RootWindow) = %d\n"
23052378 "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n"
2379+ "IsWindowFocused(_RootWindow|_DockHierarchy) = %d\n"
23062380 "IsWindowFocused(_AnyWindow) = %d\n",
23072381 ImGui::IsWindowFocused(),
23082382 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
23092383 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy),
2384+ ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_DockHierarchy),
23102385 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
23112386 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2387+ ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
23122388 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
23132389 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2390+ ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
23142391 ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
23152392
23162393 // Testing IsWindowHovered() function with its various flags.
@@ -2320,10 +2397,13 @@
23202397 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
23212398 "IsWindowHovered(_ChildWindows) = %d\n"
23222399 "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n"
2400+ "IsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n"
23232401 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
23242402 "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2403+ "IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
23252404 "IsWindowHovered(_RootWindow) = %d\n"
23262405 "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n"
2406+ "IsWindowHovered(_RootWindow|_DockHierarchy) = %d\n"
23272407 "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n"
23282408 "IsWindowHovered(_AnyWindow) = %d\n"
23292409 "IsWindowHovered(_Stationary) = %d\n",
@@ -2332,10 +2412,13 @@
23322412 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
23332413 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
23342414 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy),
2415+ ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_DockHierarchy),
23352416 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
23362417 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2418+ ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
23372419 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
23382420 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2421+ ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
23392422 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup),
23402423 ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow),
23412424 ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary));
@@ -2348,10 +2431,13 @@
23482431
23492432 // Calling IsItemHovered() after begin returns the hovered status of the title bar.
23502433 // This is useful in particular if you want to create a context menu associated to the title bar of a window.
2434+ // This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties).
23512435 static bool test_window = false;
23522436 ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
23532437 if (test_window)
23542438 {
2439+ // FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck.
2440+ // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"?
23552441 ImGui::Begin("Title bar Hovered/Active tests", &test_window);
23562442 if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered()
23572443 {
@@ -4121,7 +4207,7 @@
41214207 ImGui::BeginDisabled();
41224208 ImGui::Button("Disabled item", sz);
41234209 if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
4124- ImGui::SetTooltip("I am a a tooltip for a disabled item.");
4210+ ImGui::SetTooltip("I am a tooltip for a disabled item.");
41254211 ImGui::EndDisabled();
41264212
41274213 ImGui::TreePop();
@@ -4138,9 +4224,9 @@
41384224 {
41394225 IMGUI_DEMO_MARKER("Widgets/Tree Nodes");
41404226 // See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven tree.
4141- if (ImGui::TreeNode("Basic trees"))
4227+ if (ImGui::TreeNode("Basic Trees"))
41424228 {
4143- IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees");
4229+ IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic Trees");
41444230 for (int i = 0; i < 5; i++)
41454231 {
41464232 // Use SetNextItemOpen() so set the default state of a node to be open. We could
@@ -4164,9 +4250,9 @@
41644250 ImGui::TreePop();
41654251 }
41664252
4167- if (ImGui::TreeNode("Hierarchy lines"))
4253+ if (ImGui::TreeNode("Hierarchy Lines"))
41684254 {
4169- IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Hierarchy lines");
4255+ IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Hierarchy Lines");
41704256 static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DefaultOpen;
41714257 HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags");
41724258 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", &base_flags, ImGuiTreeNodeFlags_DrawLinesNone);
@@ -4203,15 +4289,57 @@
42034289 ImGui::TreePop();
42044290 }
42054291
4206- if (ImGui::TreeNode("Advanced, with Selectable nodes"))
4292+ if (ImGui::TreeNode("Selectable Nodes"))
42074293 {
4208- IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes");
4294+ IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Selectable Nodes");
42094295 HelpMarker(
4210- "This is a more typical looking tree with selectable nodes.\n"
4211- "Click to select, Ctrl+Click to toggle, click on arrows or double-click to open.");
4296+ "Manually implemented selectable nodes.\n"
4297+ "Click to select, Ctrl+Click to toggle, click on arrows or double-click to open.\n\n"
4298+ "You may also use the multi-select API (see 'Demo->Widgets->Selection State & Multi-Select') for more advanced multi-selection features.");
4299+
4300+ // Hold in 'selection_mask' a simple representation of what may be user-side selection state.
4301+ // - You may retain selection state inside or outside your objects in whatever format you see fit.
4302+ // You may use ImGuiSelectionBasicStorage which is conceptually close to a set<> of identifiers.
4303+ // - We record which node was clicked and then apply selection at the end of the loop.
4304+ // - This is a manual and simplified reimplementation of multi-selection, which the full
4305+ // BeginMultiSelect() API implements better, but which is not trivial to wire for trees.
4306+ static int selection_mask = 0x00;
4307+ int node_clicked_idx = -1;
4308+ for (int node_n = 0; node_n < 6; node_n++)
4309+ {
4310+ // Disable the default "open on single-click behavior" + set Selected flag according to our selection.
4311+ // To alter selection we use if 'IsItemClicked() && !IsItemToggledOpen()', so clicking on an arrow doesn't alter selection.
4312+ // In a BeginMultiSelect()/EndMultiSelect() we could use IsItemToggledSelection() but here we reimplement and use our own logic.
4313+ ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
4314+ if (selection_mask & (1 << node_n))
4315+ flags |= ImGuiTreeNodeFlags_Selected;
4316+
4317+ bool is_open = ImGui::TreeNodeEx((void*)(intptr_t)node_n, flags, "Selectable Node %d", node_n);
4318+ if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
4319+ node_clicked_idx = node_n;
4320+ if (is_open)
4321+ {
4322+ ImGui::BulletText("<Node contents here>");
4323+ ImGui::TreePop();
4324+ }
4325+ }
4326+ if (node_clicked_idx != -1)
4327+ {
4328+ // Update selection state (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
4329+ if (ImGui::GetIO().KeyCtrl)
4330+ selection_mask ^= (1 << node_clicked_idx); // Ctrl+Click to toggle
4331+ else //if (!(selection_mask & (1 << node_clicked_idx))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection
4332+ selection_mask = (1 << node_clicked_idx); // Click to single-select
4333+ }
4334+ ImGui::TreePop();
4335+ }
4336+
4337+ if (ImGui::TreeNode("Advanced"))
4338+ {
4339+ IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced");
42124340 static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
42134341 static bool align_label_with_current_x_position = false;
4214- static bool test_drag_and_drop = false;
4342+ static bool use_drag_and_drop = false;
42154343 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow);
42164344 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
42174345 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node.");
@@ -4229,44 +4357,30 @@
42294357 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, ImGuiTreeNodeFlags_DrawLinesToNodes);
42304358
42314359 ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
4232- ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
4233- ImGui::Text("Hello!");
4360+ ImGui::Checkbox("Make Tree Nodes as drag & drop sources", &use_drag_and_drop);
42344361 if (align_label_with_current_x_position)
42354362 ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
42364363
4237- // 'selection_mask' is dumb representation of what may be user-side selection state.
4238- // You may retain selection state inside or outside your objects in whatever format you see fit.
4239- // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end
4240- /// of the loop. May be a pointer to your own node type, etc.
4241- static int selection_mask = (1 << 2);
4242- int node_clicked = -1;
4243- for (int i = 0; i < 6; i++)
4364+ for (int node_n = 0; node_n < 6; node_n++)
42444365 {
4245- // Disable the default "open on single-click behavior" + set Selected flag according to our selection.
4246- // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection.
42474366 ImGuiTreeNodeFlags node_flags = base_flags;
4248- const bool is_selected = (selection_mask & (1 << i)) != 0;
4249- if (is_selected)
4250- node_flags |= ImGuiTreeNodeFlags_Selected;
4251- if (i < 3)
4367+ if (node_n < 3)
42524368 {
42534369 // Items 0..2 are Tree Node
4254- bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
4255- if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
4256- node_clicked = i;
4257- if (test_drag_and_drop && ImGui::BeginDragDropSource())
4370+ bool is_open = ImGui::TreeNodeEx((void*)(intptr_t)node_n, node_flags, "Selectable Node %d", node_n);
4371+ if (use_drag_and_drop && ImGui::BeginDragDropSource())
42584372 {
4259- ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
4373+ ImGui::SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", NULL, 0);
42604374 ImGui::Text("This is a drag and drop source");
42614375 ImGui::EndDragDropSource();
42624376 }
4263- if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanLabelWidth))
4377+ if (node_n == 2 && (base_flags & ImGuiTreeNodeFlags_SpanLabelWidth))
42644378 {
42654379 // Item 2 has an additional inline button to help demonstrate SpanLabelWidth.
42664380 ImGui::SameLine();
42674381 if (ImGui::SmallButton("button")) {}
42684382 }
4269- if (node_open)
4383+ if (is_open)
42704384 {
42714385 ImGui::BulletText("Blah blah\nBlah Blah");
42724386 ImGui::SameLine();
@@ -4280,26 +4394,15 @@
42804394 // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can
42814395 // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text().
42824396 node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
4283- ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
4284- if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
4285- node_clicked = i;
4286- if (test_drag_and_drop && ImGui::BeginDragDropSource())
4397+ ImGui::TreeNodeEx((void*)(intptr_t)node_n, node_flags, "Selectable Leaf %d", node_n);
4398+ if (use_drag_and_drop && ImGui::BeginDragDropSource())
42874399 {
4288- ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
4400+ ImGui::SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", NULL, 0);
42894401 ImGui::Text("This is a drag and drop source");
42904402 ImGui::EndDragDropSource();
42914403 }
42924404 }
42934405 }
4294- if (node_clicked != -1)
4295- {
4296- // Update selection state
4297- // (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
4298- if (ImGui::GetIO().KeyCtrl)
4299- selection_mask ^= (1 << node_clicked); // Ctrl+Click to toggle
4300- else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection
4301- selection_mask = (1 << node_clicked); // Click to single-select
4302- }
43034406 if (align_label_with_current_x_position)
43044407 ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
43054408 ImGui::TreePop();
@@ -8333,6 +8436,12 @@
83338436 ImGui::Text("Emscripten: %d.%d.%d", __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__);
83348437 #endif
83358438 #endif
8439+#ifdef IMGUI_HAS_VIEWPORT
8440+ ImGui::Text("define: IMGUI_HAS_VIEWPORT");
8441+#endif
8442+#ifdef IMGUI_HAS_DOCK
8443+ ImGui::Text("define: IMGUI_HAS_DOCK");
8444+#endif
83368445 #ifdef NDEBUG
83378446 ImGui::Text("define: NDEBUG");
83388447 #endif
@@ -8361,7 +8470,20 @@
83618470 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse");
83628471 if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange");
83638472 if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard) ImGui::Text(" NoKeyboard");
8473+ if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) ImGui::Text(" DockingEnable");
8474+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui::Text(" ViewportsEnable");
83648475 if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor");
8476+ if (io.ConfigDpiScaleFonts) ImGui::Text("io.ConfigDpiScaleFonts");
8477+ if (io.ConfigDpiScaleViewports) ImGui::Text("io.ConfigDpiScaleViewports");
8478+ if (io.ConfigViewportsNoAutoMerge) ImGui::Text("io.ConfigViewportsNoAutoMerge");
8479+ if (io.ConfigViewportsNoTaskBarIcon) ImGui::Text("io.ConfigViewportsNoTaskBarIcon");
8480+ if (io.ConfigViewportsNoDecoration) ImGui::Text("io.ConfigViewportsNoDecoration");
8481+ if (io.ConfigViewportsNoDefaultParent) ImGui::Text("io.ConfigViewportsNoDefaultParent");
8482+ if (io.ConfigDockingNoSplit) ImGui::Text("io.ConfigDockingNoSplit");
8483+ if (io.ConfigDockingNoDockingOver) ImGui::Text("io.ConfigDockingNoDockingOver");
8484+ if (io.ConfigDockingWithShift) ImGui::Text("io.ConfigDockingWithShift");
8485+ if (io.ConfigDockingAlwaysTabBar) ImGui::Text("io.ConfigDockingAlwaysTabBar");
8486+ if (io.ConfigDockingTransparentPayload) ImGui::Text("io.ConfigDockingTransparentPayload");
83658487 if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors");
83668488 if (io.ConfigNavMoveSetMousePos) ImGui::Text("io.ConfigNavMoveSetMousePos");
83678489 if (io.ConfigNavCaptureKeyboard) ImGui::Text("io.ConfigNavCaptureKeyboard");
@@ -8373,8 +8495,12 @@
83738495 if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad");
83748496 if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors");
83758497 if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos");
8498+ if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) ImGui::Text(" PlatformHasViewports");
8499+ if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)ImGui::Text(" HasMouseHoveredViewport");
8500+ if (io.BackendFlags & ImGuiBackendFlags_HasParentViewport) ImGui::Text(" HasParentViewport");
83768501 if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset");
83778502 if (io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) ImGui::Text(" RendererHasTextures");
8503+ if (io.BackendFlags & ImGuiBackendFlags_RendererHasViewports) ImGui::Text(" RendererHasViewports");
83788504 ImGui::Separator();
83798505 ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexData->Width, io.Fonts->TexData->Height);
83808506 ImGui::Text("io.Fonts->FontLoaderName: %s", io.Fonts->FontLoaderName ? io.Fonts->FontLoaderName : "NULL");
@@ -8487,10 +8613,10 @@
84878613 style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work.
84888614 SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize());
84898615 DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 4.0f);
8490- //BeginDisabled(GetIO().ConfigDpiScaleFonts);
8616+ BeginDisabled(GetIO().ConfigDpiScaleFonts);
84918617 DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 4.0f);
8492- //SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten.");
8493- //EndDisabled();
8618+ SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten.");
8619+ EndDisabled();
84948620
84958621 // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f)
84968622 if (SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
@@ -8539,6 +8665,8 @@
85398665 SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
85408666 SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
85418667 SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
8668+ SliderFloat("MenuItemRounding", &style.MenuItemRounding, 0.0f, 12.0f, "%.0f");
8669+ // NB: SelectableRounding is intentionally NOT made visible here. We don't want to encourage people using that.
85428670
85438671 SeparatorText("Scrollbar");
85448672 SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
@@ -8598,6 +8726,11 @@
85988726 SliderFloat("ImageRounding", &style.ImageRounding, 0.0f, 12.0f, "%.0f");
85998727 SliderFloat("ImageBorderSize", &style.ImageBorderSize, 0.0f, max_border_size, "%.0f");
86008728
8729+ SeparatorText("Docking");
8730+ //SetCursorPosX(GetCursorPosX() + CalcItemWidth() - GetFrameHeight());
8731+ Checkbox("DockingNodeHasCloseButton", &style.DockingNodeHasCloseButton);
8732+ SliderFloat("DockingSeparatorSize", &style.DockingSeparatorSize, 0.0f, 12.0f, "%.0f");
8733+
86018734 SeparatorText("Tooltips");
86028735 for (int n = 0; n < 2; n++)
86038736 if (TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav"))
@@ -9985,6 +10118,8 @@
998510118 else
998610119 {
998710120 ImGui::Text("(Hold Shift to display a dummy viewport)");
10121+ if (ImGui::IsWindowDocked())
10122+ ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!");
998810123 if (ImGui::Button("Set 200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
998910124 if (ImGui::Button("Set 500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
999010125 if (ImGui::Button("Set 800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
@@ -10011,7 +10146,7 @@
1001110146 {
1001210147 static int location = 0;
1001310148 ImGuiIO& io = ImGui::GetIO();
10014- ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
10149+ ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
1001510150 if (location >= 0)
1001610151 {
1001710152 const float PAD = 10.0f;
@@ -10024,6 +10159,7 @@
1002410159 window_pos_pivot.x = (location & 1) ? 1.0f : 0.0f;
1002510160 window_pos_pivot.y = (location & 2) ? 1.0f : 0.0f;
1002610161 ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
10162+ ImGui::SetNextWindowViewport(viewport->ID);
1002710163 window_flags |= ImGuiWindowFlags_NoMove;
1002810164 }
1002910165 else if (location == -2)
@@ -10451,6 +10587,164 @@
1045110587 }
1045210588
1045310589 //-----------------------------------------------------------------------------
10590+// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
10591+//-----------------------------------------------------------------------------
10592+
10593+struct ImGuiDemoDockspaceArgs
10594+{
10595+ bool IsFullscreen = true;
10596+ bool KeepWindowPadding = false; // Keep WindowPadding to help understand that DockSpace() is a widget inside the window.
10597+ ImGuiDockNodeFlags DockSpaceFlags = ImGuiDockNodeFlags_None;
10598+};
10599+
10600+// THIS IS A DEMO FOR ADVANCED USAGE OF DockSpace().
10601+// MOST REGULAR APPLICATIONS WANTING TO ALLOW DOCKING WINDOWS ON THE EDGE OF YOUR SCREEN CAN SIMPLY USE:
10602+// ImGui::NewFrame(); + ImGui::DockSpaceOverViewport(); // Create a dockspace in main viewport
10603+// OR:
10604+// ImGui::NewFrame(); + ImGui::DockSpaceOverViewport(0, nullptr, ImGuiDockNodeFlags_PassthruCentralNode); // Create a dockspace in main viewport, where central node is transparent.
10605+// Demonstrate using DockSpace() to create an explicit docking node within an existing window, with various options.
10606+// Read https://github.com/ocornut/imgui/wiki/Docking for details.
10607+// The reasons we do not use DockSpaceOverViewport() in this demo is because:
10608+// - (1) we allow the host window to be floating/moveable instead of filling the viewport (when args->IsFullscreen == false)
10609+// which is mostly to showcase the idea that DockSpace() may be submitted anywhere.
10610+// Also see 'Demo->Examples->Documents' for a less abstract version of this.
10611+// - (2) we allow the host window to have padding (when args->UsePadding == true)
10612+// - (3) we expose variety of other flags.
10613+static void ShowExampleAppDockSpaceAdvanced(ImGuiDemoDockspaceArgs* args, bool* p_open)
10614+{
10615+ ImGuiDockNodeFlags dockspace_flags = args->DockSpaceFlags;
10616+
10617+ // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
10618+ // because it would be confusing to have two docking targets within each others.
10619+ ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking;
10620+ if (args->IsFullscreen)
10621+ {
10622+ // Fullscreen dockspace: practically the same as calling DockSpaceOverViewport();
10623+ const ImGuiViewport* viewport = ImGui::GetMainViewport();
10624+ ImGui::SetNextWindowPos(viewport->WorkPos);
10625+ ImGui::SetNextWindowSize(viewport->WorkSize);
10626+ ImGui::SetNextWindowViewport(viewport->ID);
10627+ ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
10628+ ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
10629+ window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
10630+ window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
10631+ window_flags |= ImGuiWindowFlags_NoBackground;
10632+ }
10633+ else
10634+ {
10635+ // Floating dockspace
10636+ dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
10637+ }
10638+
10639+ // Important: note that we proceed even if Begin() returns false (aka window is collapsed).
10640+ // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
10641+ // all active windows docked into it will lose their parent and become undocked.
10642+ // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
10643+ // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
10644+ if (!args->KeepWindowPadding)
10645+ ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
10646+ ImGui::Begin("Window with a DockSpace", p_open, window_flags);
10647+ if (!args->KeepWindowPadding)
10648+ ImGui::PopStyleVar();
10649+
10650+ if (args->IsFullscreen)
10651+ ImGui::PopStyleVar(2);
10652+
10653+ // Submit the DockSpace widget inside our window
10654+ // - Note that the id here is different from the one used by DockSpaceOverViewport(), so docking state won't get transfered between "Basic" and "Advanced" demos.
10655+ // - If we made the ShowExampleAppDockSpaceBasic() calculate its own ID and pass it to DockSpaceOverViewport() the ID could easily match.
10656+ ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
10657+ ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
10658+
10659+ ImGui::End();
10660+}
10661+
10662+static void ShowExampleAppDockSpaceBasic(ImGuiDockNodeFlags flags)
10663+{
10664+ // Basic version which you can use in many apps:
10665+ // e.g:
10666+ // ImGui::DockSpaceOverViewport();
10667+ // or:
10668+ // ImGui::DockSpaceOverViewport(0, nullptr, ImGuiDockNodeFlags_PassthruCentralNode); // Central node will be transparent
10669+ // or:
10670+ // ImGuiViewport* viewport = ImGui::GetMainViewport();
10671+ // ImGui::DockSpaceOverViewport(0, viewport, ImGuiDockNodeFlags_None);
10672+
10673+ ImGui::DockSpaceOverViewport(0, nullptr, flags);
10674+}
10675+
10676+void ShowExampleAppDockSpace(bool* p_open)
10677+{
10678+ static int opt_demo_mode = 0;
10679+ static bool opt_demo_mode_changed = false;
10680+ static ImGuiDemoDockspaceArgs args;
10681+
10682+ if (opt_demo_mode == 0)
10683+ ShowExampleAppDockSpaceBasic(args.DockSpaceFlags);
10684+ else
10685+ ShowExampleAppDockSpaceAdvanced(&args, p_open);
10686+
10687+ // Refocus our window to minimize perceived loss of focus when changing mode (caused by the fact that each use a different window, which would not happen in a real app)
10688+ if (opt_demo_mode_changed)
10689+ ImGui::SetNextWindowFocus();
10690+ ImGui::Begin("Examples: Dockspace", p_open, ImGuiWindowFlags_MenuBar);
10691+ opt_demo_mode_changed = false;
10692+ opt_demo_mode_changed |= ImGui::RadioButton("Basic demo mode", &opt_demo_mode, 0);
10693+ opt_demo_mode_changed |= ImGui::RadioButton("Advanced demo mode", &opt_demo_mode, 1);
10694+
10695+ ImGui::SeparatorText("Options");
10696+
10697+ if ((ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable) == 0)
10698+ {
10699+ ShowDockingDisabledMessage();
10700+ }
10701+ else if (opt_demo_mode == 0)
10702+ {
10703+ args.DockSpaceFlags &= ImGuiDockNodeFlags_PassthruCentralNode; // Allowed flags
10704+ ImGui::CheckboxFlags("Flag: PassthruCentralNode", &args.DockSpaceFlags, ImGuiDockNodeFlags_PassthruCentralNode);
10705+ }
10706+ else if (opt_demo_mode == 1)
10707+ {
10708+ ImGui::Checkbox("Fullscreen", &args.IsFullscreen);
10709+ ImGui::Checkbox("Keep Window Padding", &args.KeepWindowPadding);
10710+ ImGui::SameLine();
10711+ HelpMarker("This is mostly exposed to facilitate understanding that a DockSpace() is _inside_ a window.");
10712+ ImGui::BeginDisabled(args.IsFullscreen == false);
10713+ ImGui::CheckboxFlags("Flag: PassthruCentralNode", &args.DockSpaceFlags, ImGuiDockNodeFlags_PassthruCentralNode);
10714+ ImGui::EndDisabled();
10715+ ImGui::CheckboxFlags("Flag: NoDockingOverCentralNode", &args.DockSpaceFlags, ImGuiDockNodeFlags_NoDockingOverCentralNode);
10716+ ImGui::CheckboxFlags("Flag: NoDockingSplit", &args.DockSpaceFlags, ImGuiDockNodeFlags_NoDockingSplit);
10717+ ImGui::CheckboxFlags("Flag: NoUndocking", &args.DockSpaceFlags, ImGuiDockNodeFlags_NoUndocking);
10718+ ImGui::CheckboxFlags("Flag: NoResize", &args.DockSpaceFlags, ImGuiDockNodeFlags_NoResize);
10719+ ImGui::CheckboxFlags("Flag: AutoHideTabBar", &args.DockSpaceFlags, ImGuiDockNodeFlags_AutoHideTabBar);
10720+ }
10721+
10722+ // Show demo options and help
10723+ if (ImGui::BeginMenuBar())
10724+ {
10725+ if (ImGui::BeginMenu("Help"))
10726+ {
10727+ ImGui::TextUnformatted(
10728+ "This demonstrates the use of ImGui::DockSpace() which allows you to manually\ncreate a docking node _within_ another window." "\n"
10729+ "The \"Basic\" version uses the ImGui::DockSpaceOverViewport() helper. Most applications can probably use this.");
10730+ ImGui::Separator();
10731+ ImGui::TextUnformatted("When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n"
10732+ "- Drag from window title bar or their tab to dock/undock." "\n"
10733+ "- Drag from window menu button (upper-left button) to undock an entire node (all windows)." "\n"
10734+ "- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" "\n"
10735+ "- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)");
10736+ ImGui::Separator();
10737+ ImGui::TextUnformatted("More details:"); ImGui::Bullet(); ImGui::SameLine(); ImGui::TextLinkOpenURL("Docking Wiki page", "https://github.com/ocornut/imgui/wiki/Docking");
10738+ ImGui::BulletText("Read comments in ShowExampleAppDockSpace()");
10739+ ImGui::EndMenu();
10740+ }
10741+ ImGui::EndMenuBar();
10742+ }
10743+
10744+ ImGui::End();
10745+}
10746+
10747+//-----------------------------------------------------------------------------
1045410748 // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
1045510749 //-----------------------------------------------------------------------------
1045610750
@@ -10575,11 +10869,25 @@
1057510869 static ExampleAppDocuments app;
1057610870
1057710871 // Options
10872+ enum Target
10873+ {
10874+ Target_None,
10875+ Target_Tab, // Create documents as local tab into a local tab bar
10876+ Target_DockSpaceAndWindow // Create documents as regular windows, and create an embedded dockspace
10877+ };
10878+ static Target opt_target = Target_Tab;
1057810879 static bool opt_reorderable = true;
1057910880 static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
1058010881
10882+ // When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant")
10883+ // that we emit gets docked into the same spot as the parent window ("Example: Documents").
10884+ // This would create a problematic feedback loop because selecting the "Eggplant" tab would make the "Example: Documents" tab
10885+ // not visible, which in turn would stop submitting the "Eggplant" window.
10886+ // We avoid this problem by submitting our documents window even if our parent window is not currently visible.
10887+ // Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking.
10888+
1058110889 bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar);
10582- if (!window_contents_visible)
10890+ if (!window_contents_visible && opt_target != Target_DockSpaceAndWindow)
1058310891 {
1058410892 ImGui::End();
1058510893 return;
@@ -10624,6 +10932,12 @@
1062410932 doc.DoForceClose();
1062510933 ImGui::PopID();
1062610934 }
10935+ ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
10936+ ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0");
10937+ ImGui::PopItemWidth();
10938+ bool redock_all = false;
10939+ if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); }
10940+ if (opt_target == Target_DockSpaceAndWindow) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); }
1062710941
1062810942 ImGui::Separator();
1062910943
@@ -10637,7 +10951,8 @@
1063710951 // hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window.
1063810952 // The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole.
1063910953
10640- // Submit Tab Bar and Tabs
10954+ // Tabs
10955+ if (opt_target == Target_Tab)
1064110956 {
1064210957 ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
1064310958 tab_bar_flags |= ImGuiTabBarFlags_DrawSelectedOverline;
@@ -10679,6 +10994,53 @@
1067910994
1068010995 ImGui::EndTabBar();
1068110996 }
10997+ }
10998+ else if (opt_target == Target_DockSpaceAndWindow)
10999+ {
11000+ if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
11001+ {
11002+ app.NotifyOfDocumentsClosedElsewhere();
11003+
11004+ // Create a DockSpace node where any window can be docked
11005+ ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
11006+ ImGui::DockSpace(dockspace_id);
11007+
11008+ // Create Windows
11009+ for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
11010+ {
11011+ MyDocument* doc = &app.Documents[doc_n];
11012+ if (!doc->Open)
11013+ continue;
11014+
11015+ ImGui::SetNextWindowDockID(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver);
11016+ ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0);
11017+ bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags);
11018+
11019+ // Cancel attempt to close when unsaved add to save queue so we can display a popup.
11020+ if (!doc->Open && doc->Dirty)
11021+ {
11022+ doc->Open = true;
11023+ app.CloseQueue.push_back(doc);
11024+ }
11025+
11026+ app.DisplayDocContextMenu(doc);
11027+ if (visible)
11028+ app.DisplayDocContents(doc);
11029+
11030+ ImGui::End();
11031+ }
11032+ }
11033+ else
11034+ {
11035+ ShowDockingDisabledMessage();
11036+ }
11037+ }
11038+
11039+ // Early out other contents
11040+ if (!window_contents_visible)
11041+ {
11042+ ImGui::End();
11043+ return;
1068211044 }
1068311045
1068411046 // Display renaming UI
@@ -1,4 +1,4 @@
1-// dear imgui, v1.92.8
1+// dear imgui, v1.92.9 WIP
22 // (drawing and font code)
33
44 /*
@@ -231,6 +231,8 @@
231231 colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
232232 colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
233233 colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.50f, 0.50f, 0.50f, 0.00f);
234+ colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_HeaderActive] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
235+ colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
234236 colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
235237 colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
236238 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
@@ -299,6 +301,8 @@
299301 colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
300302 colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
301303 colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.53f, 0.53f, 0.87f, 0.00f);
304+ colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
305+ colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
302306 colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
303307 colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
304308 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
@@ -368,6 +372,8 @@
368372 colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
369373 colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
370374 colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.26f, 0.59f, 1.00f, 0.00f);
375+ colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
376+ colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
371377 colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
372378 colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
373379 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
@@ -402,7 +408,6 @@
402408 const float a = ((float)i * 2 * IM_PI) / (float)IM_COUNTOF(ArcFastVtx);
403409 ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a));
404410 }
405- ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError);
406411 }
407412
408413 ImDrawListSharedData::~ImDrawListSharedData()
@@ -412,17 +417,17 @@
412417
413418 void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error)
414419 {
415- if (CircleSegmentMaxError == max_error)
420+ if (CircleTessellationMaxError == max_error)
416421 return;
417422
418423 IM_ASSERT(max_error > 0.0f);
419- CircleSegmentMaxError = max_error;
424+ CircleTessellationMaxError = max_error;
420425 for (int i = 0; i < IM_COUNTOF(CircleSegmentCounts); i++)
421426 {
422427 const float radius = (float)i;
423- CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : IM_DRAWLIST_ARCFAST_SAMPLE_MAX);
428+ CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleTessellationMaxError) : IM_DRAWLIST_ARCFAST_SAMPLE_MAX);
424429 }
425- ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError);
430+ ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleTessellationMaxError);
426431 }
427432
428433 ImDrawList::ImDrawList(ImDrawListSharedData* shared_data)
@@ -656,11 +661,11 @@
656661 int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const
657662 {
658663 // Automatic segment count
659- const int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy
664+ const int radius_idx = (int)(radius + 0.999f); // ceil to never reduce accuracy
660665 if (radius_idx >= 0 && radius_idx < IM_COUNTOF(_Data->CircleSegmentCounts))
661666 return _Data->CircleSegmentCounts[radius_idx]; // Use cached value
662667 else
663- return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError);
668+ return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleTessellationMaxError);
664669 }
665670
666671 // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)
@@ -823,8 +828,13 @@
823828 const ImVec2 opaque_uv = _Data->TexUvWhitePixel;
824829 const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw
825830 const bool thick_line = (thickness > _FringeScale);
826- IM_ASSERT((flags & ImDrawFlags_InvalidMask_) == 0 && "Incorrect parameter. Did you swapped 'thickness' and 'flags'?");
827831
832+ // If this assert triggers on legacy code:
833+ // - 1.92.8 (2025/05): swapped two last parameters order: flags, thickness --> thickness, flags. This should normally be caught by compile-time type-checking.
834+ // - 1.92.8 (2025/05): changed value of ImDrawList_Closed which was previously guaranteed to be == 1. Hardcoded use of 1 or true should be replaced.
835+ // Read more details near AddRect() + see "API BREAKING CHANGES" section for 1.82, 1.90 and 1.92.8.
836+ IM_ASSERT_USER_ERROR_RET((flags & ImDrawFlags_InvalidMask_) == 0, "Incorrect parameter. Did you swap 'thickness' and 'flags'?");
837+
828838 if (Flags & ImDrawListFlags_AntiAliasedLines)
829839 {
830840 // Anti-aliased stroke
@@ -1475,27 +1485,24 @@
14751485 {
14761486 if ((col & IM_COL32_A_MASK) == 0)
14771487 return;
1478- PathLineTo(p1 + ImVec2(0.5f, 0.5f));
1479- PathLineTo(p2 + ImVec2(0.5f, 0.5f));
1480- PathStroke(col, thickness);
1488+ const ImVec2 points[2] = { ImVec2(p1.x + 0.5f, p1.y + 0.5f), ImVec2(p2.x + 0.5f, p2.y + 0.5f) };
1489+ AddPolyline(points, 2, col, thickness);
14811490 }
14821491
14831492 void ImDrawList::AddLineH(float min_x, float max_x, float y, ImU32 col, float thickness)
14841493 {
14851494 if ((col & IM_COL32_A_MASK) == 0)
14861495 return;
1487- PathLineTo(ImVec2(min_x + 0.5f, y + 0.5f)); // Same as AddLine() above.
1488- PathLineTo(ImVec2(max_x + 0.5f, y + 0.5f));
1489- PathStroke(col, thickness);
1496+ const ImVec2 points[2] = { ImVec2(min_x + 0.5f, y + 0.5f), ImVec2(max_x + 0.5f, y + 0.5f) }; // Same as AddLine() above.
1497+ AddPolyline(points, 2, col, thickness);
14901498 }
14911499
14921500 void ImDrawList::AddLineV(float x, float min_y, float max_y, ImU32 col, float thickness)
14931501 {
14941502 if ((col & IM_COL32_A_MASK) == 0)
14951503 return;
1496- PathLineTo(ImVec2(x + 0.5f, min_y + 0.5f)); // Same as AddLine() above.
1497- PathLineTo(ImVec2(x + 0.5f, max_y + 0.5f));
1498- PathStroke(col, thickness);
1504+ const ImVec2 points[2] = { ImVec2(x + 0.5f, min_y + 0.5f), ImVec2(x + 0.5f, max_y + 0.5f) }; // Same as AddLine() above.
1505+ AddPolyline(points, 2, col, thickness);
14991506 }
15001507
15011508 // p_min = upper-left, p_max = lower-right
@@ -1503,14 +1510,15 @@
15031510 void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, float thickness, ImDrawFlags flags)
15041511 {
15051512 // If this assert triggers on legacy code:
1506- // - 1.92.8 (2025/04): swapped two last parameters order: flags, thickness --> thickness, flags. This should normally be caught by compile-time type-checking.
1513+ // - 1.92.8 (2025/05): swapped two last parameters order: flags, thickness --> thickness, flags. This should normally be caught by compile-time type-checking.
1514+ // - 1.92.8 (2025/05): changed value of ImDrawList_Closed which was previously guaranteed to be == 1. Hardcoded use of 1 or true should be replaced.
15071515 // - 1.82.0 (2021/03): changed ImDrawCornerFlags to ImDrawFlags_RoundCornersXXX values.
15081516 // If you used hard-coded 1 to 15 or ~0 in flags to configure corner rounding use the new flags!
15091517 // - Hard coded support for ~0 == ImDrawFlags_RoundCornersAll.
15101518 // - Hard coded support for values 0x01 to 0x0F (matching 15 out of 16 old flags combinations) --> see FixRectCornerFlags() in <1.90 code.
15111519 // - Hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f'.
1512- // See "API BREAKING CHANGES" section for 1.82 and 1.90.
1513- IM_ASSERT((flags & ImDrawFlags_InvalidMask_) == 0 && "Incorrect parameter. Did you swapped 'thickness' and 'flags'?"); // Or misuse of legacy hard-coded ImDrawCornerFlags values
1520+ // See "API BREAKING CHANGES" section for 1.82, 1.90 and 1.92.8.
1521+ IM_ASSERT_USER_ERROR_RET((flags & ImDrawFlags_InvalidMask_) == 0, "Incorrect parameter. Did you swap 'thickness' and 'flags'?"); // Or misuse of legacy hard-coded ImDrawCornerFlags values
15141522
15151523 if ((col & IM_COL32_A_MASK) == 0)
15161524 return;
@@ -2560,8 +2568,6 @@
25602568 // - ImFontAtlasBuildPreloadAllGlyphRanges()
25612569 // - ImFontAtlasBuildUpdatePointers()
25622570 // - ImFontAtlasBuildRenderBitmapFromString()
2563-// - ImFontAtlasBuildUpdateBasicTexData()
2564-// - ImFontAtlasBuildUpdateLinesTexData()
25652571 // - ImFontAtlasBuildAddFont()
25662572 // - ImFontAtlasBuildSetupFontBakedEllipsis()
25672573 // - ImFontAtlasBuildSetupFontBakedBlanks()
@@ -2578,13 +2584,14 @@
25782584 // - ImFontAtlasUpdateDrawListsSharedData()
25792585 //-----------------------------------------------------------------------------
25802586 // - ImFontAtlasBuildSetTexture()
2581-// - ImFontAtlasBuildAddTexture()
2582-// - ImFontAtlasBuildMakeSpace()
2583-// - ImFontAtlasBuildRepackTexture()
2584-// - ImFontAtlasBuildGrowTexture()
2585-// - ImFontAtlasBuildRepackOrGrowTexture()
2586-// - ImFontAtlasBuildGetTextureSizeEstimate()
2587-// - ImFontAtlasBuildCompactTexture()
2587+// - ImFontAtlasBuildUpdateTexData()
2588+// - ImFontAtlasTextureAdd()
2589+// - ImFontAtlasTextureRepack()
2590+// - ImFontAtlasTextureGrow()
2591+// - ImFontAtlasTextureMakeSpace()
2592+// - ImFontAtlasTextureGetSizeEstimate()
2593+// - ImFontAtlasBuildClear()
2594+// - ImFontAtlasTextureCompact()
25882595 // - ImFontAtlasBuildInit()
25892596 // - ImFontAtlasBuildDestroy()
25902597 //-----------------------------------------------------------------------------
@@ -2689,6 +2696,7 @@
26892696 // Calling this mid-frame will discard the CPU-side copy of the texture data which is generally unreliable as you may have textures queued for creation or updates.
26902697 void ImFontAtlas::Clear()
26912698 {
2699+ IMGUI_DEBUG_LOG_FONT("[font] ImFontAtlas::Clear()\n");
26922700 bool backup_renderer_has_textures = RendererHasTextures;
26932701 RendererHasTextures = false; // Full Clear() is supported, but ClearTexData() only isn't.
26942702 ClearFonts();
@@ -2699,6 +2707,7 @@
26992707 void ImFontAtlas::ClearFonts()
27002708 {
27012709 // FIXME-NEWATLAS: Illegal to remove currently bound font.
2710+ IMGUI_DEBUG_LOG_FONT("[font] ImFontAtlas::ClearFonts()\n");
27022711 IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
27032712 for (ImFont* font : Fonts)
27042713 ImFontAtlasBuildNotifySetFont(this, font, NULL);
@@ -2774,6 +2783,28 @@
27742783 IM_ASSERT(atlas->Builder == NULL || atlas->Builder->FrameCount < frame_count); // Protection against being called twice.
27752784 atlas->RendererHasTextures = renderer_has_textures;
27762785
2786+ // Update texture status and discard old textures.
2787+ // (we do this first thing to handle an edge case: if user mistakenly calls ClearFonts()+SetStatus(OK) during
2788+ // rendering, it would ImFontAtlasBuildMain() rebuilding before tex->Updates[] gets a chance to be cleared)
2789+ // (if somehow we need to move this back lower in the function, we could manually call the code to clear Updates[]).
2790+ for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++)
2791+ {
2792+ // Update and remove if requested
2793+ ImTextureData* tex = atlas->TexList[tex_n];
2794+ if (tex->Status == ImTextureStatus_WantCreate && atlas->RendererHasTextures)
2795+ IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture's TexID/BackendUserData but did not update Status to OK.");
2796+
2797+ bool remove_from_list = ImTextureDataUpdateNewFrame(tex);
2798+ if (remove_from_list)
2799+ {
2800+ IM_ASSERT(atlas->TexData != tex);
2801+ tex->DestroyPixels();
2802+ IM_DELETE(tex);
2803+ atlas->TexList.erase(atlas->TexList.begin() + tex_n);
2804+ tex_n--;
2805+ }
2806+ }
2807+
27772808 // Check that font atlas was built or backend support texture reload in which case we can build now
27782809 if (atlas->RendererHasTextures)
27792810 {
@@ -2813,61 +2844,49 @@
28132844 builder->BakedPool.Size -= builder->BakedDiscardedCount;
28142845 builder->BakedDiscardedCount = 0;
28152846 }
2847+}
28162848
2817- // Update texture status
2818- for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++)
2849+bool ImTextureDataUpdateNewFrame(ImTextureData* tex)
2850+{
2851+ bool remove_from_list = false;
2852+ if (tex->Status == ImTextureStatus_OK)
28192853 {
2820- ImTextureData* tex = atlas->TexList[tex_n];
2821- bool remove_from_list = false;
2822- if (tex->Status == ImTextureStatus_OK)
2823- {
2824- tex->Updates.resize(0);
2825- tex->UpdateRect.x = tex->UpdateRect.y = (unsigned short)~0;
2826- tex->UpdateRect.w = tex->UpdateRect.h = 0;
2827- }
2828- if (tex->Status == ImTextureStatus_WantCreate && atlas->RendererHasTextures)
2829- IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture's TexID/BackendUserData but did not update Status to OK.");
2854+ tex->Updates.resize(0);
2855+ tex->UpdateRect.x = tex->UpdateRect.y = (unsigned short)~0;
2856+ tex->UpdateRect.w = tex->UpdateRect.h = 0;
2857+ }
28302858
2831- // Request destroy
2832- // - Keep bool to true in order to differentiate a planned destroy vs a destroy decided by the backend.
2833- // - We don't destroy pixels right away, as backend may have an in-flight copy from RAM.
2834- if (tex->WantDestroyNextFrame && tex->Status != ImTextureStatus_Destroyed && tex->Status != ImTextureStatus_WantDestroy)
2835- {
2836- IM_ASSERT(tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates);
2837- tex->Status = ImTextureStatus_WantDestroy;
2838- }
2859+ // Request destroy
2860+ // - Keep bool to true in order to differentiate a planned destroy vs a destroy decided by the backend.
2861+ // - We don't destroy pixels right away, as backend may have an in-flight copy from RAM.
2862+ if (tex->WantDestroyNextFrame && tex->Status != ImTextureStatus_Destroyed && tex->Status != ImTextureStatus_WantDestroy)
2863+ {
2864+ IM_ASSERT(tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates);
2865+ tex->Status = ImTextureStatus_WantDestroy;
2866+ }
28392867
2840- // If a texture has never reached the backend, they don't need to know about it.
2841- // (note: backends between 1.92.0 and 1.92.4 could set an already destroyed texture to ImTextureStatus_WantDestroy
2842- // when invalidating graphics objects twice, which would previously remove it from the list and crash.)
2843- if (tex->Status == ImTextureStatus_WantDestroy && tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL)
2844- tex->Status = ImTextureStatus_Destroyed;
2868+ // If a texture has never reached the backend, they don't need to know about it.
2869+ // (note: backends between 1.92.0 and 1.92.4 could set an already destroyed texture to ImTextureStatus_WantDestroy
2870+ // when invalidating graphics objects twice, which would previously remove it from the list and crash.)
2871+ if (tex->Status == ImTextureStatus_WantDestroy && tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL)
2872+ tex->Status = ImTextureStatus_Destroyed;
28452873
2846- // Process texture being destroyed
2847- if (tex->Status == ImTextureStatus_Destroyed)
2848- {
2849- IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture Status to Destroyed but did not clear TexID/BackendUserData!");
2850- if (tex->WantDestroyNextFrame)
2851- remove_from_list = true; // Destroy was scheduled by us
2852- else
2853- tex->Status = ImTextureStatus_WantCreate; // Destroy was done was backend: recreate it (e.g. freed resources mid-run)
2854- }
2874+ // Process texture being destroyed
2875+ if (tex->Status == ImTextureStatus_Destroyed)
2876+ {
2877+ IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture Status to Destroyed but did not clear TexID/BackendUserData!");
2878+ if (tex->WantDestroyNextFrame)
2879+ remove_from_list = true; // Destroy was scheduled by us
2880+ else
2881+ tex->Status = ImTextureStatus_WantCreate; // Destroy was done was backend: recreate it (e.g. freed resources mid-run)
2882+ }
28552883
2856- // The backend may need defer destroying by a few frames, to handle texture used by previous in-flight rendering.
2857- // We allow the texture staying in _WantDestroy state and increment a counter which the backend can use to take its decision.
2858- if (tex->Status == ImTextureStatus_WantDestroy)
2859- tex->UnusedFrames++;
2884+ // The backend may need defer destroying by a few frames, to handle texture used by previous in-flight rendering.
2885+ // We allow the texture staying in _WantDestroy state and increment a counter which the backend can use to take its decision.
2886+ if (tex->Status == ImTextureStatus_WantDestroy)
2887+ tex->UnusedFrames++;
28602888
2861- // Destroy and remove
2862- if (remove_from_list)
2863- {
2864- IM_ASSERT(atlas->TexData != tex);
2865- tex->DestroyPixels();
2866- IM_DELETE(tex);
2867- atlas->TexList.erase(atlas->TexList.begin() + tex_n);
2868- tex_n--;
2869- }
2870- }
2889+ return remove_from_list;
28712890 }
28722891
28732892 void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h)
@@ -3143,8 +3162,10 @@
31433162 dst += 4;
31443163 }
31453164 }
3146-#ifndef IMGUI_DISABLE_DEFAULT_FONT
3165+#if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_BITMAP)
31473166 static const char* GetDefaultCompressedFontDataProggyClean(int* out_size);
3167+#endif
3168+#if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_VECTOR)
31483169 static const char* GetDefaultCompressedFontDataProggyForever(int* out_size);
31493170 #endif
31503171
@@ -3169,7 +3190,7 @@
31693190 // If you want a similar font which may be better scaled, consider using AddFontDefaultVector().
31703191 ImFont* ImFontAtlas::AddFontDefaultBitmap(const ImFontConfig* font_cfg_template)
31713192 {
3172-#ifndef IMGUI_DISABLE_DEFAULT_FONT
3193+#if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_BITMAP)
31733194 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
31743195 if (!font_cfg_template)
31753196 font_cfg.PixelSnapH = true; // Prevents sub-integer scaling factors at lower-level layers.
@@ -3190,14 +3211,14 @@
31903211 IM_ASSERT(0 && "Function is disabled in this build.");
31913212 IM_UNUSED(font_cfg_template);
31923213 return NULL;
3193-#endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT
3214+#endif
31943215 }
31953216
31963217 // Load a minimal version of ProggyForever, designed to match our good old ProggyClean, but nicely scalable.
31973218 // (See build script in https://github.com/ocornut/proggyforever for details)
31983219 ImFont* ImFontAtlas::AddFontDefaultVector(const ImFontConfig* font_cfg_template)
31993220 {
3200-#ifndef IMGUI_DISABLE_DEFAULT_FONT
3221+#if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_VECTOR)
32013222 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
32023223 if (!font_cfg_template)
32033224 font_cfg.PixelSnapH = true; // Precisely match ProggyClean, but prevents sub-integer scaling factors at lower-level layers.
@@ -3218,7 +3239,7 @@
32183239 IM_ASSERT(0 && "Function is disabled in this build.");
32193240 IM_UNUSED(font_cfg_template);
32203241 return NULL;
3221-#endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT
3242+#endif
32223243 }
32233244
32243245 ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
@@ -3574,7 +3595,7 @@
35743595 }
35753596 }
35763597
3577-static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas)
3598+static void ImFontAtlasBuildUpdateTexDataBasic(ImFontAtlas* atlas)
35783599 {
35793600 // Pack and store identifier so we can refresh UV coordinates on texture resize.
35803601 // FIXME-NEWATLAS: User/custom rects where user code wants to store UV coordinates will need to do the same thing.
@@ -3608,7 +3629,7 @@
36083629 atlas->TexUvWhitePixel = ImVec2((r.x + 0.5f) * atlas->TexUvScale.x, (r.y + 0.5f) * atlas->TexUvScale.y);
36093630 }
36103631
3611-static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas)
3632+static void ImFontAtlasBuildUpdateTexDataLines(ImFontAtlas* atlas)
36123633 {
36133634 if (atlas->Flags & ImFontAtlasFlags_NoBakedLines)
36143635 return;
@@ -4057,6 +4078,12 @@
40574078 ImFontAtlasUpdateDrawListsTextures(atlas, old_tex_ref, atlas->TexRef);
40584079 }
40594080
4081+static void ImFontAtlasBuildUpdateTexData(ImFontAtlas* atlas)
4082+{
4083+ ImFontAtlasBuildUpdateTexDataBasic(atlas);
4084+ ImFontAtlasBuildUpdateTexDataLines(atlas);
4085+}
4086+
40604087 // Create a new texture, discard previous one
40614088 ImTextureData* ImFontAtlasTextureAdd(ImFontAtlas* atlas, int w, int h)
40624089 {
@@ -4171,8 +4198,7 @@
41714198 }
41724199
41734200 // Update other cached UV
4174- ImFontAtlasBuildUpdateLinesTexData(atlas);
4175- ImFontAtlasBuildUpdateBasicTexData(atlas);
4201+ ImFontAtlasBuildUpdateTexData(atlas);
41764202
41774203 builder->LockDisableResize = false;
41784204 ImFontAtlasUpdateDrawListsSharedData(atlas);
@@ -4321,8 +4347,7 @@
43214347 ImFontAtlasPackInit(atlas);
43224348
43234349 // Add required texture data
4324- ImFontAtlasBuildUpdateLinesTexData(atlas);
4325- ImFontAtlasBuildUpdateBasicTexData(atlas);
4350+ ImFontAtlasBuildUpdateTexData(atlas);
43264351
43274352 // Register fonts
43284353 ImFontAtlasBuildUpdatePointers(atlas);
@@ -4351,6 +4376,8 @@
43514376 atlas->Builder = NULL;
43524377 }
43534378
4379+//-----------------------------------------------------------------------------
4380+
43544381 void ImFontAtlasPackInit(ImFontAtlas * atlas)
43554382 {
43564383 ImTextureData* tex = atlas->TexData;
@@ -5747,8 +5774,13 @@
57475774 if (glyph->Colored)
57485775 col |= ~IM_COL32_A_MASK;
57495776 float scale = (size >= 0.0f) ? (size / baked->Size) : 1.0f;
5750- float x = IM_TRUNC(pos.x);
5751- float y = IM_TRUNC(pos.y);
5777+ float x = pos.x;
5778+ float y = pos.y;
5779+ if ((draw_list->Flags & ImDrawListFlags_TextNoPixelSnap) == 0)
5780+ {
5781+ x = IM_TRUNC(x);
5782+ y = IM_TRUNC(y);
5783+ }
57525784
57535785 float x1 = x + glyph->X0 * scale;
57545786 float x2 = x + glyph->X1 * scale;
@@ -5780,12 +5812,17 @@
57805812 // DO NOT CALL DIRECTLY THIS WILL CHANGE WILDLY IN 2026. Use ImDrawList::AddText().
57815813 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)
57825814 {
5783- // Align to be pixel perfect
57845815 begin:
5785- float x = IM_TRUNC(pos.x);
5786- float y = IM_TRUNC(pos.y);
5816+ // Align to be pixel perfect
5817+ float x = pos.x;
5818+ float y = pos.y;
57875819 if (y > clip_rect.w)
57885820 return;
5821+ if ((draw_list->Flags & ImDrawListFlags_TextNoPixelSnap) == 0)
5822+ {
5823+ x = IM_TRUNC(x);
5824+ y = IM_TRUNC(y);
5825+ }
57895826
57905827 if (!text_end)
57915828 text_end = text_begin + ImStrlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
@@ -5990,6 +6027,7 @@
59906027 // - RenderArrow()
59916028 // - RenderBullet()
59926029 // - RenderCheckMark()
6030+// - RenderArrowDockMenu()
59936031 // - RenderArrowPointingAt()
59946032 // - RenderRectFilledInRangeH()
59956033 // - RenderRectFilledWithHole()
@@ -6065,6 +6103,14 @@
60656103 }
60666104 }
60676105
6106+// This is less wide than RenderArrow() and we use in dock nodes instead of the regular RenderArrow() to denote a change of functionality,
6107+// and because the saved space means that the left-most tab label can stay at exactly the same position as the label of a loose window.
6108+void ImGui::RenderArrowDockMenu(ImDrawList* draw_list, ImVec2 p_min, float sz, ImU32 col)
6109+{
6110+ draw_list->AddRectFilled(p_min + ImVec2(sz * 0.20f, sz * 0.15f), p_min + ImVec2(sz * 0.80f, sz * 0.30f), col);
6111+ RenderArrowPointingAt(draw_list, p_min + ImVec2(sz * 0.50f, sz * 0.85f), ImVec2(sz * 0.30f, sz * 0.40f), ImGuiDir_Down, col);
6112+}
6113+
60686114 static inline float ImAcos01(float x)
60696115 {
60706116 if (x <= 0.0f) return IM_PI * 0.5f;
@@ -6171,8 +6217,8 @@
61716217 flags = ImDrawFlags_RoundCornersDefault_;
61726218 if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF)
61736219 {
6174- ImU32 col_bg1 = GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col));
6175- ImU32 col_bg2 = GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col));
6220+ ImU32 col_bg1 = GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col));
6221+ ImU32 col_bg2 = GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col));
61766222 draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, flags);
61776223
61786224 int yi = 0;
@@ -6181,12 +6227,12 @@
61816227 float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y);
61826228 if (y2 <= y1)
61836229 continue;
6184- for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f)
6230+ for (float x = p_min.x + grid_off.x + ((yi ^ 1) & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f)
61856231 {
61866232 float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x);
61876233 if (x2 <= x1)
61886234 continue;
6189- ImDrawFlags cell_flags = ImDrawFlags_RoundCornersNone;
6235+ ImDrawFlags cell_flags = ImDrawFlags_RoundCornersNone; // FIXME: Could use CalcRoundingFlagsForRectInRect()
61906236 if (y1 <= p_min.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersTopLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersTopRight; }
61916237 if (y2 >= p_max.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersBottomLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersBottomRight; }
61926238
@@ -6328,7 +6374,7 @@
63286374 // Download and more information at https://github.com/bluescan/proggyfonts
63296375 //-----------------------------------------------------------------------------
63306376
6331-#ifndef IMGUI_DISABLE_DEFAULT_FONT
6377+#if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_BITMAP)
63326378
63336379 // File: 'ProggyClean.ttf' (41208 bytes)
63346380 // Exported using binary_to_compressed_c.exe -u8 "ProggyClean.ttf" proggy_clean_ttf
@@ -6508,6 +6554,7 @@
65086554 *out_size = proggy_clean_ttf_compressed_size;
65096555 return (const char*)proggy_clean_ttf_compressed_data;
65106556 }
6557+#endif // #if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_BITMAP)
65116558
65126559 //-----------------------------------------------------------------------------
65136560 // [SECTION] Default font data (ProggyForever-Regular-minimal.ttf)
@@ -6516,6 +6563,8 @@
65166563 // MIT license / Copyright (c) 2026 Disco Hello, Copyright (c) 2019,2023 Tristan Grimmer
65176564 //-----------------------------------------------------------------------------
65186565
6566+#if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_VECTOR)
6567+
65196568 // File: 'output/ProggyForever-Regular-minimal.ttf' (18556 bytes)
65206569 // Exported using binary_to_compressed_c.exe -u8 "output/ProggyForever-Regular-minimal.ttf" proggy_forever_minimal_ttf
65216570 static const unsigned int proggy_forever_minimal_ttf_compressed_size = 14562;
@@ -6770,7 +6819,6 @@
67706819 *out_size = proggy_forever_minimal_ttf_compressed_size;
67716820 return (const char*)proggy_forever_minimal_ttf_compressed_data;
67726821 }
6773-
6774-#endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT
6822+#endif // #if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_VECTOR)
67756823
67766824 #endif // #ifndef IMGUI_DISABLE
@@ -1,4 +1,4 @@
1-// dear imgui, v1.92.8
1+// dear imgui, v1.92.9 WIP
22 // (internal structures/api)
33
44 // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.
@@ -35,7 +35,7 @@
3535 // [SECTION] ImGuiContext (main imgui context)
3636 // [SECTION] ImGuiWindowTempData, ImGuiWindow
3737 // [SECTION] Tab bar, Tab item support
38-// [SECTION] Table support
38+// [SECTION] Table support + internal API
3939 // [SECTION] ImGui internal API
4040 // [SECTION] ImFontLoader
4141 // [SECTION] ImFontAtlas internal API
@@ -153,6 +153,10 @@
153153 struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine
154154 struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum
155155 struct ImGuiDeactivatedItemData; // Data for IsItemDeactivated()/IsItemDeactivatedAfterEdit() function.
156+struct ImGuiDockContext; // Docking system context
157+struct ImGuiDockRequest; // Docking system dock/undock queued request
158+struct ImGuiDockNode; // Docking system node (hold a list of Windows OR two child dock nodes)
159+struct ImGuiDockNodeSettings; // Storage for a dock node in .ini file (we preserve those even if the associated dock node isn't active during the session)
156160 struct ImGuiErrorRecoveryState; // Storage of stack sizes for error handling and recovery
157161 struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup()
158162 struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box
@@ -185,12 +189,14 @@
185189 struct ImGuiTypingSelectState; // Storage for GetTypingSelectRequest()
186190 struct ImGuiTypingSelectRequest; // Storage for GetTypingSelectRequest() (aimed to be public)
187191 struct ImGuiWindow; // Storage for one window
192+struct ImGuiWindowDockStyle; // Storage for window-style data which needs to be stored for docking purpose
188193 struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame, in practice we currently keep it for each window)
189194 struct ImGuiWindowSettings; // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session)
190195
191196 // Enumerations
192197 // Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists.
193198 enum ImGuiLocKey : int; // -> enum ImGuiLocKey // Enum: a localization entry for translation.
199+typedef int ImGuiDataAuthority; // -> enum ImGuiDataAuthority_ // Enum: for storing the source authority (dock node vs window) of a field
194200 typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical
195201
196202 // Flags
@@ -230,6 +236,9 @@
230236 // [SECTION] Macros
231237 //-----------------------------------------------------------------------------
232238
239+// Internal Drag and Drop payload types. String starting with '_' are reserved for Dear ImGui.
240+#define IMGUI_PAYLOAD_TYPE_WINDOW "_IMWINDOW" // Payload == ImGuiWindow*
241+
233242 // Debug Printing Into TTY
234243 // (since IMGUI_VERSION_NUM >= 18729: IMGUI_DEBUG_LOG was reworked into IMGUI_DEBUG_PRINTF (and removed framecount from it). If you were using a #define IMGUI_DEBUG_LOG please rename)
235244 #ifndef IMGUI_DEBUG_PRINTF
@@ -247,10 +256,13 @@
247256 #define IMGUI_DEBUG_LOG_POPUP(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
248257 #define IMGUI_DEBUG_LOG_NAV(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventNav) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
249258 #define IMGUI_DEBUG_LOG_SELECTION(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
259+#define IMGUI_DEBUG_LOG_TABLE(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventTable) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
250260 #define IMGUI_DEBUG_LOG_CLIPPER(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventClipper) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
251261 #define IMGUI_DEBUG_LOG_IO(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
252262 #define IMGUI_DEBUG_LOG_FONT(...) do { ImGuiContext* g2 = GImGui; if (g2 && g2->DebugLogFlags & ImGuiDebugLogFlags_EventFont) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) // Called from ImFontAtlas function which may operate without a context.
253263 #define IMGUI_DEBUG_LOG_INPUTROUTING(...) do{if (g.DebugLogFlags & ImGuiDebugLogFlags_EventInputRouting)IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
264+#define IMGUI_DEBUG_LOG_DOCKING(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventDocking) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
265+#define IMGUI_DEBUG_LOG_VIEWPORT(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventViewport) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
254266
255267 // Debug options (also see ones on top of imgui.cpp)
256268 //#define IMGUI_DEBUG_BOXSELECT
@@ -321,6 +333,8 @@
321333 #define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xde01")
322334 #elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__)
323335 #define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xe7f001f0")
336+#elif defined(__GNUC__) && defined(__aarch64__)
337+#define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xd4200000") // GDB needs 'set $pc=($pc+4)' to skip this :(
324338 #else
325339 #define IM_DEBUG_BREAK() IM_ASSERT(0) // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger!
326340 #endif
@@ -531,6 +545,7 @@
531545 inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2(ImFloor(v.x), ImFloor(v.y)); }
532546 inline float ImTrunc64(float f) { return (float)(ImS64)(f); }
533547 inline float ImRound64(float f) { return (float)(ImS64)(f + 0.5f); } // FIXME: Positive values only.
548+inline float ImCeilFast(float f) { int i = (int)f; return (float)(i + (f > (float)i)); } // Consider using the the bit-hack version (search for "0x1p120f").
534549 inline int ImModPositive(int a, int b) { return (a + b) % b; }
535550 inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; }
536551 inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); }
@@ -688,6 +703,8 @@
688703
689704 inline void set(T* data, int size) { Data = data; DataEnd = data + size; }
690705 inline void set(T* data, T* data_end) { Data = data; DataEnd = data_end; }
706+ inline void clear() { Data = DataEnd = NULL; }
707+ inline bool empty() const { return Data == DataEnd; }
691708 inline int size() const { return (int)(ptrdiff_t)(DataEnd - Data); }
692709 inline int size_in_bytes() const { return (int)(ptrdiff_t)(DataEnd - Data) * (int)sizeof(T); }
693710 inline T& operator[](int i) { T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; }
@@ -872,7 +889,7 @@
872889 float FontSize; // Current font size (used for for simplified AddText overload)
873890 float FontScale; // Current font scale (== FontSize / Font->FontSize)
874891 float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo()
875- float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc
892+ float CircleTessellationMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc
876893 float InitialFringeScale; // Initial scale to apply to AA fringe
877894 ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards)
878895 ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen()
@@ -1021,7 +1038,7 @@
10211038 enum ImGuiHoveredFlagsPrivate_
10221039 {
10231040 ImGuiHoveredFlags_DelayMask_ = ImGuiHoveredFlags_DelayNone | ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay,
1024- ImGuiHoveredFlags_AllowedMaskForIsWindowHovered = ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_Stationary,
1041+ ImGuiHoveredFlags_AllowedMaskForIsWindowHovered = ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_DockHierarchy | ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_Stationary,
10251042 ImGuiHoveredFlags_AllowedMaskForIsItemHovered = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped | ImGuiHoveredFlags_AllowWhenDisabled | ImGuiHoveredFlags_NoNavOverride | ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayMask_,
10261043 };
10271044
@@ -1319,6 +1336,9 @@
13191336 ImGuiNextWindowDataFlags_HasWindowFlags = 1 << 8,
13201337 ImGuiNextWindowDataFlags_HasChildFlags = 1 << 9,
13211338 ImGuiNextWindowDataFlags_HasRefreshPolicy = 1 << 10,
1339+ ImGuiNextWindowDataFlags_HasViewport = 1 << 11,
1340+ ImGuiNextWindowDataFlags_HasDock = 1 << 12,
1341+ ImGuiNextWindowDataFlags_HasWindowClass = 1 << 13,
13221342 };
13231343
13241344 // Storage for SetNexWindow** functions
@@ -1330,6 +1350,7 @@
13301350 ImGuiCond PosCond;
13311351 ImGuiCond SizeCond;
13321352 ImGuiCond CollapsedCond;
1353+ ImGuiCond DockCond;
13331354 ImVec2 PosVal;
13341355 ImVec2 PosPivotVal;
13351356 ImVec2 SizeVal;
@@ -1337,11 +1358,15 @@
13371358 ImVec2 ScrollVal;
13381359 ImGuiWindowFlags WindowFlags; // Only honored by BeginTable()
13391360 ImGuiChildFlags ChildFlags;
1361+ bool PosUndock;
13401362 bool CollapsedVal;
13411363 ImRect SizeConstraintRect;
13421364 ImGuiSizeCallback SizeCallback;
13431365 void* SizeCallbackUserData;
13441366 float BgAlphaVal; // Override background alpha
1367+ ImGuiID ViewportId;
1368+ ImGuiID DockId;
1369+ ImGuiWindowClass WindowClass;
13451370 ImVec2 MenuBarOffsetMinVal; // (Always on) This is not exposed publicly, so we don't clear it and it doesn't have a corresponding flag (could we? for consistency?)
13461371 ImGuiWindowRefreshFlags RefreshFlagsVal;
13471372
@@ -1527,6 +1552,7 @@
15271552 ImGuiInputEventType_MousePos,
15281553 ImGuiInputEventType_MouseWheel,
15291554 ImGuiInputEventType_MouseButton,
1555+ ImGuiInputEventType_MouseViewport,
15301556 ImGuiInputEventType_Key,
15311557 ImGuiInputEventType_Text,
15321558 ImGuiInputEventType_Focus,
@@ -1547,6 +1573,7 @@
15471573 struct ImGuiInputEventMousePos { float PosX, PosY; ImGuiMouseSource MouseSource; };
15481574 struct ImGuiInputEventMouseWheel { float WheelX, WheelY; ImGuiMouseSource MouseSource; };
15491575 struct ImGuiInputEventMouseButton { int Button; bool Down; ImGuiMouseSource MouseSource; };
1576+struct ImGuiInputEventMouseViewport { ImGuiID HoveredViewportID; };
15501577 struct ImGuiInputEventKey { ImGuiKey Key; bool Down; float AnalogValue; };
15511578 struct ImGuiInputEventText { unsigned int Char; };
15521579 struct ImGuiInputEventAppFocused { bool Focused; };
@@ -1561,6 +1588,7 @@
15611588 ImGuiInputEventMousePos MousePos; // if Type == ImGuiInputEventType_MousePos
15621589 ImGuiInputEventMouseWheel MouseWheel; // if Type == ImGuiInputEventType_MouseWheel
15631590 ImGuiInputEventMouseButton MouseButton; // if Type == ImGuiInputEventType_MouseButton
1591+ ImGuiInputEventMouseViewport MouseViewport; // if Type == ImGuiInputEventType_MouseViewport
15641592 ImGuiInputEventKey Key; // if Type == ImGuiInputEventType_Key
15651593 ImGuiInputEventText Text; // if Type == ImGuiInputEventType_Text
15661594 ImGuiInputEventAppFocused AppFocused; // if Type == ImGuiInputEventType_Focus
@@ -1702,6 +1730,7 @@
17021730 };
17031731
17041732 // Early work-in-progress API for ScrollToItem()
1733+// FIXME: Missing flags to request making both edges visible when possible.
17051734 enum ImGuiScrollFlags_
17061735 {
17071736 ImGuiScrollFlags_None = 0,
@@ -1721,8 +1750,8 @@
17211750 ImGuiNavRenderCursorFlags_None = 0,
17221751 ImGuiNavRenderCursorFlags_Compact = 1 << 1, // Compact highlight, no padding/distance from focused item
17231752 ImGuiNavRenderCursorFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) even when g.NavCursorVisible == false, aka even when using the mouse.
1724- ImGuiNavRenderCursorFlags_NoRounding = 1 << 3,
17251753 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1754+ ImGuiNavRenderCursorFlags_NoRounding = 1 << 3,
17261755 ImGuiNavHighlightFlags_None = ImGuiNavRenderCursorFlags_None, // Renamed in 1.91.4
17271756 ImGuiNavHighlightFlags_Compact = ImGuiNavRenderCursorFlags_Compact, // Renamed in 1.91.4
17281757 ImGuiNavHighlightFlags_AlwaysDraw = ImGuiNavRenderCursorFlags_AlwaysDraw, // Renamed in 1.91.4
@@ -1958,8 +1987,156 @@
19581987 // [SECTION] Docking support
19591988 //-----------------------------------------------------------------------------
19601989
1990+#define DOCKING_HOST_DRAW_CHANNEL_BG 0 // Dock host: background fill
1991+#define DOCKING_HOST_DRAW_CHANNEL_FG 1 // Dock host: decorations and contents
1992+
19611993 #ifdef IMGUI_HAS_DOCK
1962-// <this is filled in 'docking' branch>
1994+
1995+// Extend ImGuiDockNodeFlags_
1996+enum ImGuiDockNodeFlagsPrivate_
1997+{
1998+ // [Internal]
1999+ ImGuiDockNodeFlags_DockSpace = 1 << 10, // Saved // A dockspace is a node that occupy space within an existing user window. Otherwise the node is floating and create its own window.
2000+ ImGuiDockNodeFlags_CentralNode = 1 << 11, // Saved // The central node has 2 main properties: stay visible when empty, only use "remaining" spaces from its neighbor.
2001+ ImGuiDockNodeFlags_NoTabBar = 1 << 12, // Saved // Tab bar is completely unavailable. No triangle in the corner to enable it back.
2002+ ImGuiDockNodeFlags_HiddenTabBar = 1 << 13, // Saved // Tab bar is hidden, with a triangle in the corner to show it again (NB: actual tab-bar instance may be destroyed as this is only used for single-window tab bar)
2003+ ImGuiDockNodeFlags_NoWindowMenuButton = 1 << 14, // Saved // Disable window/docking menu (that one that appears instead of the collapse button)
2004+ ImGuiDockNodeFlags_NoCloseButton = 1 << 15, // Saved // Disable close button
2005+ ImGuiDockNodeFlags_NoResizeX = 1 << 16, // //
2006+ ImGuiDockNodeFlags_NoResizeY = 1 << 17, // //
2007+ ImGuiDockNodeFlags_DockedWindowsInFocusRoute= 1 << 18, // // Any docked window will be automatically be focus-route chained (window->ParentWindowForFocusRoute set to this) so Shortcut() in this window can run when any docked window is focused.
2008+
2009+ // Disable docking/undocking actions in this dockspace or individual node (existing docked nodes will be preserved)
2010+ // Those are not exposed in public because the desirable sharing/inheriting/copy-flag-on-split behaviors are quite difficult to design and understand.
2011+ // The two public flags ImGuiDockNodeFlags_NoDockingOverCentralNode/ImGuiDockNodeFlags_NoDockingSplit don't have those issues.
2012+ ImGuiDockNodeFlags_NoDockingSplitOther = 1 << 19, // // Disable this node from splitting other windows/nodes.
2013+ ImGuiDockNodeFlags_NoDockingOverMe = 1 << 20, // // Disable other windows/nodes from being docked over this node.
2014+ ImGuiDockNodeFlags_NoDockingOverOther = 1 << 21, // // Disable this node from being docked over another window or non-empty node.
2015+ ImGuiDockNodeFlags_NoDockingOverEmpty = 1 << 22, // // Disable this node from being docked over an empty node (e.g. DockSpace with no other windows)
2016+ ImGuiDockNodeFlags_NoDocking = ImGuiDockNodeFlags_NoDockingOverMe | ImGuiDockNodeFlags_NoDockingOverOther | ImGuiDockNodeFlags_NoDockingOverEmpty | ImGuiDockNodeFlags_NoDockingSplit | ImGuiDockNodeFlags_NoDockingSplitOther,
2017+
2018+ // Masks
2019+ ImGuiDockNodeFlags_SharedFlagsInheritMask_ = ~0,
2020+ ImGuiDockNodeFlags_NoResizeFlagsMask_ = (int)ImGuiDockNodeFlags_NoResize | ImGuiDockNodeFlags_NoResizeX | ImGuiDockNodeFlags_NoResizeY,
2021+
2022+ // When splitting, those local flags are moved to the inheriting child, never duplicated
2023+ ImGuiDockNodeFlags_LocalFlagsTransferMask_ = (int)ImGuiDockNodeFlags_NoDockingSplit | ImGuiDockNodeFlags_NoResizeFlagsMask_ | (int)ImGuiDockNodeFlags_AutoHideTabBar | ImGuiDockNodeFlags_CentralNode | ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_HiddenTabBar | ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_NoCloseButton,
2024+ ImGuiDockNodeFlags_SavedFlagsMask_ = ImGuiDockNodeFlags_NoResizeFlagsMask_ | ImGuiDockNodeFlags_DockSpace | ImGuiDockNodeFlags_CentralNode | ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_HiddenTabBar | ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_NoCloseButton,
2025+};
2026+
2027+// Store the source authority (dock node vs window) of a field
2028+enum ImGuiDataAuthority_
2029+{
2030+ ImGuiDataAuthority_Auto,
2031+ ImGuiDataAuthority_DockNode,
2032+ ImGuiDataAuthority_Window,
2033+};
2034+
2035+enum ImGuiDockNodeState
2036+{
2037+ ImGuiDockNodeState_Unknown,
2038+ ImGuiDockNodeState_HostWindowHiddenBecauseSingleWindow,
2039+ ImGuiDockNodeState_HostWindowHiddenBecauseWindowsAreResizing,
2040+ ImGuiDockNodeState_HostWindowVisible,
2041+};
2042+
2043+// sizeof() 176~216
2044+struct IMGUI_API ImGuiDockNode
2045+{
2046+ ImGuiID ID;
2047+ ImGuiDockNodeFlags SharedFlags; // (Write) Flags shared by all nodes of a same dockspace hierarchy (inherited from the root node)
2048+ ImGuiDockNodeFlags LocalFlags; // (Write) Flags specific to this node
2049+ ImGuiDockNodeFlags LocalFlagsInWindows; // (Write) Flags specific to this node, applied from windows
2050+ ImGuiDockNodeFlags MergedFlags; // (Read) Effective flags (== SharedFlags | LocalFlagsInNode | LocalFlagsInWindows)
2051+ ImGuiDockNodeState State;
2052+ ImGuiDockNode* ParentNode;
2053+ ImGuiDockNode* ChildNodes[2]; // [Split node only] Child nodes (left/right or top/bottom). Consider switching to an array.
2054+ ImVector<ImGuiWindow*> Windows; // Note: unordered list! Iterate TabBar->Tabs for user-order.
2055+ ImGuiTabBar* TabBar;
2056+ ImVec2 Pos; // Current position
2057+ ImVec2 Size; // Current size
2058+ ImVec2 SizeRef; // [Split node only] Last explicitly written-to size (overridden when using a splitter affecting the node), used to calculate Size.
2059+ ImGuiAxis SplitAxis; // [Split node only] Split axis (X or Y)
2060+ ImU32 LastBgColor;
2061+ ImGuiWindowClass WindowClass; // [Root node only]
2062+
2063+ ImGuiWindow* HostWindow;
2064+ ImGuiWindow* VisibleWindow; // Generally point to window which is ID is == SelectedTabID, but when CTRL+Tabbing this can be a different window.
2065+ ImGuiDockNode* CentralNode; // [Root node only] Pointer to central node.
2066+ ImGuiDockNode* OnlyNodeWithWindows; // [Root node only] Set when there is a single visible node within the hierarchy.
2067+ int CountNodeWithWindows; // [Root node only]
2068+ int LastFrameAlive; // Last frame number the node was updated or kept alive explicitly with DockSpace() + ImGuiDockNodeFlags_KeepAliveOnly
2069+ int LastFrameActive; // Last frame number the node was updated.
2070+ int LastFrameFocused; // Last frame number the node was focused.
2071+ ImGuiID LastFocusedNodeId; // [Root node only] Which of our child docking node (any ancestor in the hierarchy) was last focused.
2072+ ImGuiID SelectedTabId; // [Leaf node only] Which of our tab/window is selected.
2073+ ImGuiID WantCloseTabId; // [Leaf node only] Set when closing a specific tab/window.
2074+ ImGuiID RefViewportId; // Reference viewport ID from visible window when HostWindow == NULL.
2075+ ImGuiDataAuthority AuthorityForPos :3;
2076+ ImGuiDataAuthority AuthorityForSize :3;
2077+ ImGuiDataAuthority AuthorityForViewport :3;
2078+ bool IsVisible :1; // Set to false when the node is hidden (usually disabled as it has no active window)
2079+ bool IsFocused :1;
2080+ bool IsBgDrawnThisFrame :1;
2081+ bool HasCloseButton :1; // Provide space for a close button (if any of the docked window has one). Note that button may be hidden on window without one.
2082+ bool HasWindowMenuButton :1;
2083+ bool HasCentralNodeChild :1;
2084+ bool WantCloseAll :1; // Set when closing all tabs at once.
2085+ bool WantLockSizeOnce :1;
2086+ bool WantMouseMove :1; // After a node extraction we need to transition toward moving the newly created host window
2087+ bool WantHiddenTabBarUpdate :1;
2088+ bool WantHiddenTabBarToggle :1;
2089+
2090+ ImGuiDockNode(ImGuiID id);
2091+ ~ImGuiDockNode();
2092+ bool IsRootNode() const { return ParentNode == NULL; }
2093+ bool IsDockSpace() const { return (MergedFlags & ImGuiDockNodeFlags_DockSpace) != 0; }
2094+ bool IsFloatingNode() const { return ParentNode == NULL && (MergedFlags & ImGuiDockNodeFlags_DockSpace) == 0; }
2095+ bool IsCentralNode() const { return (MergedFlags & ImGuiDockNodeFlags_CentralNode) != 0; }
2096+ bool IsHiddenTabBar() const { return (MergedFlags & ImGuiDockNodeFlags_HiddenTabBar) != 0; } // Hidden tab bar can be shown back by clicking the small triangle
2097+ bool IsNoTabBar() const { return (MergedFlags & ImGuiDockNodeFlags_NoTabBar) != 0; } // Never show a tab bar
2098+ bool IsSplitNode() const { return ChildNodes[0] != NULL; }
2099+ bool IsLeafNode() const { return ChildNodes[0] == NULL; }
2100+ bool IsEmpty() const { return ChildNodes[0] == NULL && Windows.Size == 0; }
2101+ ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
2102+
2103+ void SetLocalFlags(ImGuiDockNodeFlags flags) { LocalFlags = flags; UpdateMergedFlags(); }
2104+ void UpdateMergedFlags() { MergedFlags = SharedFlags | LocalFlags | LocalFlagsInWindows; }
2105+};
2106+
2107+// List of colors that are stored at the time of Begin() into Docked Windows.
2108+// We currently store the packed colors in a simple array window->DockStyle.Colors[].
2109+// A better solution may involve appending into a log of colors in ImGuiContext + store offsets into those arrays in ImGuiWindow,
2110+// but it would be more complex as we'd need to double-buffer both as e.g. drop target may refer to window from last frame.
2111+enum ImGuiWindowDockStyleCol
2112+{
2113+ ImGuiWindowDockStyleCol_Text,
2114+ ImGuiWindowDockStyleCol_TabHovered,
2115+ ImGuiWindowDockStyleCol_TabFocused,
2116+ ImGuiWindowDockStyleCol_TabSelected,
2117+ ImGuiWindowDockStyleCol_TabSelectedOverline,
2118+ ImGuiWindowDockStyleCol_TabDimmed,
2119+ ImGuiWindowDockStyleCol_TabDimmedSelected,
2120+ ImGuiWindowDockStyleCol_TabDimmedSelectedOverline,
2121+ ImGuiWindowDockStyleCol_UnsavedMarker,
2122+ ImGuiWindowDockStyleCol_COUNT
2123+};
2124+
2125+// We don't store style.Alpha: dock_node->LastBgColor embeds it and otherwise it would only affect the docking tab, which intuitively I would say we don't want to.
2126+struct ImGuiWindowDockStyle
2127+{
2128+ ImU32 Colors[ImGuiWindowDockStyleCol_COUNT];
2129+};
2130+
2131+struct ImGuiDockContext
2132+{
2133+ ImGuiStorage Nodes; // Map ID -> ImGuiDockNode*: Active nodes
2134+ ImVector<ImGuiDockRequest> Requests;
2135+ ImVector<ImGuiDockNodeSettings> NodesSettings;
2136+ bool WantFullRebuild;
2137+ ImGuiDockContext() { memset((void*)this, 0, sizeof(*this)); }
2138+};
2139+
19632140 #endif // #ifdef IMGUI_HAS_DOCK
19642141
19652142 //-----------------------------------------------------------------------------
@@ -1970,10 +2147,24 @@
19702147 // Every instance of ImGuiViewport is in fact a ImGuiViewportP.
19712148 struct ImGuiViewportP : public ImGuiViewport
19722149 {
2150+ ImGuiWindow* Window; // Set when the viewport is owned by a window (and ImGuiViewportFlags_CanHostOtherWindows is NOT set)
2151+ int Idx;
2152+ int LastFrameActive; // Last frame number this viewport was activated by a window
2153+ int LastFocusedStampCount; // Last stamp number from when a window hosted by this viewport was focused (by comparing this value between two viewport we have an implicit viewport z-order we use as fallback)
2154+ ImGuiID LastNameHash;
2155+ ImVec2 LastPos;
2156+ ImVec2 LastSize;
2157+ float Alpha; // Window opacity (when dragging dockable windows/viewports we make them transparent)
2158+ float LastAlpha;
2159+ bool LastFocusedHadNavWindow;// Instead of maintaining a LastFocusedWindow (which may harder to correctly maintain), we merely store weither NavWindow != NULL last time the viewport was focused.
2160+ short PlatformMonitor;
19732161 float BgFgDrawListsLastTimeActive[2]; // Last frame number the background (0) and foreground (1) draw lists were used
19742162 ImDrawList* BgFgDrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays.
19752163 ImDrawData DrawDataP;
19762164 ImDrawDataBuilder DrawDataBuilder; // Temporary data while building final ImDrawData
2165+ ImVec2 LastPlatformPos;
2166+ ImVec2 LastPlatformSize;
2167+ ImVec2 LastRendererSize;
19772168
19782169 // Per-viewport work area
19792170 // - Insets are >= 0.0f values, distance from viewport corners to work area.
@@ -1984,8 +2175,9 @@
19842175 ImVec2 BuildWorkInsetMin; // Work Area inset accumulator for current frame, to become next frame's WorkInset
19852176 ImVec2 BuildWorkInsetMax; // "
19862177
1987- ImGuiViewportP() { BgFgDrawListsLastTimeActive[0] = BgFgDrawListsLastTimeActive[1] = -1.0f; BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; }
1988- ~ImGuiViewportP() { if (BgFgDrawLists[0]) IM_DELETE(BgFgDrawLists[0]); if (BgFgDrawLists[1]) IM_DELETE(BgFgDrawLists[1]); }
2178+ ImGuiViewportP() { Window = NULL; Idx = -1; LastFrameActive = LastFocusedStampCount = -1; BgFgDrawListsLastTimeActive[0] = BgFgDrawListsLastTimeActive[1] = -1.0f; LastNameHash = 0; Alpha = LastAlpha = 1.0f; LastFocusedHadNavWindow = false; PlatformMonitor = -1; BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; LastPlatformPos = LastPlatformSize = LastRendererSize = ImVec2(FLT_MAX, FLT_MAX); }
2179+ ~ImGuiViewportP() { if (BgFgDrawLists[0]) IM_DELETE(BgFgDrawLists[0]); if (BgFgDrawLists[1]) IM_DELETE(BgFgDrawLists[1]); }
2180+ void ClearRequestFlags() { PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; }
19892181
19902182 // Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect)
19912183 ImVec2 CalcWorkRectPos(const ImVec2& inset_min) const { return ImVec2(Pos.x + inset_min.x, Pos.y + inset_min.y); }
@@ -2008,14 +2200,19 @@
20082200 struct ImGuiWindowSettings
20092201 {
20102202 ImGuiID ID;
2011- ImVec2ih Pos;
2203+ ImVec2ih Pos; // NB: Settings position are stored RELATIVE to the viewport! Whereas runtime ones are absolute positions.
20122204 ImVec2ih Size;
2205+ ImVec2ih ViewportPos;
2206+ ImGuiID ViewportId;
2207+ ImGuiID DockId; // ID of last known DockNode (even if the DockNode is invisible because it has only 1 active window), or 0 if none.
2208+ ImGuiID ClassId; // ID of window class if specified
2209+ short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible.
20132210 bool Collapsed;
20142211 bool IsChild;
20152212 bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context)
20162213 bool WantDelete; // Set to invalidate/delete the settings entry
20172214
2018- ImGuiWindowSettings() { memset((void*)this, 0, sizeof(*this)); }
2215+ ImGuiWindowSettings() { memset((void*)this, 0, sizeof(*this)); DockOrder = -1; }
20192216 char* GetName() { return (char*)(this + 1); }
20202217 };
20212218
@@ -2045,12 +2242,18 @@
20452242 ImGuiLocKey_TableSizeOne,
20462243 ImGuiLocKey_TableSizeAllFit,
20472244 ImGuiLocKey_TableSizeAllDefault,
2245+ ImGuiLocKey_TableReset,
2246+ //ImGuiLocKey_TableResetAll,
20482247 ImGuiLocKey_TableResetOrder,
2248+ ImGuiLocKey_TableResetVisibility,
20492249 ImGuiLocKey_WindowingMainMenuBar,
20502250 ImGuiLocKey_WindowingPopup,
20512251 ImGuiLocKey_WindowingUntitled,
20522252 ImGuiLocKey_OpenLink_s,
20532253 ImGuiLocKey_CopyLink,
2254+ ImGuiLocKey_DockingHideTabBar,
2255+ ImGuiLocKey_DockingHoldShiftToDock,
2256+ ImGuiLocKey_DockingDragToUndockOrMoveNode,
20542257 ImGuiLocKey_COUNT
20552258 };
20562259
@@ -2097,10 +2300,11 @@
20972300 ImGuiDebugLogFlags_EventIO = 1 << 7,
20982301 ImGuiDebugLogFlags_EventFont = 1 << 8,
20992302 ImGuiDebugLogFlags_EventInputRouting = 1 << 9,
2100- ImGuiDebugLogFlags_EventDocking = 1 << 10, // Unused in this branch
2101- ImGuiDebugLogFlags_EventViewport = 1 << 11, // Unused in this branch
2303+ ImGuiDebugLogFlags_EventDocking = 1 << 10,
2304+ ImGuiDebugLogFlags_EventViewport = 1 << 11,
2305+ ImGuiDebugLogFlags_EventTable = 1 << 12,
21022306
2103- ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventIO | ImGuiDebugLogFlags_EventFont | ImGuiDebugLogFlags_EventInputRouting | ImGuiDebugLogFlags_EventDocking | ImGuiDebugLogFlags_EventViewport,
2307+ ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventTable | ImGuiDebugLogFlags_EventIO | ImGuiDebugLogFlags_EventFont | ImGuiDebugLogFlags_EventInputRouting | ImGuiDebugLogFlags_EventDocking | ImGuiDebugLogFlags_EventViewport,
21042308 ImGuiDebugLogFlags_OutputToTTY = 1 << 20, // Also send output to TTY
21052309 ImGuiDebugLogFlags_OutputToDebugger = 1 << 21, // Also send output to Debugger Console [Windows only]
21062310 ImGuiDebugLogFlags_OutputToTestEngine = 1 << 22, // Also send output to Dear ImGui Test Engine
@@ -2134,6 +2338,7 @@
21342338 bool ShowDrawCmdBoundingBoxes = true;
21352339 bool ShowTextEncodingViewer = false;
21362340 bool ShowTextureUsedRect = false;
2341+ bool ShowDockingNodes = false;
21372342 int ShowWindowsRectsType = -1;
21382343 int ShowTablesRectsType = -1;
21392344 int HighlightMonitorIdx = -1;
@@ -2208,12 +2413,15 @@
22082413 bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log()
22092414 int FrameCount;
22102415 int FrameCountEnded;
2416+ int FrameCountPlatformEnded;
22112417 int FrameCountRendered;
22122418 double Time;
22132419 char ContextName[16]; // Storage for a context name (to facilitate debugging multi-context setups)
22142420 ImGuiIO IO;
22152421 ImGuiPlatformIO PlatformIO;
22162422 ImGuiStyle Style;
2423+ ImGuiConfigFlags ConfigFlagsCurrFrame; // = g.IO.ConfigFlags at the time of NewFrame()
2424+ ImGuiConfigFlags ConfigFlagsLastFrame;
22172425 ImVector<ImFontAtlas*> FontAtlases; // List of font atlases used by the context (generally only contains g.IO.Fonts aka the main font atlas)
22182426 ImFont* Font; // Currently bound font. (== FontStack.back().Font)
22192427 ImFontBaked* FontBaked; // Currently bound font at currently bound size. (== Font->GetFontBaked(FontSize))
@@ -2246,7 +2454,7 @@
22462454 ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs.
22472455 ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set.
22482456 ImGuiWindow* HoveredWindowBeforeClear; // Window the mouse is hovering. Filled even with _NoMouse. This is currently useful for multi-context compositors.
2249- ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow.
2457+ ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindowDockTree.
22502458 ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window.
22512459 ImVec2 WheelingWindowRefMousePos;
22522460 int WheelingWindowStartFrame; // This may be set one frame before WheelingWindow is != NULL
@@ -2325,7 +2533,16 @@
23252533 ImVector<ImGuiTreeNodeStackData>TreeNodeStack; // Stack for TreeNode()
23262534
23272535 // Viewports
2328- ImVector<ImGuiViewportP*> Viewports; // Active viewports (Size==1 in 'master' branch). Each viewports hold their copy of ImDrawData.
2536+ ImVector<ImGuiViewportP*> Viewports; // Active viewports (always 1+, and generally 1 unless multi-viewports are enabled). Each viewports hold their copy of ImDrawData.
2537+ ImGuiViewportP* CurrentViewport; // We track changes of viewport (happening in Begin) so we can call Platform_OnChangedViewport()
2538+ ImGuiViewportP* MouseViewport;
2539+ ImGuiViewportP* MouseLastHoveredViewport; // Last known viewport that was hovered by mouse (even if we are not hovering any viewport any more) + honoring the _NoInputs flag.
2540+ ImGuiID PlatformLastFocusedViewportId;
2541+ ImGuiPlatformMonitor FallbackMonitor; // Virtual monitor used as fallback if backend doesn't provide monitor information.
2542+ ImRect PlatformMonitorsFullWorkRect; // Bounding box of all platform monitors
2543+ int ViewportCreatedCount; // Unique sequential creation counter (mostly for testing/debugging)
2544+ int PlatformWindowsCreatedCount; // Unique sequential creation counter (mostly for testing/debugging)
2545+ int ViewportFocusedStampCount; // Every time the front-most window changes, we stamp its viewport with an incrementing counter
23292546
23302547 // Keyboard/Gamepad Navigation
23312548 bool NavCursorVisible; // Nav focus cursor/rectangle is visible? We hide it after a mouse click. We show it after a nav move.
@@ -2515,6 +2732,8 @@
25152732 // Extensions
25162733 // FIXME: We could provide an API to register one slot in an array held in ImGuiContext?
25172734 ImVector<ImTextureData*> UserTextures; // List of textures created/managed by user or third-party extension. Automatically appended into platform_io.Textures[].
2735+ ImGuiDockContext DockContext;
2736+ void (*DockNodeWindowMenuHandler)(ImGuiContext* ctx, ImGuiDockNode* node, ImGuiTabBar* tab_bar);
25182737
25192738 // Settings
25202739 bool SettingsLoaded;
@@ -2577,6 +2796,7 @@
25772796 ImGuiDebugItemPathQuery DebugItemPathQuery;
25782797 ImGuiIDStackTool DebugIDStackTool;
25792798 ImGuiDebugAllocInfo DebugAllocInfo;
2799+ ImGuiDockNode* DebugHoveredDockNode; // Hovered dock node.
25802800 #if defined(IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS) && !defined(IMGUI_DISABLE_DEBUG_TOOLS)
25812801 ImGuiStorage DebugDrawIdConflictsAliveCount;
25822802 ImGuiStorage DebugDrawIdConflictsHighlightSet;
@@ -2647,8 +2867,12 @@
26472867 ImGuiLayoutType LayoutType;
26482868 ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin()
26492869 ImU32 ModalDimBgColor;
2870+
2871+ // Status flags
26502872 ImGuiItemStatusFlags WindowItemStatusFlags;
26512873 ImGuiItemStatusFlags ChildItemStatusFlags;
2874+ ImGuiItemStatusFlags DockTabItemStatusFlags;
2875+ ImRect DockTabItemRect;
26522876
26532877 // Local parameters stacks
26542878 // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings.
@@ -2665,9 +2889,13 @@
26652889 ImGuiContext* Ctx; // Parent UI context (needs to be set explicitly by parent).
26662890 char* Name; // Window name, owned by the window.
26672891 ImGuiID ID; // == ImHashStr(Name)
2668- ImGuiWindowFlags Flags; // See enum ImGuiWindowFlags_
2892+ ImGuiWindowFlags Flags, FlagsPreviousFrame; // See enum ImGuiWindowFlags_
26692893 ImGuiChildFlags ChildFlags; // Set when window is a child window. See enum ImGuiChildFlags_
2894+ ImGuiWindowClass WindowClass; // Advanced users only. Set with SetNextWindowClass()
26702895 ImGuiViewportP* Viewport; // Always set in Begin(). Inactive windows may have a NULL value here if their viewport was discarded.
2896+ ImGuiID ViewportId; // We backup the viewport id (since the viewport may disappear or never be created if the window is inactive)
2897+ ImVec2 ViewportPos; // We backup the viewport position (since the viewport may disappear or never be created if the window is inactive)
2898+ int ViewportAllowPlatformMonitorExtend; // Reset to -1 every frame (index is guaranteed to be valid between NewFrame..EndFrame), only used in the Appearing frame of a tooltip/popup to enforce clamping to a given monitor
26712899 ImVec2 Pos; // Position (always rounded-up to nearest pixel)
26722900 ImVec2 Size; // Current size (==SizeFull or collapsed title bar size)
26732901 ImVec2 SizeFull; // Size when non collapsed
@@ -2683,6 +2911,7 @@
26832911 float DecoInnerSizeX1, DecoInnerSizeY1; // Applied AFTER/OVER InnerRect. Specialized for Tables as they use specialized form of clipping and frozen rows/columns are inside InnerRect (and not part of regular decoration sizes).
26842912 int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)!
26852913 ImGuiID MoveId; // == window->GetID("#MOVE")
2914+ ImGuiID TabId; // == window->GetID("#TAB")
26862915 ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window)
26872916 ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling)
26882917 ImVec2 Scroll;
@@ -2694,6 +2923,7 @@
26942923 bool ScrollbarX, ScrollbarY; // Are scrollbars visible?
26952924 bool ScrollbarXStabilizeEnabled; // Was ScrollbarX previously auto-stabilized?
26962925 ImU8 ScrollbarXStabilizeToggledHistory; // Used to stabilize scrollbar visibility in case of feedback loops
2926+ bool ViewportOwned;
26972927 bool Active; // Set to true on Begin(), unless Collapsed
26982928 bool WasActive;
26992929 bool WriteAccessed; // Set to true when any widget access the current window
@@ -2724,6 +2954,7 @@
27242954 ImGuiCond SetWindowPosAllowFlags : 8; // store acceptable condition flags for SetNextWindowPos() use.
27252955 ImGuiCond SetWindowSizeAllowFlags : 8; // store acceptable condition flags for SetNextWindowSize() use.
27262956 ImGuiCond SetWindowCollapsedAllowFlags : 8; // store acceptable condition flags for SetNextWindowCollapsed() use.
2957+ ImGuiCond SetWindowDockAllowFlags : 8; // store acceptable condition flags for SetNextWindowDock() use.
27272958 ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size)
27282959 ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0, 0) when positioning from top-left corner; ImVec2(0.5f, 0.5f) for centering; ImVec2(1, 1) for bottom right.
27292960
@@ -2743,6 +2974,7 @@
27432974 ImVec2ih HitTestHoleOffset;
27442975
27452976 int LastFrameActive; // Last frame number the window was Active.
2977+ int LastFrameJustFocused; // Last frame number the window was made Focused.
27462978 float LastTimeActive; // Last timestamp the window was Active (using float as we don't need high precision there)
27472979 ImGuiStorage StateStorage;
27482980 ImVector<ImGuiOldColumns> ColumnsStorage;
@@ -2757,6 +2989,7 @@
27572989 ImGuiWindow* ParentWindowInBeginStack;
27582990 ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window. Doesn't cross through popups/dock nodes.
27592991 ImGuiWindow* RootWindowPopupTree; // Point to ourself or first ancestor that is not a child window. Cross through popups parent<>child.
2992+ ImGuiWindow* RootWindowDockTree; // Point to ourself or first ancestor that is not a child window. Cross through dock nodes.
27602993 ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active.
27612994 ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag.
27622995 ImGuiWindow* ParentWindowForFocusRoute; // Set to manual link a window to its logical parent so that Shortcut() chain are honored (e.g. Tool linked to Document)
@@ -2771,6 +3004,17 @@
27713004 int MemoryDrawListVtxCapacity;
27723005 bool MemoryCompacted; // Set when window extraneous data have been garbage collected
27733006
3007+ // Docking
3008+ bool DockIsActive :1; // When docking artifacts are actually visible. When this is set, DockNode is guaranteed to be != NULL. ~~ (DockNode != NULL) && (DockNode->Windows.Size > 1).
3009+ bool DockNodeIsVisible :1;
3010+ bool DockTabIsVisible :1; // Is our window visible this frame? ~~ is the corresponding tab selected?
3011+ bool DockTabWantClose :1;
3012+ short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible.
3013+ ImGuiWindowDockStyle DockStyle;
3014+ ImGuiDockNode* DockNode; // Which node are we docked into. Important: Prefer testing DockIsActive in many cases as this will still be set when the dock node is hidden.
3015+ ImGuiDockNode* DockNodeAsHost; // Which node are we owning (for parent windows)
3016+ ImGuiID DockId; // Backup of last valid DockNode->ID, so single window remember their dock node id even when they are not bound any more
3017+
27743018 public:
27753019 ImGuiWindow(ImGuiContext* context, const char* name);
27763020 ~ImGuiWindow();
@@ -2787,7 +3031,7 @@
27873031 ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight; return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight); }
27883032
27893033 // [OBSOLETE] ImGuiWindow::CalcFontSize() was removed in 1.92.0 because error-prone/misleading. You can use window->FontRefSize for a copy of g.FontSize at the time of the last Begin() call for this window.
2790- //float CalcFontSize() const { ImGuiContext& g = *Ctx; return g.FontSizeBase * FontWindowScale * FontWindowScaleParents;
3034+ //float CalcFontSize() const { ImGuiContext& g = *Ctx; return g.FontSizeBase * FontWindowScale * FontDpiScale * FontWindowScaleParents;
27913035 };
27923036
27933037 //-----------------------------------------------------------------------------
@@ -2809,14 +3053,15 @@
28093053 ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout)
28103054 ImGuiTabItemFlags_Button = 1 << 21, // Used by TabItemButton, change the tab item behavior to mimic a button
28113055 ImGuiTabItemFlags_Invisible = 1 << 22, // To reserve space e.g. with ImGuiTabItemFlags_Leading
2812- //ImGuiTabItemFlags_Unsorted = 1 << 23, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window.
3056+ ImGuiTabItemFlags_Unsorted = 1 << 23, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window.
28133057 };
28143058
2815-// Storage for one active tab item (sizeof() 40 bytes)
3059+// Storage for one active tab item (sizeof() 48 bytes)
28163060 struct ImGuiTabItem
28173061 {
28183062 ImGuiID ID;
28193063 ImGuiTabItemFlags Flags;
3064+ ImGuiWindow* Window; // When TabItem is part of a DockNode's TabBar, we hold on to a window.
28203065 int LastFrameVisible;
28213066 int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance
28223067 float Offset; // Position relative to beginning of tab bar
@@ -2876,13 +3121,13 @@
28763121 };
28773122
28783123 //-----------------------------------------------------------------------------
2879-// [SECTION] Table support
3124+// [SECTION] Table support + internal API
28803125 //-----------------------------------------------------------------------------
28813126
28823127 #define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color.
28833128 #define IMGUI_TABLE_MAX_COLUMNS 512 // Arbitrary "safety" maximum, may be lifted in the future if needed. Must fit in ImGuiTableColumnIdx/ImGuiTableDrawChannelIdx.
28843129
2885-// [Internal] sizeof() ~ 112
3130+// [Internal] sizeof() ~ 120
28863131 // We use the terminology "Enabled" to refer to a column that is not Hidden by user/api.
28873132 // We use the terminology "Clipped" to refer to a column that is out of sight because of scrolling/clipping.
28883133 // This is in contrast with some user-facing api such as IsItemVisible() / IsRectVisible() which use "Visible" to mean "not clipped".
@@ -2898,7 +3143,8 @@
28983143 float StretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially.
28993144 float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_).
29003145 ImRect ClipRect; // Clipping rectangle for the column
2901- ImGuiID UserID; // Optional, value passed to TableSetupColumn()
3146+ ImGuiID ID; // Hash of column name (ignoring top of ID stack), used for .ini persistence when available.
3147+ ImGuiID UserData; // (Optional) User data value passed to TableSetupColumn()
29023148 float WorkMinX; // Contents region min ~(MinX + CellPaddingX + CellSpacingX1) == cursor start position when entering column
29033149 float WorkMaxX; // Contents region max ~(MaxX - CellPaddingX - CellSpacingX2)
29043150 float ItemWidth; // Current item width for the column, preserved across rows
@@ -2922,10 +3168,14 @@
29223168 bool IsVisibleY;
29233169 bool IsRequestOutput; // Return value for TableSetColumnIndex() / TableNextColumn(): whether we request user to output contents or not.
29243170 bool IsSkipItems; // Do we want item submissions to this column to be completely ignored (no layout will happen).
2925- bool IsPreserveWidthAuto;
3171+ bool IsPreserveWidthAuto : 1;
3172+ bool IsJustCreated : 1;
3173+ bool IsLoadedSettings : 1;
3174+ bool IsNeedReconcileSrc : 1;
3175+ bool IsNeedReconcileDst : 1;
29263176 ImS8 NavLayerCurrent; // ImGuiNavLayer in 1 byte
2927- ImU8 AutoFitQueue; // Queue of 8 values for the next 8 frames to request auto-fit
2928- ImU8 CannotSkipItemsQueue; // Queue of 8 values for the next 8 frames to disable Clipped/SkipItem
3177+ ImU8 AutoFitQueue : 4; // Queue of 4 values for the next 4 frames to request auto-fit
3178+ ImU8 CannotSkipItemsQueue : 4; // Queue of 4 values for the next 4 frames to disable Clipped/SkipItem
29293179 ImU8 SortDirection : 2; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending
29303180 ImU8 SortDirectionsAvailCount : 2; // Number of available sort directions (0 to 3)
29313181 ImU8 SortDirectionsAvailMask : 4; // Mask of available sort directions (1-bit each)
@@ -2940,10 +3190,28 @@
29403190 PrevEnabledColumn = NextEnabledColumn = -1;
29413191 SortOrder = -1;
29423192 SortDirection = ImGuiSortDirection_None;
3193+ IsJustCreated = true;
29433194 DrawChannelCurrent = DrawChannelFrozen = DrawChannelUnfrozen = (ImU8)-1;
29443195 }
29453196 };
29463197
3198+// Passed to TableSetupColumn()
3199+// sizeof() ~ 24+120 bytes
3200+struct ImGuiTableReconcileColumnData
3201+{
3202+ // Setup data
3203+ ImGuiID ID;
3204+ ImS16 NameOffset;
3205+ ImGuiTableColumnFlags Flags;
3206+ float InitWidthOrWeight;
3207+ ImGuiID UserData;
3208+
3209+ // Reconcile data
3210+ ImGuiTableColumnIdx ColumnNewIdx; // Index in the current table.
3211+ ImGuiTableColumnIdx ColumnOldIdx; // Index in the previous frame table.
3212+ ImGuiTableColumn ColumnOldData; // Full backup of the column. Could be avoided by storing 1 of them and applying reconcile in the right order. Not worth bothering.
3213+};
3214+
29473215 // Transient cell data stored per row.
29483216 // sizeof() ~ 6 bytes
29493217 struct ImGuiTableCellData
@@ -3077,6 +3345,7 @@
30773345 bool IsLayoutLocked; // Set by TableUpdateLayout() which is called when beginning the first row.
30783346 bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow().
30793347 bool IsInitializing;
3348+ bool IsReconcileMode;
30803349 bool IsSortSpecsDirty;
30813350 bool IsUsingHeaders; // Set when the first row had the ImGuiTableRowFlags_Headers flag.
30823351 bool IsContextPopupOpen; // Set when default context menu is open (also see: ContextPopupColumn, InstanceInteracted).
@@ -3084,8 +3353,10 @@
30843353 bool IsSettingsRequestLoad;
30853354 bool IsSettingsDirty; // Set when table settings have changed and needs to be reported into ImGuiTableSettings data.
30863355 bool IsDefaultDisplayOrder; // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1)
3087- bool IsResetAllRequest;
3356+ bool IsDefaultVisibility; // Set when enabled/visibility is unchanged from default
3357+ bool IsResetAllRequest; // Set to queue a call to TableResetSettings() in BeginTable()
30883358 bool IsResetDisplayOrderRequest;
3359+ bool IsResetVisibilityRequest;
30893360 bool IsUnfrozenRows; // Set when we got past the frozen row.
30903361 bool IsDefaultSizingPolicy; // Set if user didn't explicitly set a sizing policy in BeginTable()
30913362 bool IsActiveIdAliveBeforeTable;
@@ -3103,15 +3374,20 @@
31033374 // - Accessing those requires chasing an extra pointer so for very frequently used data we leave them in the main table structure.
31043375 // - We also leave out of this structure data that tend to be particularly useful for debugging/metrics.
31053376 // FIXME-TABLE: more transient data could be stored in a stacked ImGuiTableTempData: e.g. SortSpecs.
3106-// sizeof() ~ 136 bytes.
3377+// sizeof() ~ 176 bytes.
31073378 struct IMGUI_API ImGuiTableTempData
31083379 {
31093380 ImGuiID WindowID; // Shortcut to g.Tables[TableIndex]->OuterWindow->ID.
31103381 int TableIndex; // Index in g.Tables.Buf[] pool
31113382 float LastTimeActive; // Last timestamp this structure was used
31123383 float AngledHeadersExtraWidth; // Used in EndTable()
3113- ImVector<ImGuiTableHeaderData> AngledHeadersRequests; // Used in TableAngledHeadersRow()
3384+ ImVector<ImGuiTableHeaderData> AngledHeadersRequests; // Used in TableAngledHeadersRow() // FIXME: Single instance is enough?
31143385
3386+ // Topology change
3387+ ImVector<ImGuiTableReconcileColumnData> ReconcileColumnsRequests; // Used in TableSetupColumn(), TableUpdateLayout(). Cleared every frame.
3388+ void* OldColumnsRawData; // Used in BeginTable() -> TableUpdateLayout() when resizing.
3389+ ImSpan<ImGuiTableColumn> OldColumnsData;
3390+
31153391 ImVec2 UserOuterSize; // outer_size.x passed to BeginTable()
31163392 ImDrawListSplitter DrawSplitter;
31173393
@@ -3131,23 +3407,25 @@
31313407 struct ImGuiTableColumnSettings
31323408 {
31333409 float WidthOrWeight;
3134- ImGuiID UserID;
3410+ ImGuiID ID;
31353411 ImGuiTableColumnIdx Index;
31363412 ImGuiTableColumnIdx DisplayOrder;
31373413 ImGuiTableColumnIdx SortOrder;
31383414 ImU8 SortDirection : 2;
3139- ImS8 IsEnabled : 2; // "Visible" in ini file
3415+ ImS8 IsEnabled : 2; // "Visible" in .ini file
31403416 ImU8 IsStretch : 1;
3417+ bool IsLoaded : 1; // Using during loading to mark finding a matching column.
31413418
31423419 ImGuiTableColumnSettings()
31433420 {
31443421 WidthOrWeight = 0.0f;
3145- UserID = 0;
3422+ ID = 0;
31463423 Index = -1;
31473424 DisplayOrder = SortOrder = -1;
31483425 SortDirection = ImGuiSortDirection_None;
31493426 IsEnabled = -1;
31503427 IsStretch = 0;
3428+ IsLoaded = false;
31513429 }
31523430 };
31533431
@@ -3165,6 +3443,87 @@
31653443 ImGuiTableColumnSettings* GetColumnSettings() { return (ImGuiTableColumnSettings*)(this + 1); }
31663444 };
31673445
3446+namespace ImGui
3447+{
3448+ // Tables: Candidates for public API
3449+ IMGUI_API void TableOpenContextMenu(int column_n = -1);
3450+ IMGUI_API void TableSetColumnWidth(int column_n, float width);
3451+ IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs);
3452+ IMGUI_API int TableGetHoveredRow(); // Retrieve *PREVIOUS FRAME* hovered row. This difference with TableGetHoveredColumn() is the reason why this is not public yet.
3453+ IMGUI_API float TableGetHeaderRowHeight();
3454+ IMGUI_API float TableGetHeaderAngledMaxLabelWidth();
3455+ IMGUI_API void TablePushBackgroundChannel();
3456+ IMGUI_API void TablePopBackgroundChannel();
3457+ IMGUI_API void TablePushColumnChannel(int column_n);
3458+ IMGUI_API void TablePopColumnChannel();
3459+ IMGUI_API void TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label_width, const ImGuiTableHeaderData* data, int data_count);
3460+
3461+ // Tables: Internals
3462+ inline ImGuiTable* GetCurrentTable() { ImGuiContext& g = *GImGui; return g.CurrentTable; }
3463+ IMGUI_API ImGuiTable* TableFindByID(ImGuiID id);
3464+ IMGUI_API bool BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f);
3465+ IMGUI_API void TableBeginInitMemory(ImGuiTable* table, int columns_count);
3466+ IMGUI_API void TableApplyQueuedRequests(ImGuiTable* table);
3467+ IMGUI_API void TableSetupDrawChannels(ImGuiTable* table);
3468+ IMGUI_API void TableReconcileColumns(ImGuiTable* table);
3469+ IMGUI_API void TableUpdateLayout(ImGuiTable* table);
3470+ IMGUI_API void TableUpdateBorders(ImGuiTable* table);
3471+ IMGUI_API void TableUpdateColumnsWeightFromWidth(ImGuiTable* table);
3472+ IMGUI_API void TableApplyExternalUnclipRect(ImGuiTable* table, ImRect& rect);
3473+ IMGUI_API void TableDrawBorders(ImGuiTable* table);
3474+ IMGUI_API void TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags_for_section_to_display);
3475+ IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table);
3476+ IMGUI_API void TableMergeDrawChannels(ImGuiTable* table);
3477+ inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; }
3478+ inline ImGuiID TableGetInstanceID(ImGuiTable* table, int instance_no) { return TableGetInstanceData(table, instance_no)->TableInstanceID; }
3479+ IMGUI_API void TableFixDisplayOrder(ImGuiTable* table);
3480+ IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table);
3481+ IMGUI_API void TableSortSpecsBuild(ImGuiTable* table);
3482+ IMGUI_API void TableInitColumnDefaults(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags init_mask);
3483+ IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column);
3484+ IMGUI_API void TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column);
3485+ IMGUI_API float TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column);
3486+ IMGUI_API void TableBeginRow(ImGuiTable* table);
3487+ IMGUI_API void TableEndRow(ImGuiTable* table);
3488+ IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n);
3489+ IMGUI_API void TableEndCell(ImGuiTable* table);
3490+ IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n);
3491+ IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n);
3492+ IMGUI_API ImGuiID TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no = 0);
3493+ IMGUI_API float TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n);
3494+ IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n);
3495+ IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table);
3496+ IMGUI_API void TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order);
3497+ IMGUI_API void TableQueueSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order);
3498+ IMGUI_API void TableRemove(ImGuiTable* table);
3499+ IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table);
3500+ IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table);
3501+ IMGUI_API void TableGcCompactSettings();
3502+
3503+ // Tables: Settings
3504+ IMGUI_API void TableLoadSettings(ImGuiTable* table);
3505+ IMGUI_API void TableLoadSettingsForColumns(ImGuiTable* table);
3506+ IMGUI_API void TableLoadSettingsForColumn(ImGuiTableColumn* column, ImGuiTableColumnSettings* column_settings, ImGuiTableFlags load_flags);
3507+ IMGUI_API void TableSaveSettings(ImGuiTable* table);
3508+ IMGUI_API void TableResetSettings(ImGuiTable* table);
3509+ IMGUI_API ImGuiTableSettings* TableGetBoundSettings(ImGuiTable* table);
3510+ IMGUI_API void TableSettingsAddSettingsHandler();
3511+ IMGUI_API ImGuiTableSettings* TableSettingsCreate(ImGuiID id, int columns_count);
3512+ IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id);
3513+
3514+ // Legacy Columns API (this is not exposed because we will encourage transitioning to the Tables API)
3515+ IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect);
3516+ IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiOldColumnFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns().
3517+ IMGUI_API void EndColumns(); // close columns
3518+ IMGUI_API void PushColumnClipRect(int column_index);
3519+ IMGUI_API void PushColumnsBackground();
3520+ IMGUI_API void PopColumnsBackground();
3521+ IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count);
3522+ IMGUI_API ImGuiOldColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id);
3523+ IMGUI_API float GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm);
3524+ IMGUI_API float GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset);
3525+}
3526+
31683527 //-----------------------------------------------------------------------------
31693528 // [SECTION] ImGui internal API
31703529 // No guarantee of forward compatibility here!
@@ -3187,7 +3546,7 @@
31873546 IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window);
31883547 IMGUI_API void UpdateWindowSkipRefresh(ImGuiWindow* window);
31893548 IMGUI_API ImVec2 CalcWindowNextAutoFitSize(ImGuiWindow* window);
3190- IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy);
3549+ IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy, bool dock_hierarchy);
31913550 IMGUI_API bool IsWindowInBeginStack(ImGuiWindow* window);
31923551 IMGUI_API bool IsWindowWithinBeginStackOf(ImGuiWindow* window, ImGuiWindow* potential_parent);
31933552 IMGUI_API bool IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below);
@@ -3197,7 +3556,7 @@
31973556 IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond = 0);
31983557 IMGUI_API void SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size);
31993558 IMGUI_API void SetWindowHiddenAndSkipItemsForCurrentFrame(ImGuiWindow* window);
3200- inline void SetWindowParentWindowForFocusRoute(ImGuiWindow* window, ImGuiWindow* parent_window) { window->ParentWindowForFocusRoute = parent_window; }
3559+ inline void SetWindowParentWindowForFocusRoute(ImGuiWindow* window, ImGuiWindow* parent_window) { window->ParentWindowForFocusRoute = parent_window; } // You may also use SetNextWindowClass()'s FocusRouteParentWindowId field.
32013560 inline ImRect WindowRectAbsToRel(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x - off.x, r.Min.y - off.y, r.Max.x - off.x, r.Max.y - off.y); }
32023561 inline ImRect WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); }
32033562 inline ImVec2 WindowPosAbsToRel(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x - off.x, p.y - off.y); }
@@ -3229,9 +3588,7 @@
32293588 IMGUI_API ImFont* GetDefaultFont();
32303589 IMGUI_API void PushPasswordFont();
32313590 IMGUI_API void PopPasswordFont();
3232- inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches.
3233- IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport); // get background draw list for the given viewport. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents.
3234- IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport); // get foreground draw list for the given viewport. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents.
3591+ inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { return GetForegroundDrawList(window->Viewport); }
32353592 IMGUI_API void AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector<ImDrawList*>* out_list, ImDrawList* draw_list);
32363593
32373594 // Init
@@ -3249,14 +3606,19 @@
32493606 IMGUI_API void UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos);
32503607 IMGUI_API void FindHoveredWindowEx(const ImVec2& pos, bool find_first_and_in_any_viewport, ImGuiWindow** out_hovered_window, ImGuiWindow** out_hovered_window_under_moving_window);
32513608 IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window);
3609+ IMGUI_API void StartMouseMovingWindowOrNode(ImGuiWindow* window, ImGuiDockNode* node, bool undock);
32523610 IMGUI_API void StopMouseMovingWindow();
32533611 IMGUI_API void UpdateMouseMovingWindowNewFrame();
32543612 IMGUI_API void UpdateMouseMovingWindowEndFrame();
32553613
32563614 // Viewports
3257- inline ImGuiViewport* GetWindowViewport() { return GetMainViewport(); } // For code consistency. This is public API in docking branch.
3615+ IMGUI_API void TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos, const ImVec2& old_size, const ImVec2& new_size);
32583616 IMGUI_API void ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale);
3617+ IMGUI_API void DestroyPlatformWindow(ImGuiViewportP* viewport);
32593618 IMGUI_API void SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport);
3619+ IMGUI_API void SetCurrentViewport(ImGuiWindow* window, ImGuiViewportP* viewport);
3620+ IMGUI_API const ImGuiPlatformMonitor* GetViewportPlatformMonitor(ImGuiViewport* viewport);
3621+ IMGUI_API ImGuiViewportP* FindHoveredViewportFromPlatformWindowStack(const ImVec2& mouse_platform_pos);
32603622
32613623 // Settings
32623624 IMGUI_API void MarkIniSettingsDirty();
@@ -3476,6 +3838,61 @@
34763838 IMGUI_API bool TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id);
34773839 IMGUI_API ImGuiKeyRoutingData* GetShortcutRoutingData(ImGuiKeyChord key_chord);
34783840
3841+ // Docking
3842+ // (some functions are only declared in imgui.cpp, see Docking section)
3843+ IMGUI_API void DockContextInitialize(ImGuiContext* ctx);
3844+ IMGUI_API void DockContextShutdown(ImGuiContext* ctx);
3845+ IMGUI_API void DockContextClearNodes(ImGuiContext* ctx, ImGuiID root_id, bool clear_settings_refs); // Use root_id==0 to clear all
3846+ IMGUI_API void DockContextRebuildNodes(ImGuiContext* ctx);
3847+ IMGUI_API void DockContextNewFrameUpdateUndocking(ImGuiContext* ctx);
3848+ IMGUI_API void DockContextNewFrameUpdateDocking(ImGuiContext* ctx);
3849+ IMGUI_API void DockContextEndFrame(ImGuiContext* ctx);
3850+ IMGUI_API ImGuiID DockContextGenNodeID(ImGuiContext* ctx);
3851+ IMGUI_API void DockContextQueueDock(ImGuiContext* ctx, ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, float split_ratio, bool split_outer);
3852+ IMGUI_API void DockContextQueueUndockWindow(ImGuiContext* ctx, ImGuiWindow* window);
3853+ IMGUI_API void DockContextQueueUndockNode(ImGuiContext* ctx, ImGuiDockNode* node);
3854+ IMGUI_API void DockContextProcessUndockWindow(ImGuiContext* ctx, ImGuiWindow* window, bool clear_persistent_docking_ref = true);
3855+ IMGUI_API void DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node);
3856+ IMGUI_API bool DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload_window, ImGuiDockNode* payload_node, ImGuiDir split_dir, bool split_outer, ImVec2* out_pos);
3857+ IMGUI_API ImGuiDockNode*DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id);
3858+ IMGUI_API void DockNodeWindowMenuHandler_Default(ImGuiContext* ctx, ImGuiDockNode* node, ImGuiTabBar* tab_bar);
3859+ IMGUI_API bool DockNodeBeginAmendTabBar(ImGuiDockNode* node);
3860+ IMGUI_API void DockNodeEndAmendTabBar();
3861+ inline ImGuiDockNode* DockNodeGetRootNode(ImGuiDockNode* node) { while (node->ParentNode) node = node->ParentNode; return node; }
3862+ inline bool DockNodeIsInHierarchyOf(ImGuiDockNode* node, ImGuiDockNode* parent) { while (node) { if (node == parent) return true; node = node->ParentNode; } return false; }
3863+ inline int DockNodeGetDepth(const ImGuiDockNode* node) { int depth = 0; while (node->ParentNode) { node = node->ParentNode; depth++; } return depth; }
3864+ inline ImGuiID DockNodeGetWindowMenuButtonId(const ImGuiDockNode* node) { return ImHashStr("#COLLAPSE", 0, node->ID); }
3865+ inline ImGuiDockNode* GetWindowDockNode() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DockNode; }
3866+ IMGUI_API bool GetWindowAlwaysWantOwnTabBar(ImGuiWindow* window);
3867+ IMGUI_API void BeginDocked(ImGuiWindow* window, bool* p_open);
3868+ IMGUI_API void BeginDockableDragDropSource(ImGuiWindow* window);
3869+ IMGUI_API void BeginDockableDragDropTarget(ImGuiWindow* window);
3870+ IMGUI_API void SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond);
3871+
3872+ // Docking - Builder function needs to be generally called before the node is used/submitted.
3873+ // - The DockBuilderXXX functions are designed to _eventually_ become a public API, but it is too early to expose it and guarantee stability.
3874+ // - Do not hold on ImGuiDockNode* pointers! They may be invalidated by any split/merge/remove operation and every frame.
3875+ // - To create a DockSpace() node, make sure to set the ImGuiDockNodeFlags_DockSpace flag when calling DockBuilderAddNode().
3876+ // You can create dockspace nodes (attached to a window) _or_ floating nodes (carry its own window) with this API.
3877+ // - DockBuilderSplitNode() create 2 child nodes within 1 node. The initial node becomes a parent node.
3878+ // - If you intend to split the node immediately after creation using DockBuilderSplitNode(), make sure
3879+ // to call DockBuilderSetNodeSize() beforehand. If you don't, the resulting split sizes may not be reliable.
3880+ // - Call DockBuilderFinish() after you are done.
3881+ IMGUI_API void DockBuilderDockWindow(const char* window_name, ImGuiID node_id);
3882+ IMGUI_API ImGuiDockNode*DockBuilderGetNode(ImGuiID node_id);
3883+ inline ImGuiDockNode* DockBuilderGetCentralNode(ImGuiID node_id) { ImGuiDockNode* node = DockBuilderGetNode(node_id); if (!node) return NULL; return DockNodeGetRootNode(node)->CentralNode; }
3884+ IMGUI_API ImGuiID DockBuilderAddNode(ImGuiID node_id = 0, ImGuiDockNodeFlags flags = 0);
3885+ IMGUI_API void DockBuilderRemoveNode(ImGuiID node_id); // Remove node and all its child, undock all windows
3886+ IMGUI_API void DockBuilderRemoveNodeDockedWindows(ImGuiID node_id, bool clear_settings_refs = true);
3887+ IMGUI_API void DockBuilderRemoveNodeChildNodes(ImGuiID node_id); // Remove all split/hierarchy. All remaining docked windows will be re-docked to the remaining root node (node_id).
3888+ IMGUI_API void DockBuilderSetNodePos(ImGuiID node_id, ImVec2 pos);
3889+ IMGUI_API void DockBuilderSetNodeSize(ImGuiID node_id, ImVec2 size);
3890+ IMGUI_API ImGuiID DockBuilderSplitNode(ImGuiID node_id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_at_dir, ImGuiID* out_id_at_opposite_dir); // Create 2 child nodes in this parent node.
3891+ IMGUI_API void DockBuilderCopyDockSpace(ImGuiID src_dockspace_id, ImGuiID dst_dockspace_id, ImVector<const char*>* in_window_remap_pairs);
3892+ IMGUI_API void DockBuilderCopyNode(ImGuiID src_node_id, ImGuiID dst_node_id, ImVector<ImGuiID>* out_node_remap_pairs);
3893+ IMGUI_API void DockBuilderCopyWindowSettings(const char* src_name, const char* dst_name);
3894+ IMGUI_API void DockBuilderFinish(ImGuiID node_id);
3895+
34793896 // [EXPERIMENTAL] Focus Scope
34803897 // This is generally used to identify a unique input location (for e.g. a selection set)
34813898 // There is one per window (automatically set in Begin), but:
@@ -3512,86 +3929,12 @@
35123929
35133930 // Multi-Select API
35143931 IMGUI_API void MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags* p_button_flags);
3515- IMGUI_API void MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed);
3932+ IMGUI_API void MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed, ImGuiMultiSelectFlags extra_flags = 0);
35163933 IMGUI_API void MultiSelectAddSetAll(ImGuiMultiSelectTempData* ms, bool selected);
35173934 IMGUI_API void MultiSelectAddSetRange(ImGuiMultiSelectTempData* ms, bool selected, int range_dir, ImGuiSelectionUserData first_item, ImGuiSelectionUserData last_item);
35183935 inline ImGuiBoxSelectState* GetBoxSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.BoxSelectState.ID == id && g.BoxSelectState.IsActive) ? &g.BoxSelectState : NULL; }
35193936 inline ImGuiMultiSelectState* GetMultiSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return g.MultiSelectStorage.GetByKey(id); }
35203937
3521- // Internal Columns API (this is not exposed because we will encourage transitioning to the Tables API)
3522- IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect);
3523- IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiOldColumnFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns().
3524- IMGUI_API void EndColumns(); // close columns
3525- IMGUI_API void PushColumnClipRect(int column_index);
3526- IMGUI_API void PushColumnsBackground();
3527- IMGUI_API void PopColumnsBackground();
3528- IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count);
3529- IMGUI_API ImGuiOldColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id);
3530- IMGUI_API float GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm);
3531- IMGUI_API float GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset);
3532-
3533- // Tables: Candidates for public API
3534- IMGUI_API void TableOpenContextMenu(int column_n = -1);
3535- IMGUI_API void TableSetColumnWidth(int column_n, float width);
3536- IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs);
3537- IMGUI_API int TableGetHoveredRow(); // Retrieve *PREVIOUS FRAME* hovered row. This difference with TableGetHoveredColumn() is the reason why this is not public yet.
3538- IMGUI_API float TableGetHeaderRowHeight();
3539- IMGUI_API float TableGetHeaderAngledMaxLabelWidth();
3540- IMGUI_API void TablePushBackgroundChannel();
3541- IMGUI_API void TablePopBackgroundChannel();
3542- IMGUI_API void TablePushColumnChannel(int column_n);
3543- IMGUI_API void TablePopColumnChannel();
3544- IMGUI_API void TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label_width, const ImGuiTableHeaderData* data, int data_count);
3545-
3546- // Tables: Internals
3547- inline ImGuiTable* GetCurrentTable() { ImGuiContext& g = *GImGui; return g.CurrentTable; }
3548- IMGUI_API ImGuiTable* TableFindByID(ImGuiID id);
3549- IMGUI_API bool BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f);
3550- IMGUI_API void TableBeginInitMemory(ImGuiTable* table, int columns_count);
3551- IMGUI_API void TableBeginApplyRequests(ImGuiTable* table);
3552- IMGUI_API void TableSetupDrawChannels(ImGuiTable* table);
3553- IMGUI_API void TableUpdateLayout(ImGuiTable* table);
3554- IMGUI_API void TableUpdateBorders(ImGuiTable* table);
3555- IMGUI_API void TableUpdateColumnsWeightFromWidth(ImGuiTable* table);
3556- IMGUI_API void TableApplyExternalUnclipRect(ImGuiTable* table, ImRect& rect);
3557- IMGUI_API void TableDrawBorders(ImGuiTable* table);
3558- IMGUI_API void TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags_for_section_to_display);
3559- IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table);
3560- IMGUI_API void TableMergeDrawChannels(ImGuiTable* table);
3561- inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; }
3562- inline ImGuiID TableGetInstanceID(ImGuiTable* table, int instance_no) { return TableGetInstanceData(table, instance_no)->TableInstanceID; }
3563- IMGUI_API void TableFixDisplayOrder(ImGuiTable* table);
3564- IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table);
3565- IMGUI_API void TableSortSpecsBuild(ImGuiTable* table);
3566- IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column);
3567- IMGUI_API void TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column);
3568- IMGUI_API float TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column);
3569- IMGUI_API void TableBeginRow(ImGuiTable* table);
3570- IMGUI_API void TableEndRow(ImGuiTable* table);
3571- IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n);
3572- IMGUI_API void TableEndCell(ImGuiTable* table);
3573- IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n);
3574- IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n);
3575- IMGUI_API ImGuiID TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no = 0);
3576- IMGUI_API float TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n);
3577- IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n);
3578- IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table);
3579- IMGUI_API void TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order);
3580- IMGUI_API void TableQueueSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order);
3581- IMGUI_API void TableRemove(ImGuiTable* table);
3582- IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table);
3583- IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table);
3584- IMGUI_API void TableGcCompactSettings();
3585-
3586- // Tables: Settings
3587- IMGUI_API void TableLoadSettings(ImGuiTable* table);
3588- IMGUI_API void TableSaveSettings(ImGuiTable* table);
3589- IMGUI_API void TableResetSettings(ImGuiTable* table);
3590- IMGUI_API ImGuiTableSettings* TableGetBoundSettings(ImGuiTable* table);
3591- IMGUI_API void TableSettingsAddSettingsHandler();
3592- IMGUI_API ImGuiTableSettings* TableSettingsCreate(ImGuiID id, int columns_count);
3593- IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id);
3594-
35953938 // Tab Bars
35963939 inline ImGuiTabBar* GetCurrentTabBar() { ImGuiContext& g = *GImGui; return g.CurrentTabBar; }
35973940 IMGUI_API ImGuiTabBar* TabBarFindByID(ImGuiID id);
@@ -3599,9 +3942,11 @@
35993942 IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags);
36003943 IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id);
36013944 IMGUI_API ImGuiTabItem* TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order);
3945+ IMGUI_API ImGuiTabItem* TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar);
36023946 IMGUI_API ImGuiTabItem* TabBarGetCurrentTab(ImGuiTabBar* tab_bar);
36033947 inline int TabBarGetTabOrder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) { return tab_bar->Tabs.index_from_ptr(tab); }
36043948 IMGUI_API const char* TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
3949+ IMGUI_API void TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window);
36053950 IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id);
36063951 IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
36073952 IMGUI_API void TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
@@ -3628,7 +3973,7 @@
36283973 IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f);
36293974 IMGUI_API void RenderColorComponentMarker(const ImRect& bb, ImU32 col, float rounding);
36303975 IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0);
3631- IMGUI_API void RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None); // Navigation highlight
3976+ IMGUI_API void RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None, float rounding = -1.0f); // Navigation highlight
36323977 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
36333978 inline void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None) { RenderNavCursor(bb, id, flags); } // Renamed in 1.91.4
36343979 #endif
@@ -3640,6 +3985,7 @@
36403985 IMGUI_API void RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col);
36413986 IMGUI_API void RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz);
36423987 IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col);
3988+ IMGUI_API void RenderArrowDockMenu(ImDrawList* draw_list, ImVec2 p_min, float sz, ImU32 col);
36433989 IMGUI_API void RenderRectFilledInRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float fill_x0, float fill_x1, float rounding);
36443990 IMGUI_API void RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding);
36453991 IMGUI_API ImDrawFlags CalcRoundingFlagsForRectInRect(const ImRect& r_in, const ImRect& r_outer, float threshold);
@@ -3660,7 +4006,7 @@
36604006
36614007 // Widgets: Window Decorations
36624008 IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos);
3663- IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos);
4009+ IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_node);
36644010 IMGUI_API void Scrollbar(ImGuiAxis axis);
36654011 IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 avail_v, ImS64 contents_v, ImDrawFlags draw_rounding_flags = 0);
36664012 IMGUI_API ImRect GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis);
@@ -3760,6 +4106,7 @@
37604106 IMGUI_API ImU64 DebugTextureIDToU64(ImTextureID tex_id);
37614107 IMGUI_API void DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end);
37624108 IMGUI_API void DebugNodeColumns(ImGuiOldColumns* columns);
4109+ IMGUI_API void DebugNodeDockNode(ImGuiDockNode* node, const char* label);
37634110 IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label);
37644111 IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb);
37654112 IMGUI_API void DebugNodeFont(ImFont* font);
@@ -3769,7 +4116,7 @@
37694116 IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label);
37704117 IMGUI_API void DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label);
37714118 IMGUI_API void DebugNodeTable(ImGuiTable* table);
3772- IMGUI_API void DebugNodeTableSettings(ImGuiTableSettings* settings);
4119+ IMGUI_API void DebugNodeTableSettings(ImGuiTableSettings* settings, ImGuiTable* table);
37734120 IMGUI_API void DebugNodeInputTextState(ImGuiInputTextState* state);
37744121 IMGUI_API void DebugNodeTypingSelectState(ImGuiTypingSelectState* state);
37754122 IMGUI_API void DebugNodeMultiSelectState(ImGuiMultiSelectState* state);
@@ -3778,6 +4125,7 @@
37784125 IMGUI_API void DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* label);
37794126 IMGUI_API void DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack);
37804127 IMGUI_API void DebugNodeViewport(ImGuiViewportP* viewport);
4128+ IMGUI_API void DebugNodePlatformMonitor(ImGuiPlatformMonitor* monitor, const char* label, int idx);
37814129 IMGUI_API void DebugRenderKeyboardPreview(ImDrawList* draw_list);
37824130 IMGUI_API void DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb);
37834131
@@ -3979,6 +4327,7 @@
39794327 IMGUI_API void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h);
39804328 IMGUI_API void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h);
39814329
4330+IMGUI_API bool ImTextureDataUpdateNewFrame(ImTextureData* tex);
39824331 IMGUI_API void ImTextureDataQueueUpload(ImTextureData* tex, int x, int y, int w, int h);
39834332 IMGUI_API int ImTextureDataGetFormatBytesPerPixel(ImTextureFormat format);
39844333 IMGUI_API const char* ImTextureDataGetStatusName(ImTextureStatus status);
@@ -1,4 +1,4 @@
1-// dear imgui, v1.92.8
1+// dear imgui, v1.92.9 WIP
22 // (tables and columns code)
33
44 /*
@@ -40,13 +40,15 @@
4040 // | TableBeginInitMemory() - first time table is used
4141 // | TableResetSettings() - on settings reset
4242 // | TableLoadSettings() - on settings load
43-// | TableBeginApplyRequests() - apply queued resizing/reordering/hiding requests
44-// | - TableSetColumnWidth() - apply resizing width (for mouse resize, often requested by previous frame)
45-// | - TableUpdateColumnsWeightFromWidth()- recompute columns weights (of stretch columns) from their respective width
43+//-----------------------------------------------------------------------------
4644 // - TableSetupColumn() user submit columns details (optional)
4745 // - TableSetupScrollFreeze() user submit scroll freeze information (optional)
4846 //-----------------------------------------------------------------------------
4947 // - TableUpdateLayout() [Internal] followup to BeginTable(): setup everything: widths, columns positions, clipping rectangles. Automatically called by the FIRST call to TableNextRow() or TableHeadersRow().
48+// | TableApplyQueuedRequests() - apply queued resizing/reordering/hiding requests
49+// | - TableSetColumnWidth() - apply resizing width (for mouse resize, often requested by previous frame)
50+// | - TableUpdateColumnsWeightFromWidth()- recompute columns weights (of stretch columns) from their respective width
51+// | - TableSetColumnDisplayOrder() - apply reordering a column
5052 // | TableSetupDrawChannels() - setup ImDrawList channels
5153 // | TableUpdateBorders() - detect hovering columns for resize, ahead of contents submission
5254 // | TableBeginContextMenuPopup()
@@ -252,7 +254,7 @@
252254 // - BeginTable()
253255 // - BeginTableEx() [Internal]
254256 // - TableBeginInitMemory() [Internal]
255-// - TableBeginApplyRequests() [Internal]
257+// - TableApplyQueuedRequests() [Internal]
256258 // - TableSetupColumnFlags() [Internal]
257259 // - TableUpdateLayout() [Internal]
258260 // - TableUpdateBorders() [Internal]
@@ -361,6 +363,7 @@
361363 g.TablesTempData.resize(g.TablesTempDataStacked, ImGuiTableTempData());
362364 ImGuiTableTempData* temp_data = table->TempData = &g.TablesTempData[g.TablesTempDataStacked - 1];
363365 temp_data->TableIndex = table_idx;
366+ temp_data->ReconcileColumnsRequests.resize(0); // FIXME: Use shrink(0) everywhere?
364367 table->DrawSplitter = &table->TempData->DrawSplitter;
365368 table->DrawSplitter->Clear();
366369
@@ -372,6 +375,7 @@
372375 const int previous_frame_active = table->LastFrameActive;
373376 const int instance_no = (previous_frame_active != g.FrameCount) ? 0 : table->InstanceCurrent + 1;
374377 const ImGuiTableFlags previous_flags = table->Flags;
378+ const bool is_new_table = (previous_frame_active == -1);
375379 table->ID = id;
376380 table->Flags = flags;
377381 table->LastFrameActive = g.FrameCount;
@@ -561,29 +565,36 @@
561565 table->MemoryCompacted = false;
562566
563567 // Setup memory buffer (clear data if columns count changed)
564- ImGuiTableColumn* old_columns_to_preserve = NULL;
565- void* old_columns_raw_data = NULL;
566568 const int old_columns_count = table->Columns.size();
567569 if (old_columns_count != 0 && old_columns_count != columns_count)
568570 {
569- // Attempt to preserve width and other settings on column count/specs change (#4046)
570- old_columns_to_preserve = table->Columns.Data;
571- old_columns_raw_data = table->RawData; // Free at end of function
571+ // Attempt to preserve width and other settings on column count/specs change (#4046, #9108)
572+ IMGUI_DEBUG_LOG_TABLE("[table] Table 0x%08X column count %d -> %d, recreating storage.\n", table->ID, old_columns_count, columns_count);
573+ IM_ASSERT(temp_data->OldColumnsRawData == NULL);
574+ temp_data->OldColumnsRawData = table->RawData; // Freed during layout
575+ temp_data->OldColumnsData = table->Columns;
576+ for (ImGuiTableColumn& src_column : table->TempData->OldColumnsData)
577+ src_column.IsNeedReconcileSrc = true;
572578 table->RawData = NULL;
573579 }
574580 if (table->RawData == NULL)
575581 {
576582 TableBeginInitMemory(table, columns_count);
577- table->IsInitializing = table->IsSettingsRequestLoad = true;
583+ table->IsInitializing = true;
578584 }
579585 if (table->IsResetAllRequest)
580586 TableResetSettings(table);
581587 if (table->IsInitializing)
582588 {
583589 // Initialize
584- table->SettingsOffset = -1;
590+ if (is_new_table)
591+ {
592+ table->SettingsOffset = -1;
593+ table->IsSettingsRequestLoad = true;
594+ }
585595 table->IsSortSpecsDirty = true;
586596 table->IsSettingsDirty = true; // Records itself into .ini file even when in default state (#7934)
597+ table->IsReconcileMode = false;
587598 table->InstanceInteracted = -1;
588599 table->ContextPopupColumn = -1;
589600 table->ReorderColumn = table->ReorderColumnDstOrder = table->ResizedColumn = table->LastResizedColumn = -1;
@@ -592,9 +603,9 @@
592603 for (int n = 0; n < columns_count; n++)
593604 {
594605 ImGuiTableColumn* column = &table->Columns[n];
595- if (old_columns_to_preserve && n < old_columns_count)
606+ if (temp_data->OldColumnsData.Data && n < temp_data->OldColumnsData.size())
596607 {
597- *column = old_columns_to_preserve[n];
608+ *column = temp_data->OldColumnsData[n];
598609 }
599610 else
600611 {
@@ -608,28 +619,11 @@
608619 table->DisplayOrderToIndex[n] = column->DisplayOrder;
609620 }
610621 }
611- if (old_columns_raw_data)
612- IM_FREE(old_columns_raw_data);
613622
614623 // Load settings
615624 if (table->IsSettingsRequestLoad)
616625 TableLoadSettings(table);
617626
618- // Handle DPI/font resize
619- // This is designed to facilitate DPI changes with the assumption that e.g. style.CellPadding has been scaled as well.
620- // It will also react to changing fonts with mixed results. It doesn't need to be perfect but merely provide a decent transition.
621- // FIXME-DPI: Provide consistent standards for reference size. Perhaps using g.CurrentDpiScale would be more self explanatory.
622- // This is will lead us to non-rounded WidthRequest in columns, which should work but is a poorly tested path.
623- const float new_ref_scale_unit = g.FontSize; // g.Font->GetCharAdvance('A') ?
624- if (table->RefScale != 0.0f && table->RefScale != new_ref_scale_unit)
625- {
626- const float scale_factor = new_ref_scale_unit / table->RefScale;
627- //IMGUI_DEBUG_PRINT("[table] %08X RefScaleUnit %.3f -> %.3f, scaling width by %.3f\n", table->ID, table->RefScaleUnit, new_ref_scale_unit, scale_factor);
628- for (int n = 0; n < columns_count; n++)
629- table->Columns[n].WidthRequest = table->Columns[n].WidthRequest * scale_factor;
630- }
631- table->RefScale = new_ref_scale_unit;
632-
633627 // Disable output until user calls TableNextRow() or TableNextColumn() leading to the TableUpdateLayout() call..
634628 // This is not strictly necessary but will reduce cases were "out of table" output will be misleading to the user.
635629 // Because we cannot safely assert in EndTable() when no rows have been created, this seems like our best option.
@@ -639,10 +633,7 @@
639633 // At this point the ->NameOffset field of each column will be invalid until TableUpdateLayout() or the first call to TableSetupColumn()
640634 if (table->ColumnsNames.Buf.Size > 0)
641635 table->ColumnsNames.Buf.resize(0);
642-
643- // Apply queued resizing/reordering/hiding requests
644- TableBeginApplyRequests(table);
645-
636+
646637 return true;
647638 }
648639
@@ -677,7 +668,7 @@
677668 }
678669
679670 // Apply queued resizing/reordering/hiding requests
680-void ImGui::TableBeginApplyRequests(ImGuiTable* table)
671+void ImGui::TableApplyQueuedRequests(ImGuiTable* table)
681672 {
682673 // Handle resizing request
683674 // (We process this in the TableBegin() of the first instance of each table)
@@ -719,7 +710,7 @@
719710 // table->ReorderColumn = -1;
720711 }
721712
722- // Handle display order reset request
713+ // Handle display order / visibility reset requests
723714 if (table->IsResetDisplayOrderRequest)
724715 {
725716 for (int n = 0; n < table->ColumnsCount; n++)
@@ -727,6 +718,13 @@
727718 table->IsResetDisplayOrderRequest = false;
728719 table->IsSettingsDirty = true;
729720 }
721+ if (table->IsResetVisibilityRequest)
722+ {
723+ for (ImGuiTableColumn& column : table->Columns)
724+ column.IsUserEnabled = column.IsUserEnabledNextFrame = (column.Flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1;
725+ table->IsResetVisibilityRequest = false;
726+ table->IsSettingsDirty = true;
727+ }
730728 }
731729
732730 // Apply immediately. See TableQueueSetColumnDisplayOrder() for additional checks/constraints.
@@ -782,8 +780,9 @@
782780 table->ReorderColumn = (ImGuiTableColumnIdx)column_n;
783781 table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)-1;
784782 dst_order = TableGetMaxDisplayOrderAllowed(table, src_order, dst_order);
785- if (dst_order != src_order)
786- table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)dst_order;
783+ if (table->IsLayoutLocked && dst_order == src_order) // We allow calling the function before layout w/ reconcile so don't early out.
784+ return;
785+ table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)dst_order;
787786 }
788787
789788 // Adjust flags: default width mode + stretch columns are not allowed when auto extending
@@ -849,13 +848,61 @@
849848 void ImGui::TableUpdateLayout(ImGuiTable* table)
850849 {
851850 ImGuiContext& g = *GImGui;
851+ ImGuiTableTempData* temp_data = table->TempData;
852852 IM_ASSERT(table->IsLayoutLocked == false);
853+ const int columns_count = table->ColumnsCount;
853854
855+ // Reconcile moved columns
856+ if (temp_data->ReconcileColumnsRequests.Size > 0)
857+ TableReconcileColumns(table);
858+ if (temp_data->OldColumnsRawData)
859+ {
860+ IM_FREE(temp_data->OldColumnsRawData);
861+ temp_data->OldColumnsRawData = NULL;
862+ temp_data->OldColumnsData.clear();
863+ }
864+
865+ // Apply columns settings
866+ if (table->IsSettingsRequestLoad)
867+ TableLoadSettingsForColumns(table);
868+ if (table->IsInitializing || table->IsSettingsRequestLoad)
869+ {
870+ for (ImGuiTableColumn& column : table->Columns)
871+ {
872+ ImGuiTableFlags init_flags;
873+ if (table->IsSettingsRequestLoad)
874+ init_flags = column.IsLoadedSettings ? ~table->SettingsLoadedFlags : ~0;
875+ else
876+ init_flags = column.IsJustCreated ? ~0 : 0;
877+ TableInitColumnDefaults(table, &column, init_flags);
878+ }
879+ TableFixDisplayOrder(table); // Call even for non _Reorderable table as we loaded .ini data.
880+ table->IsSettingsRequestLoad = false;
881+ }
882+
883+ // Apply queued resizing/reordering/hiding requests
884+ TableApplyQueuedRequests(table);
885+
886+ // Handle DPI/font resize
887+ // This is designed to facilitate DPI changes with the assumption that e.g. style.CellPadding has been scaled as well.
888+ // It will also react to changing fonts with mixed results. It doesn't need to be perfect but merely provide a decent transition.
889+ // FIXME-DPI: Provide consistent standards for reference size. Perhaps using g.CurrentDpiScale would be more self explanatory.
890+ // This is will lead us to non-rounded WidthRequest in columns, which should work but is a poorly tested path.
891+ const float new_ref_scale_unit = g.FontSize; // g.Font->GetCharAdvance('A') ?
892+ if (table->RefScale != 0.0f && table->RefScale != new_ref_scale_unit)
893+ {
894+ const float scale_factor = new_ref_scale_unit / table->RefScale;
895+ IMGUI_DEBUG_LOG_TABLE("[table] 0x%08X RefScale %.3f -> %.3f, scaling width by %.3f\n", table->ID, table->RefScale, new_ref_scale_unit, scale_factor);
896+ for (int n = 0; n < columns_count; n++)
897+ table->Columns[n].WidthRequest = table->Columns[n].WidthRequest * scale_factor;
898+ }
899+ table->RefScale = new_ref_scale_unit;
900+
854901 const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_);
855- table->IsDefaultDisplayOrder = true;
902+ table->IsDefaultDisplayOrder = table->IsDefaultVisibility = true;
856903 table->ColumnsEnabledCount = 0;
857- ImBitArrayClearAllBits(table->EnabledMaskByIndex, table->ColumnsCount);
858- ImBitArrayClearAllBits(table->EnabledMaskByDisplayOrder, table->ColumnsCount);
904+ ImBitArrayClearAllBits(table->EnabledMaskByIndex, columns_count);
905+ ImBitArrayClearAllBits(table->EnabledMaskByDisplayOrder, columns_count);
859906 table->LeftMostEnabledColumn = -1;
860907 table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE
861908
@@ -868,11 +915,9 @@
868915 bool has_resizable = false;
869916 float stretch_sum_width_auto = 0.0f;
870917 float fixed_max_width_auto = 0.0f;
871- for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
918+ for (int order_n = 0; order_n < columns_count; order_n++)
872919 {
873920 const int column_n = table->DisplayOrderToIndex[order_n];
874- if (column_n != order_n)
875- table->IsDefaultDisplayOrder = false;
876921 ImGuiTableColumn* column = &table->Columns[column_n];
877922
878923 // Clear column setup if not submitted by user. Currently we make it mandatory to call TableSetupColumn() every frame.
@@ -882,7 +927,7 @@
882927 {
883928 TableSetupColumnFlags(table, column, ImGuiTableColumnFlags_None);
884929 column->NameOffset = -1;
885- column->UserID = 0;
930+ column->ID = column->UserData = 0;
886931 column->InitStretchWeightOrWidth = -1.0f;
887932 }
888933
@@ -895,7 +940,13 @@
895940 table->IsSettingsDirty = true;
896941 }
897942 column->IsEnabled = column->IsUserEnabled && (column->Flags & ImGuiTableColumnFlags_Disabled) == 0;
943+ column->IsJustCreated = false;
898944
945+ if (column->IsEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1))
946+ table->IsDefaultVisibility = false;
947+ if (column_n != order_n)
948+ table->IsDefaultDisplayOrder = false;
949+
899950 if (column->SortOrder != -1 && !column->IsEnabled)
900951 table->IsSortSpecsDirty = true;
901952 if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti))
@@ -967,7 +1018,7 @@
9671018 float sum_width_requests = 0.0f; // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns but including spacing/padding.
9681019 float stretch_sum_weights = 0.0f; // Sum of all weights for stretch columns.
9691020 table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1;
970- for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
1021+ for (int column_n = 0; column_n < columns_count; column_n++)
9711022 {
9721023 if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n))
9731024 continue;
@@ -1031,7 +1082,7 @@
10311082 const float width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests;
10321083 float width_remaining_for_stretched_columns = width_avail_for_stretched_columns;
10331084 table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount;
1034- for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
1085+ for (int column_n = 0; column_n < columns_count; column_n++)
10351086 {
10361087 if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n))
10371088 continue;
@@ -1058,7 +1109,7 @@
10581109 // [Part 5] Redistribute stretch remainder width due to rounding (remainder width is < 1.0f * number of Stretch column).
10591110 // Using right-to-left distribution (more likely to match resizing cursor).
10601111 if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths))
1061- for (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--)
1112+ for (int order_n = columns_count - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--)
10621113 {
10631114 if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))
10641115 continue;
@@ -1098,8 +1149,8 @@
10981149 float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1;
10991150 ImRect host_clip_rect = table->InnerClipRect;
11001151 //host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2;
1101- ImBitArrayClearAllBits(table->VisibleMaskByIndex, table->ColumnsCount);
1102- for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
1152+ ImBitArrayClearAllBits(table->VisibleMaskByIndex, columns_count);
1153+ for (int order_n = 0; order_n < columns_count; order_n++)
11031154 {
11041155 const int column_n = table->DisplayOrderToIndex[order_n];
11051156 ImGuiTableColumn* column = &table->Columns[column_n];
@@ -1247,7 +1298,7 @@
12471298 const float unused_x1 = ImMax(table->WorkRect.Min.x, table->Columns[table->RightMostEnabledColumn].ClipRect.Max.x);
12481299 if (is_hovering_table && table->HoveredColumnBody == -1)
12491300 if (mouse_skewed_x >= unused_x1)
1250- table->HoveredColumnBody = (ImGuiTableColumnIdx)table->ColumnsCount;
1301+ table->HoveredColumnBody = (ImGuiTableColumnIdx)columns_count;
12511302 if (has_resizable == false && (table->Flags & ImGuiTableFlags_Resizable))
12521303 table->Flags &= ~ImGuiTableFlags_Resizable;
12531304
@@ -1289,7 +1340,7 @@
12891340 table->HighlightColumnHeader = -1;
12901341 if (table->IsContextPopupOpen && table->ContextPopupColumn != -1 && table->InstanceInteracted == table->InstanceCurrent)
12911342 table->HighlightColumnHeader = table->ContextPopupColumn;
1292- else if ((table->Flags & ImGuiTableFlags_HighlightHoveredColumn) && table->HoveredColumnBody != -1 && table->HoveredColumnBody != table->ColumnsCount && table->HoveredColumnBorder == -1)
1343+ else if ((table->Flags & ImGuiTableFlags_HighlightHoveredColumn) && table->HoveredColumnBody != -1 && table->HoveredColumnBody != columns_count && table->HoveredColumnBorder == -1)
12931344 if (g.ActiveId == 0 || (table->IsActiveIdInTable || g.DragDropActive))
12941345 table->HighlightColumnHeader = table->HoveredColumnBody;
12951346
@@ -1629,9 +1680,9 @@
16291680 NavUpdateCurrentWindowIsScrollPushableX();
16301681 }
16311682
1632-// Called in TableSetupColumn() when initializing and in TableLoadSettings() for defaults before applying stored settings.
1683+// Called in TableUpdateLayout() when initializing/after loading settings.
16331684 // 'init_mask' specify which fields to initialize.
1634-static void TableInitColumnDefaults(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags init_mask)
1685+void ImGui::TableInitColumnDefaults(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags init_mask)
16351686 {
16361687 ImGuiTableColumnFlags flags = column->Flags;
16371688 if (init_mask & ImGuiTableFlags_Resizable)
@@ -1643,7 +1694,7 @@
16431694 column->AutoFitQueue = 0x00;
16441695 }
16451696 if (init_mask & ImGuiTableFlags_Reorderable)
1646- column->DisplayOrder = (ImGuiTableColumnIdx)table->Columns.index_from_ptr(column);
1697+ column->DisplayOrder = (ImGuiTableColumnIdx)((table->Flags & ImGuiTableFlags_Reorderable) ? -1 : table->Columns.index_from_ptr(column));
16471698 if (init_mask & ImGuiTableFlags_Hideable)
16481699 column->IsUserEnabled = column->IsUserEnabledNextFrame = (flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1;
16491700 if (init_mask & ImGuiTableFlags_Sortable)
@@ -1656,18 +1707,10 @@
16561707
16571708 // See "COLUMNS SIZING POLICIES" comments at the top of this file
16581709 // If (init_width_or_weight <= 0.0f) it is ignored
1659-void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id)
1710+static void TableSetupColumnApply(ImGuiTable* table, int idx, ImGuiID id, ImS16 name_offset, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_data)
16601711 {
1661- ImGuiContext& g = *GImGui;
1662- ImGuiTable* table = g.CurrentTable;
1663- IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!");
1664- IM_ASSERT_USER_ERROR_RET(table->DeclColumnsCount < table->ColumnsCount, "TableSetupColumn(): called too many times!");
1665- IM_ASSERT_USER_ERROR_RET(table->IsLayoutLocked == false, "TableSetupColumn(): need to call before first row!"); // Table layout is locked when submitting a row or when calling BeginMultiSelect() with box-select.
1666- IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()");
1712+ ImGuiTableColumn* column = &table->Columns[idx];
16671713
1668- ImGuiTableColumn* column = &table->Columns[table->DeclColumnsCount];
1669- table->DeclColumnsCount++;
1670-
16711714 // Assert when passing a width or weight if policy is entirely left to default, to avoid storing width into weight and vice-versa.
16721715 // Give a grace to users of ImGuiTableFlags_ScrollX.
16731716 if (table->IsDefaultSizingPolicy && (flags & ImGuiTableColumnFlags_WidthMask_) == 0 && (flags & ImGuiTableFlags_ScrollX) == 0)
@@ -1685,29 +1728,129 @@
16851728 }
16861729
16871730 TableSetupColumnFlags(table, column, flags);
1688- column->UserID = user_id;
1689- flags = column->Flags;
1690-
1691- // Initialize defaults
1731+ column->ID = id;
1732+ column->UserData = user_data;
1733+ column->NameOffset = name_offset;
16921734 column->InitStretchWeightOrWidth = init_width_or_weight;
1693- if (table->IsInitializing)
1694- {
1695- ImGuiTableFlags init_flags = ~table->SettingsLoadedFlags;
1696- if (column->WidthRequest < 0.0f && column->StretchWeight < 0.0f)
1697- init_flags |= ImGuiTableFlags_Resizable;
1698- TableInitColumnDefaults(table, column, init_flags);
1699- }
1735+}
17001736
1737+void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_data)
1738+{
1739+ ImGuiContext& g = *GImGui;
1740+ ImGuiTable* table = g.CurrentTable;
1741+ IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!");
1742+ IM_ASSERT_USER_ERROR_RET(table->DeclColumnsCount < table->ColumnsCount, "TableSetupColumn(): called too many times!");
1743+ IM_ASSERT_USER_ERROR_RET(table->IsLayoutLocked == false, "TableSetupColumn(): need to call before first row!"); // Table layout is locked when submitting a row or when calling BeginMultiSelect() with box-select.
1744+ IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()");
1745+
17011746 // Store name (append with zero-terminator in contiguous buffer)
17021747 // FIXME: If we recorded the number of \n in names we could compute header row height
1703- column->NameOffset = -1;
1748+ ImS16 name_offset = -1;
17041749 if (label != NULL && label[0] != 0)
17051750 {
1706- column->NameOffset = (ImS16)table->ColumnsNames.size();
1751+ name_offset = (ImS16)table->ColumnsNames.size();
17071752 table->ColumnsNames.append(label, label + ImStrlen(label) + 1);
17081753 }
1754+ const ImGuiID column_id = (label != NULL && label[0] != 0) ? ImHashStr(label) : 0;
1755+
1756+ // When ID changed or a column moved: defer the request until layout where we will process full reconcile.
1757+ const int column_idx = table->DeclColumnsCount++;
1758+ ImGuiTableColumn* column = &table->Columns[column_idx];
1759+
1760+ // If topology change goes into reconcile mode
1761+ if (table->IsReconcileMode == false && column->ID != column_id)
1762+ {
1763+ table->IsReconcileMode = true;
1764+ table->TempData->ReconcileColumnsRequests.reserve(table->ColumnsCount - column_idx);
1765+ }
1766+
1767+ // Fast/common path
1768+ if (table->IsReconcileMode == false)
1769+ {
1770+ TableSetupColumnApply(table, column_idx, column_id, name_offset, flags, init_width_or_weight, user_data);
1771+ column->IsNeedReconcileSrc = column->IsNeedReconcileDst = false;
1772+ if (column_idx < table->TempData->OldColumnsData.size())
1773+ table->TempData->OldColumnsData[column_idx].IsNeedReconcileSrc = false;
1774+ return;
1775+ }
1776+
1777+ // Reconcile path: defer applying data to TableUpdateLayout() -> TableReconcileMovedColumns() -> TableSetupColumnApply().
1778+ // On column count change: search the previous columns:
1779+ // - the live Columns[] array is truncated on shrink, so a moved column may only exist in old data.
1780+ // - the live Columns[] array may already be partially reset.
1781+ table->TempData->ReconcileColumnsRequests.push_back(ImGuiTableReconcileColumnData());
1782+ ImGuiTableReconcileColumnData& reconcile_data = table->TempData->ReconcileColumnsRequests.back();
1783+ reconcile_data.ID = column_id;
1784+ reconcile_data.NameOffset = name_offset;
1785+ reconcile_data.Flags = flags;
1786+ reconcile_data.InitWidthOrWeight = init_width_or_weight;
1787+ reconcile_data.UserData = user_data;
1788+ reconcile_data.ColumnNewIdx = (ImGuiTableColumnIdx)column_idx;
1789+ reconcile_data.ColumnOldIdx = (ImGuiTableColumnIdx)-1;
1790+ column->NameOffset = name_offset; // Allow TableGetColumnName() to work before layout
1791+ column->IsNeedReconcileSrc = column->IsNeedReconcileDst = true;
17091792 }
17101793
1794+// NB: This was written to be similar to the logic in TableLoadSettingsForColumns().
1795+void ImGui::TableReconcileColumns(ImGuiTable* table)
1796+{
1797+ ImGuiContext& g = *GImGui;
1798+ ImGuiTableTempData* temp_data = table->TempData;
1799+ IM_UNUSED(g);
1800+ IMGUI_DEBUG_LOG_TABLE("[table] Reconcile columns for table 0x%08X\n", table->ID);
1801+
1802+ ImSpan<ImGuiTableColumn>& dst_columns = table->Columns;
1803+ ImSpan<ImGuiTableColumn>& src_columns = table->TempData->OldColumnsData.empty() ? table->Columns : table->TempData->OldColumnsData;
1804+
1805+ // Find matches for named columns.
1806+ int matches = 0;
1807+ ImVector<ImGuiTableReconcileColumnData>& reconcile_requests = temp_data->ReconcileColumnsRequests;
1808+ for (ImGuiTableReconcileColumnData& reconcile_data : reconcile_requests)
1809+ if (reconcile_data.ID != 0)
1810+ for (ImGuiTableColumn& src_column : src_columns)
1811+ if (src_column.ID == reconcile_data.ID && src_column.IsNeedReconcileSrc)
1812+ {
1813+ ImGuiTableColumn& dst_column = dst_columns[reconcile_data.ColumnNewIdx];
1814+ IM_ASSERT(src_column.IsNeedReconcileSrc && dst_column.IsNeedReconcileDst);
1815+ src_column.IsNeedReconcileSrc = dst_column.IsNeedReconcileDst = false;
1816+ reconcile_data.ColumnOldIdx = (ImGuiTableColumnIdx)src_columns.index_from_ptr(&src_column);
1817+ reconcile_data.ColumnOldData = src_column;
1818+ matches++;
1819+ break;
1820+ }
1821+
1822+ // Remaining entries are matched sequentially.
1823+ int dst_idx = 0; // index in reconcile array
1824+ if (matches != reconcile_requests.Size)
1825+ for (ImGuiTableColumn& src_column : src_columns)
1826+ {
1827+ if (!src_column.IsNeedReconcileSrc)
1828+ continue;
1829+ while (dst_idx < reconcile_requests.Size && reconcile_requests[dst_idx].ColumnOldIdx != (ImGuiTableColumnIdx)-1)
1830+ dst_idx++;
1831+ if (dst_idx == reconcile_requests.Size)
1832+ break;
1833+ ImGuiTableReconcileColumnData& reconcile_data = reconcile_requests[dst_idx];
1834+ ImGuiTableColumn& dst_column = dst_columns[reconcile_data.ColumnNewIdx];
1835+ IM_ASSERT(src_column.IsNeedReconcileSrc && dst_column.IsNeedReconcileDst);
1836+ src_column.IsNeedReconcileSrc = dst_column.IsNeedReconcileDst = false;
1837+ reconcile_data.ColumnOldIdx = (ImGuiTableColumnIdx)src_columns.index_from_ptr(&src_column);
1838+ reconcile_data.ColumnOldData = src_column;
1839+ }
1840+
1841+ // Apply in the final pass. Because it is possible that src_columns == table->Columns we went through a temporary copy.
1842+ for (ImGuiTableReconcileColumnData& reconcile_data : reconcile_requests)
1843+ {
1844+ table->Columns[reconcile_data.ColumnNewIdx] = reconcile_data.ColumnOldData; // When old column was not found clear anyway with default-constructed data (which will set IsJustCreated=true)
1845+ TableSetupColumnApply(table, reconcile_data.ColumnNewIdx, reconcile_data.ID, reconcile_data.NameOffset, reconcile_data.Flags, reconcile_data.InitWidthOrWeight, reconcile_data.UserData);
1846+ IMGUI_DEBUG_LOG_TABLE("[table] - old %d -> new %d \"%s\"\n", reconcile_data.ColumnOldIdx, reconcile_data.ColumnNewIdx, TableGetColumnName(table, reconcile_data.ColumnNewIdx)); // Log at the end so NameOffset was copied.
1847+ }
1848+ TableFixDisplayOrder(table);
1849+ table->IsSettingsDirty = true; // FIXME-RECONCILE: Necessary?
1850+ table->IsReconcileMode = false;
1851+ reconcile_requests.resize(0); // GC-ed once in NewFrame()
1852+}
1853+
17111854 // [Public]
17121855 void ImGui::TableSetupScrollFreeze(int columns, int rows)
17131856 {
@@ -3081,7 +3224,7 @@
30813224 continue;
30823225 IM_ASSERT(column->SortOrder < table->SortSpecsCount);
30833226 ImGuiTableColumnSortSpecs* sort_spec = &sort_specs[column->SortOrder];
3084- sort_spec->ColumnUserID = column->UserID;
3227+ sort_spec->ColumnUserID = column->UserData;
30853228 sort_spec->ColumnIndex = (ImGuiTableColumnIdx)column_n;
30863229 sort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder;
30873230 sort_spec->SortDirection = (ImGuiSortDirection)column->SortDirection;
@@ -3252,7 +3395,7 @@
32523395 if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0)
32533396 TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn);
32543397 }
3255- RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding);
3398+ RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact, 0.0f);
32563399 if (held)
32573400 table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n;
32583401 window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f;
@@ -3277,7 +3420,9 @@
32773420 }
32783421
32793422 // Sort order arrow
3280- const float ellipsis_max = ImMax(cell_r.Max.x - w_arrow - w_sort_text, label_pos.x);
3423+ // - Only clip label for a visible arrow. Auto-fit still accounts for a possible arrow, but when
3424+ // manually sized smaller we don't clip the label for the sake of an arrow that isn't displayed.
3425+ const float ellipsis_max = ImMax(cell_r.Max.x - (sort_arrow ? w_arrow + w_sort_text : 0.0f), label_pos.x);
32813426 if ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort))
32823427 {
32833428 if (column->SortOrder != -1)
@@ -3597,18 +3742,21 @@
35973742 want_separator = true;
35983743 }
35993744
3600- // Ordering
3601- if (flags_for_section_to_display & ImGuiTableFlags_Reorderable)
3602- {
3603- if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetOrder), NULL, false, !table->IsDefaultDisplayOrder))
3604- table->IsResetDisplayOrderRequest = true;
3605- want_separator = true;
3606- }
3745+ // Reset Order/Visibility etc.
3746+ if (flags_for_section_to_display & (ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
3747+ if (BeginMenu(LocalizeGetMsg(ImGuiLocKey_TableReset)))
3748+ {
3749+ //if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetAll))) // FIXME: Hiding because altering Sort Order + requesting auto-fit simultaneously has a tendency to exhibit a sizing glitch.
3750+ // table->IsResetAllRequest = true;
3751+ if (flags_for_section_to_display & ImGuiTableFlags_Reorderable)
3752+ if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetOrder), NULL, false, !table->IsDefaultDisplayOrder)) // PS: cannot be hidden because it would mess with drag reordering.
3753+ table->IsResetDisplayOrderRequest = true;
3754+ if (flags_for_section_to_display & ImGuiTableFlags_Hideable)
3755+ if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetVisibility), NULL, false, !table->IsDefaultVisibility))
3756+ table->IsResetVisibilityRequest = true;
3757+ EndMenu();
3758+ }
36073759
3608- // Reset all (should work but seems unnecessary/noisy to expose?)
3609- //if (MenuItem("Reset all"))
3610- // table->IsResetAllRequest = true;
3611-
36123760 // Sorting
36133761 // (modify TableOpenContextMenu() to add _Sortable flag if enabling this)
36143762 #if 0
@@ -3692,6 +3840,7 @@
36923840 // - TableResetSettings()
36933841 // - TableSaveSettings() [Internal]
36943842 // - TableLoadSettings() [Internal]
3843+// - TableLoadSettingsForColumns() [Internal]
36953844 // - TableSettingsHandler_ClearAll() [Internal]
36963845 // - TableSettingsHandler_ApplyAll() [Internal]
36973846 // - TableSettingsHandler_ReadOpen() [Internal]
@@ -3726,6 +3875,8 @@
37263875 ImGuiTableSettings* ImGui::TableSettingsCreate(ImGuiID id, int columns_count)
37273876 {
37283877 ImGuiContext& g = *GImGui;
3878+ //ImGuiTableSettings* old_settings = TableSettingsFindByID(id); // Comment out sanity check to avoid unnecessary lookups.
3879+ //IM_ASSERT(old_settings == NULL || old_settings->ColumnsCountMax < columns_count);
37293880 ImGuiTableSettings* settings = g.SettingsTables.alloc_chunk(TableSettingsCalcChunkSize(columns_count));
37303881 TableSettingsInit(settings, id, columns_count, columns_count);
37313882 return settings;
@@ -3745,16 +3896,12 @@
37453896 // Get settings for a given table, NULL if none
37463897 ImGuiTableSettings* ImGui::TableGetBoundSettings(ImGuiTable* table)
37473898 {
3748- if (table->SettingsOffset != -1)
3749- {
3750- ImGuiContext& g = *GImGui;
3751- ImGuiTableSettings* settings = g.SettingsTables.ptr_from_offset(table->SettingsOffset);
3752- IM_ASSERT(settings->ID == table->ID);
3753- if (settings->ColumnsCountMax >= table->ColumnsCount)
3754- return settings; // OK
3755- settings->ID = 0; // Invalidate storage, we won't fit because of a count change
3756- }
3757- return NULL;
3899+ if (table->SettingsOffset == -1)
3900+ return NULL;
3901+ ImGuiContext& g = *GImGui;
3902+ ImGuiTableSettings* settings = g.SettingsTables.ptr_from_offset(table->SettingsOffset);
3903+ IM_ASSERT(settings->ID == table->ID);
3904+ return settings;
37583905 }
37593906
37603907 // Restore initial state of table (with or without saved settings)
@@ -3775,6 +3922,11 @@
37753922 // Bind or create settings data
37763923 ImGuiContext& g = *GImGui;
37773924 ImGuiTableSettings* settings = TableGetBoundSettings(table);
3925+ if (settings != NULL && table->ColumnsCount > settings->ColumnsCountMax)
3926+ {
3927+ settings->ID = 0; // Invalidate storage, we won't fit because of a count change
3928+ settings = NULL;
3929+ }
37783930 if (settings == NULL)
37793931 {
37803932 settings = TableSettingsCreate(table->ID, table->ColumnsCount);
@@ -3793,6 +3945,7 @@
37933945 for (int n = 0; n < table->ColumnsCount; n++, column++, column_settings++)
37943946 {
37953947 const float width_or_weight = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? column->StretchWeight : column->WidthRequest;
3948+ column_settings->ID = column->ID;
37963949 column_settings->WidthOrWeight = width_or_weight;
37973950 column_settings->Index = (ImGuiTableColumnIdx)n;
37983951 column_settings->DisplayOrder = column->DisplayOrder;
@@ -3824,9 +3977,11 @@
38243977 void ImGui::TableLoadSettings(ImGuiTable* table)
38253978 {
38263979 ImGuiContext& g = *GImGui;
3827- table->IsSettingsRequestLoad = false;
38283980 if (table->Flags & ImGuiTableFlags_NoSavedSettings)
3981+ {
3982+ table->IsSettingsRequestLoad = false; // Done
38293983 return;
3984+ }
38303985
38313986 // Bind settings
38323987 ImGuiTableSettings* settings;
@@ -3846,44 +4001,83 @@
38464001
38474002 table->SettingsLoadedFlags = settings->SaveFlags;
38484003 table->RefScale = settings->RefScale;
4004+ // TableUpdateLayout() will then call TableLoadSettingsForColumns() to apply the data.
4005+}
38494006
3850- // Initialize default columns settings
3851- for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
3852- {
3853- ImGuiTableColumn* column = &table->Columns[column_n];
3854- TableInitColumnDefaults(table, column, ~0);
3855- column->AutoFitQueue = 0x00;
3856- }
4007+// NB: This was written to be similar to the logic in TableReconcileColumns().
4008+void ImGui::TableLoadSettingsForColumns(ImGuiTable* table)
4009+{
4010+ for (ImGuiTableColumn& column : table->Columns)
4011+ column.IsLoadedSettings = false;
4012+ ImGuiTableSettings* settings = TableGetBoundSettings(table);
4013+ if (settings == NULL)
4014+ return;
38574015
4016+ table->SettingsLoadedFlags |= ImGuiTableFlags_Reorderable; // We handle above in code above.
4017+
38584018 // Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn
38594019 ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings();
3860- for (int data_n = 0; data_n < settings->ColumnsCount; data_n++, column_settings++)
4020+
4021+ // Fast path
4022+ int matches = 0;
4023+ for (int n = 0; n < table->ColumnsCount; n++)
38614024 {
3862- int column_n = column_settings->Index;
3863- if (column_n < 0 || column_n >= table->ColumnsCount)
3864- continue;
4025+ if (n >= settings->ColumnsCount || column_settings[n].ID != table->Columns[n].ID)
4026+ break;
4027+ TableLoadSettingsForColumn(&table->Columns[n], &column_settings[n], settings->SaveFlags);
4028+ matches++;
4029+ }
4030+ if (matches == settings->ColumnsCount)
4031+ return;
4032+ const int settings_start_n = matches; // Small optimization
4033+ for (int n = settings_start_n; n < settings->ColumnsCount; n++)
4034+ column_settings[n].IsLoaded = false;
38654035
3866- ImGuiTableColumn* column = &table->Columns[column_n];
3867- if (settings->SaveFlags & ImGuiTableFlags_Resizable)
4036+ // Find matches for named columns
4037+ for (ImGuiTableColumn& column : table->Columns)
4038+ if (column.ID != 0 && !column.IsLoadedSettings)
4039+ for (int n = settings_start_n; n < settings->ColumnsCount; n++)
4040+ if (column_settings[n].ID == column.ID && !column_settings[n].IsLoaded)
4041+ {
4042+ TableLoadSettingsForColumn(&column, &column_settings[n], settings->SaveFlags);
4043+ matches++;
4044+ break;
4045+ }
4046+
4047+ // Remaining entries are matched sequentially
4048+ int dst_idx = 0;
4049+ for (int n = settings_start_n; n < settings->ColumnsCount; n++)
4050+ if (!column_settings[n].IsLoaded)
38684051 {
3869- if (column_settings->IsStretch)
3870- column->StretchWeight = column_settings->WidthOrWeight;
3871- else
3872- column->WidthRequest = column_settings->WidthOrWeight;
4052+ while (dst_idx < table->ColumnsCount && table->Columns[dst_idx].IsLoadedSettings)
4053+ dst_idx++;
4054+ if (dst_idx >= table->ColumnsCount)
4055+ break;
4056+ TableLoadSettingsForColumn(&table->Columns[dst_idx], &column_settings[n], settings->SaveFlags);
4057+ dst_idx++;
38734058 }
3874- if (settings->SaveFlags & ImGuiTableFlags_Reorderable)
3875- column->DisplayOrder = column_settings->DisplayOrder;
3876- if ((settings->SaveFlags & ImGuiTableFlags_Hideable) && column_settings->IsEnabled != -1)
3877- column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled == 1;
3878- column->SortOrder = column_settings->SortOrder;
3879- column->SortDirection = column_settings->SortDirection;
3880- }
4059+}
38814060
3882- // Fix display order and build index
3883- if (settings->SaveFlags & ImGuiTableFlags_Reorderable)
3884- TableFixDisplayOrder(table);
3885- for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
3886- table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n;
4061+void ImGui::TableLoadSettingsForColumn(ImGuiTableColumn* column, ImGuiTableColumnSettings* column_settings, ImGuiTableFlags load_flags)
4062+{
4063+ column->IsLoadedSettings = true;
4064+ column_settings->IsLoaded = true;
4065+ if (load_flags & ImGuiTableFlags_Resizable)
4066+ {
4067+ if (column_settings->IsStretch)
4068+ column->StretchWeight = column_settings->WidthOrWeight;
4069+ else
4070+ column->WidthRequest = column_settings->WidthOrWeight;
4071+ column->AutoFitQueue = 0x00;
4072+ }
4073+ if (load_flags & ImGuiTableFlags_Reorderable)
4074+ column->DisplayOrder = column_settings->DisplayOrder;
4075+ else
4076+ column->DisplayOrder = column_settings->Index; // Because default depends on previous Index, we need to set that up and cannot rely on TableInitColumnDefaults()
4077+ if ((load_flags & ImGuiTableFlags_Hideable) && column_settings->IsEnabled != -1)
4078+ column->IsUserEnabled = column->IsUserEnabledNextFrame = (column_settings->IsEnabled == 1);
4079+ column->SortOrder = column_settings->SortOrder;
4080+ column->SortDirection = column_settings->SortDirection;
38874081 }
38884082
38894083 struct ImGuiTableFixDisplayOrderColumnData
@@ -3898,7 +4092,8 @@
38984092 const ImGuiTable* table = ((const ImGuiTableFixDisplayOrderColumnData*)lhs)->Table;
38994093 const ImGuiTableColumnIdx lhs_idx = ((const ImGuiTableFixDisplayOrderColumnData*)lhs)->Idx;
39004094 const ImGuiTableColumnIdx rhs_idx = ((const ImGuiTableFixDisplayOrderColumnData*)rhs)->Idx;
3901- const int order_delta = (table->Columns[lhs_idx].DisplayOrder - table->Columns[rhs_idx].DisplayOrder);
4095+ // Assume ImGuiTableColumnIdx == signed short, to turn -1 into a large value so that it always sort after.
4096+ const int order_delta = ((unsigned short)table->Columns[lhs_idx].DisplayOrder - (unsigned short)table->Columns[rhs_idx].DisplayOrder);
39024097 return (order_delta > 0) ? +1 : (order_delta < 0) ? -1 : (lhs_idx > rhs_idx) ? +1 : -1;
39034098 }
39044099
@@ -3916,6 +4111,8 @@
39164111 ImQsort(fdo_columns, (size_t)table->ColumnsCount, sizeof(ImGuiTableFixDisplayOrderColumnData), TableFixDisplayOrderComparer);
39174112 for (int n = 0; n < table->ColumnsCount; n++)
39184113 table->Columns[fdo_columns[n].Idx].DisplayOrder = (ImGuiTableColumnIdx)n;
4114+ for (int n = 0; n < table->ColumnsCount; n++)
4115+ table->DisplayOrderToIndex[table->Columns[n].DisplayOrder] = (ImGuiTableColumnIdx)n;
39194116 }
39204117
39214118 static void TableSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
@@ -3975,12 +4172,13 @@
39754172 char c = 0;
39764173 ImGuiTableColumnSettings* column = settings->GetColumnSettings() + column_n;
39774174 column->Index = (ImGuiTableColumnIdx)column_n;
3978- if (sscanf(line, "UserID=0x%08X%n", (ImU32*)&n, &r)==1) { line = ImStrSkipBlank(line + r); column->UserID = (ImGuiID)n; }
4175+ if (sscanf(line, "UserID=0x%08X%n", (ImU32*)&n, &r)==1) { line = ImStrSkipBlank(line + r); } // FIXME-LEGACY: Removed 2025/11/12, was never properly set.
39794176 if (sscanf(line, "Width=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->WidthOrWeight = (float)n; column->IsStretch = 0; settings->SaveFlags |= ImGuiTableFlags_Resizable; }
39804177 if (sscanf(line, "Weight=%f%n", &f, &r) == 1) { line = ImStrSkipBlank(line + r); column->WidthOrWeight = f; column->IsStretch = 1; settings->SaveFlags |= ImGuiTableFlags_Resizable; }
39814178 if (sscanf(line, "Visible=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->IsEnabled = (ImU8)n; settings->SaveFlags |= ImGuiTableFlags_Hideable; }
39824179 if (sscanf(line, "Order=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->DisplayOrder = (ImGuiTableColumnIdx)n; settings->SaveFlags |= ImGuiTableFlags_Reorderable; }
39834180 if (sscanf(line, "Sort=%d%c%n", &n, &c, &r) == 2) { line = ImStrSkipBlank(line + r); column->SortOrder = (ImGuiTableColumnIdx)n; column->SortDirection = (c == '^') ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending; settings->SaveFlags |= ImGuiTableFlags_Sortable; }
4181+ if (sscanf(line, "ID=0x%08X%n", (ImU32*)&n, &r) == 1) { line = ImStrSkipBlank(line + r); column->ID = (ImGuiID)n; }
39844182 }
39854183 }
39864184
@@ -4008,16 +4206,16 @@
40084206 for (int column_n = 0; column_n < settings->ColumnsCount; column_n++, column++)
40094207 {
40104208 // "Column 0 UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v"
4011- bool save_column = column->UserID != 0 || save_size || save_visible || save_order || (save_sort && column->SortOrder != -1);
4209+ bool save_column = save_size || save_visible || save_order || (save_sort && column->SortOrder != -1);
40124210 if (!save_column)
40134211 continue;
40144212 buf->appendf("Column %-2d", column_n);
4015- if (column->UserID != 0) { buf->appendf(" UserID=%08X", column->UserID); }
40164213 if (save_size && column->IsStretch) { buf->appendf(" Weight=%.4f", column->WidthOrWeight); }
40174214 if (save_size && !column->IsStretch) { buf->appendf(" Width=%d", (int)column->WidthOrWeight); }
40184215 if (save_visible) { buf->appendf(" Visible=%d", column->IsEnabled); }
40194216 if (save_order) { buf->appendf(" Order=%d", column->DisplayOrder); }
40204217 if (save_sort && column->SortOrder != -1) { buf->appendf(" Sort=%d%c", column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? 'v' : '^'); }
4218+ if (column->ID != 0) { buf->appendf(" ID=0x%08X", column->ID); }
40214219 buf->append("\n");
40224220 }
40234221 buf->append("\n");
@@ -4075,11 +4273,12 @@
40754273
40764274 void ImGui::TableGcCompactTransientBuffers(ImGuiTableTempData* temp_data)
40774275 {
4276+ temp_data->AngledHeadersRequests.clear();
40784277 temp_data->DrawSplitter.ClearFreeMemory();
40794278 temp_data->LastTimeActive = -1.0f;
40804279 }
40814280
4082-// Compact and remove unused settings data (currently only used by TestEngine)
4281+// Compact and remove unused or resize settings data (only TestEngine mark unused, but resizing table down can lead to compaction)
40834282 void ImGui::TableGcCompactSettings()
40844283 {
40854284 ImGuiContext& g = *GImGui;
@@ -4095,6 +4294,9 @@
40954294 if (settings->ID != 0)
40964295 memcpy(new_chunk_stream.alloc_chunk(TableSettingsCalcChunkSize(settings->ColumnsCount)), settings, TableSettingsCalcChunkSize(settings->ColumnsCount));
40974296 g.SettingsTables.swap(new_chunk_stream);
4297+ for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++)
4298+ if (ImGuiTable* table = g.Tables.TryGetMapData(table_n))
4299+ table->SettingsOffset = -1;
40984300 }
40994301
41004302
@@ -4102,6 +4304,7 @@
41024304 // [SECTION] Tables: Debugging
41034305 //-------------------------------------------------------------------------
41044306 // - DebugNodeTable() [Internal]
4307+// - DebugNodeTableSettings() [Internal]
41054308 //-------------------------------------------------------------------------
41064309
41074310 #ifndef IMGUI_DISABLE_DEBUG_TOOLS
@@ -4165,13 +4368,13 @@
41654368 "WidthGiven: %.1f, Request/Auto: %.1f/%.1f, StretchWeight: %.3f (%.1f%%)\n"
41664369 "MinX: %.1f, MaxX: %.1f (%+.1f), ClipRect: %.1f to %.1f (+%.1f)\n"
41674370 "ContentWidth: %.1f,%.1f, HeadersUsed/Ideal %.1f/%.1f\n"
4168- "Sort: %d%s, UserID: 0x%08X, Flags: 0x%04X: %s%s%s..",
4371+ "Sort: %d%s, UserData: 0x%08X, Flags: 0x%04X: %s%s%s..",
41694372 n, column->DisplayOrder, name, column->MinX - table->WorkRect.Min.x, column->MaxX - table->WorkRect.Min.x, (n < table->FreezeColumnsRequest) ? " (Frozen)" : "",
41704373 column->IsEnabled, column->IsVisibleX, column->IsVisibleY, column->IsRequestOutput, column->IsSkipItems, column->DrawChannelFrozen, column->DrawChannelUnfrozen,
41714374 column->WidthGiven, column->WidthRequest, column->WidthAuto, column->StretchWeight, column->StretchWeight > 0.0f ? (column->StretchWeight / sum_weights) * 100.0f : 0.0f,
41724375 column->MinX, column->MaxX, column->MaxX - column->MinX, column->ClipRect.Min.x, column->ClipRect.Max.x, column->ClipRect.Max.x - column->ClipRect.Min.x,
41734376 column->ContentMaxXFrozen - column->WorkMinX, column->ContentMaxXUnfrozen - column->WorkMinX, column->ContentMaxXHeadersUsed - column->WorkMinX, column->ContentMaxXHeadersIdeal - column->WorkMinX,
4174- column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? " (Asc)" : (column->SortDirection == ImGuiSortDirection_Descending) ? " (Des)" : "", column->UserID, column->Flags,
4377+ column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? " (Asc)" : (column->SortDirection == ImGuiSortDirection_Descending) ? " (Des)" : "", column->UserData, column->Flags,
41754378 (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? "WidthStretch " : "",
41764379 (column->Flags & ImGuiTableColumnFlags_WidthFixed) ? "WidthFixed " : "",
41774380 (column->Flags & ImGuiTableColumnFlags_NoResize) ? "NoResize " : "");
@@ -4184,34 +4387,45 @@
41844387 }
41854388 }
41864389 if (ImGuiTableSettings* settings = TableGetBoundSettings(table))
4187- DebugNodeTableSettings(settings);
4390+ DebugNodeTableSettings(settings, table);
41884391 if (clear_settings)
4189- table->IsResetAllRequest = true;
4392+ table->IsResetAllRequest = true; // Queue a call to TableResetSettings()
41904393 TreePop();
41914394 }
41924395
4193-void ImGui::DebugNodeTableSettings(ImGuiTableSettings* settings)
4396+void ImGui::DebugNodeTableSettings(ImGuiTableSettings* settings, ImGuiTable* table)
41944397 {
4195- if (!TreeNode((void*)(intptr_t)settings->ID, "Settings 0x%08X (%d columns)", settings->ID, settings->ColumnsCount))
4196- return;
4197- BulletText("SaveFlags: 0x%08X", settings->SaveFlags);
4198- BulletText("ColumnsCount: %d (max %d)", settings->ColumnsCount, settings->ColumnsCountMax);
4199- for (int n = 0; n < settings->ColumnsCount; n++)
4398+ if (settings->ID == 0)
4399+ PushID(settings);
4400+ const bool open = TreeNode((void*)(intptr_t)settings->ID, "Settings 0x%08X (%d columns)", settings->ID, settings->ColumnsCount);
4401+ const bool hovered = IsItemHovered();
4402+ if (hovered && table == NULL && settings->ID != 0)
4403+ table = TableFindByID(settings->ID);
4404+ if (hovered && table != NULL)
4405+ GetForegroundDrawList(table->OuterWindow)->AddRect(table->OuterRect.Min, table->OuterRect.Max, IM_COL32(255, 255, 0, 255));
4406+ if (open)
42004407 {
4201- ImGuiTableColumnSettings* column_settings = &settings->GetColumnSettings()[n];
4202- ImGuiSortDirection sort_dir = (column_settings->SortOrder != -1) ? (ImGuiSortDirection)column_settings->SortDirection : ImGuiSortDirection_None;
4203- BulletText("Column %d Order %d SortOrder %d %s Vis %d %s %7.3f UserID 0x%08X",
4204- n, column_settings->DisplayOrder, column_settings->SortOrder,
4205- (sort_dir == ImGuiSortDirection_Ascending) ? "Asc" : (sort_dir == ImGuiSortDirection_Descending) ? "Des" : "---",
4206- column_settings->IsEnabled, column_settings->IsStretch ? "Weight" : "Width ", column_settings->WidthOrWeight, column_settings->UserID);
4408+ BulletText("SaveFlags: 0x%08X", settings->SaveFlags);
4409+ BulletText("ColumnsCount: %d (max %d)", settings->ColumnsCount, settings->ColumnsCountMax);
4410+ for (int n = 0; n < settings->ColumnsCount; n++)
4411+ {
4412+ ImGuiTableColumnSettings* column_settings = &settings->GetColumnSettings()[n];
4413+ ImGuiSortDirection sort_dir = (column_settings->SortOrder != -1) ? (ImGuiSortDirection)column_settings->SortDirection : ImGuiSortDirection_None;
4414+ BulletText("Column %d Order %d SortOrder %2d %s Vis %d %s %7.3f ID 0x%08X",
4415+ n, column_settings->DisplayOrder, column_settings->SortOrder,
4416+ (sort_dir == ImGuiSortDirection_Ascending) ? "Asc" : (sort_dir == ImGuiSortDirection_Descending) ? "Des" : "---",
4417+ column_settings->IsEnabled, column_settings->IsStretch ? "Weight" : "Width ", column_settings->WidthOrWeight, column_settings->ID);
4418+ }
4419+ TreePop();
42074420 }
4208- TreePop();
4421+ if (settings->ID == 0)
4422+ PopID();
42094423 }
42104424
42114425 #else // #ifndef IMGUI_DISABLE_DEBUG_TOOLS
42124426
42134427 void ImGui::DebugNodeTable(ImGuiTable*) {}
4214-void ImGui::DebugNodeTableSettings(ImGuiTableSettings*) {}
4428+void ImGui::DebugNodeTableSettings(ImGuiTableSettings*, ImGuiTable*) {}
42154429
42164430 #endif
42174431
@@ -1,4 +1,4 @@
1-// dear imgui, v1.92.8
1+// dear imgui, v1.92.9 WIP
22 // (widgets code)
33
44 /*
@@ -266,6 +266,8 @@
266266 }
267267 }
268268
269+// Note that all functions taking format strings in the API may be passed ("%s", text) or ("%.*s", text_len, text),
270+// which will automatically bypass the formatter.
269271 void ImGui::TextUnformatted(const char* text, const char* text_end)
270272 {
271273 TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText);
@@ -562,7 +564,7 @@
562564 flags |= (item_flags & ImGuiItemFlags_ButtonRepeat) ? ImGuiButtonFlags_PressedOnClick : ImGuiButtonFlags_PressedOnDefault_;
563565
564566 ImGuiWindow* backup_hovered_window = g.HoveredWindow;
565- const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window->RootWindow;
567+ const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindowDockTree == window->RootWindowDockTree;
566568 if (flatten_hovered_children)
567569 g.HoveredWindow = window;
568570
@@ -937,7 +939,8 @@
937939 return pressed;
938940 }
939941
940-bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos)
942+// The Collapse button also functions as a Dock Menu button.
943+bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_node)
941944 {
942945 ImGuiContext& g = *GImGui;
943946 ImGuiWindow* window = g.CurrentWindow;
@@ -950,16 +953,21 @@
950953 return pressed;
951954
952955 // Render
956+ //bool is_dock_menu = (window->DockNodeAsHost && !window->Collapsed);
953957 ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
954958 ImU32 text_col = GetColorU32(ImGuiCol_Text);
955959 if (hovered || held)
956960 window->DrawList->AddRectFilled(bb.Min, bb.Max, bg_col);
957961 RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact);
958- RenderArrow(window->DrawList, bb.Min, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
959962
963+ if (dock_node)
964+ RenderArrowDockMenu(window->DrawList, bb.Min, g.FontSize, text_col);
965+ else
966+ RenderArrow(window->DrawList, bb.Min, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
967+
960968 // Switch to moving the window after mouse is moved beyond the initial drag threshold
961969 if (IsItemActive() && IsMouseDragging(0))
962- StartMouseMovingWindow(window);
970+ StartMouseMovingWindowOrNode(window, dock_node, true); // Undock from window/collapse menu button
963971
964972 return pressed;
965973 }
@@ -1003,7 +1011,8 @@
10031011
10041012 // Calculate scrollbar bounding box
10051013 ImRect bb = GetWindowScrollbarRect(window, axis);
1006- ImDrawFlags rounding_corners = CalcRoundingFlagsForRectInRect(bb, window->Rect(), g.Style.WindowBorderSize);
1014+ ImRect host_rect = (window->DockIsActive ? window->DockNode->HostWindow : window)->Rect();
1015+ ImDrawFlags rounding_corners = CalcRoundingFlagsForRectInRect(bb, host_rect, g.Style.WindowBorderSize);
10071016 float size_visible = window->InnerRect.Max[axis] - window->InnerRect.Min[axis];
10081017 float size_contents = window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f;
10091018 ImS64 scroll = (ImS64)window->Scroll[axis];
@@ -1272,7 +1281,7 @@
12721281
12731282 // Range-Selection/Multi-selection support (footer)
12741283 if (is_multi_select)
1275- MultiSelectItemFooter(id, &checked, &pressed);
1284+ MultiSelectItemFooter(id, &checked, &pressed, ImGuiMultiSelectFlags_CheckboxMode_);
12761285 else if (pressed)
12771286 checked = !checked;
12781287
@@ -1575,7 +1584,7 @@
15751584 bool pressed = TextLink(label);
15761585 if (pressed && g.PlatformIO.Platform_OpenInShellFn != NULL)
15771586 g.PlatformIO.Platform_OpenInShellFn(&g, url);
1578- SetItemTooltip(LocalizeGetMsg(ImGuiLocKey_OpenLink_s), url); // It is more reassuring for user to _always_ display URL when we same as label
1587+ SetItemTooltip(LocalizeGetMsg(ImGuiLocKey_OpenLink_s), url); // It is more reassuring for user to _always_ display URL when it is the same as the label.
15791588 if (BeginPopupContextItem())
15801589 {
15811590 if (MenuItem(LocalizeGetMsg(ImGuiLocKey_CopyLink)))
@@ -1746,14 +1755,14 @@
17461755 const float separator_thickness = style.SeparatorTextBorderSize;
17471756 const ImVec2 min_size(label_size.x + extra_w + padding.x * 2.0f, ImMax(label_size.y + padding.y * 2.0f, separator_thickness));
17481757 const ImRect bb(pos, ImVec2(window->WorkRect.Max.x, pos.y + min_size.y));
1749- 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));
1758+ const float text_baseline_y = ImTrunc((bb.GetHeight() - label_size.y) * style.SeparatorTextAlign.y + 0.999f); //ImMax(padding.y, ImTrunc((style.SeparatorTextSize - label_size.y) * 0.5f));
17501759 ItemSize(min_size, text_baseline_y);
17511760 if (!ItemAdd(bb, id))
17521761 return;
17531762
17541763 const float sep1_x1 = pos.x;
17551764 const float sep2_x2 = bb.Max.x;
1756- const float seps_y = ImTrunc((bb.Min.y + bb.Max.y) * 0.5f + 0.99999f);
1765+ const float seps_y = ImTrunc((bb.Min.y + bb.Max.y) * 0.5f + 0.999f);
17571766
17581767 const float label_avail_w = ImMax(0.0f, sep2_x2 - sep1_x1 - padding.x * 2.0f);
17591768 const ImVec2 label_pos(pos.x + padding.x + ImMax(0.0f, (label_avail_w - label_size.x - extra_w) * style.SeparatorTextAlign.x), pos.y + text_baseline_y); // FIXME-ALIGN
@@ -5641,7 +5650,7 @@
56415650 ImVec2 cursor_screen_pos = ImTrunc(draw_pos + cursor_offset - draw_scroll);
56425651 ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f);
56435652 if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))
5644- draw_window->DrawList->AddLineV(cursor_screen_rect.Min.x, cursor_screen_rect.Min.y, cursor_screen_rect.Max.y, GetColorU32(ImGuiCol_InputTextCursor), 1.0f * (float)(int)style._MainScale); // FIXME-DPI: Cursor thickness (#7031)
5653+ draw_window->DrawList->AddLineV(cursor_screen_rect.Min.x, cursor_screen_rect.Min.y, cursor_screen_rect.Max.y, GetColorU32(ImGuiCol_InputTextCursor), style.InputTextCursorSize);
56455654
56465655 // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.)
56475656 // This is required for some backends (SDL3) to start emitting character/text inputs.
@@ -7114,9 +7123,9 @@
71147123 if (hovered || selected)
71157124 {
71167125 const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
7117- RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false);
7126+ RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false, 0.0f);
71187127 }
7119- RenderNavCursor(frame_bb, id, nav_render_cursor_flags);
7128+ RenderNavCursor(frame_bb, id, nav_render_cursor_flags, 0.0f);
71207129 if (span_all_columns && !span_all_columns_label)
71217130 TablePopBackgroundChannel();
71227131 if (flags & ImGuiTreeNodeFlags_Bullet)
@@ -7496,14 +7505,14 @@
74967505 {
74977506 // Between 1.91.0 and 1.91.4 we made selected Selectable use an arbitrary lerp between _Header and _HeaderHovered. Removed that now. (#8106)
74987507 ImU32 col = GetColorU32((held && highlighted) ? ImGuiCol_HeaderActive : highlighted ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
7499- RenderFrame(bb.Min, bb.Max, col, false, 0.0f);
7508+ RenderFrame(bb.Min, bb.Max, col, false, style.SelectableRounding);
75007509 }
75017510 if (g.NavId == id)
75027511 {
7503- ImGuiNavRenderCursorFlags nav_render_cursor_flags = ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding;
7512+ ImGuiNavRenderCursorFlags nav_render_cursor_flags = ImGuiNavRenderCursorFlags_Compact;
75047513 if (is_multi_select)
75057514 nav_render_cursor_flags |= ImGuiNavRenderCursorFlags_AlwaysDraw; // Always show the nav rectangle
7506- RenderNavCursor(bb, id, nav_render_cursor_flags);
7515+ RenderNavCursor(bb, id, nav_render_cursor_flags, style.SelectableRounding);
75077516 }
75087517 }
75097518
@@ -8305,7 +8314,7 @@
83058314 // - Altering selection based on Ctrl/Shift modifiers, both for keyboard and mouse.
83068315 // - Record current selection state for RangeSrc
83078316 // This is all rather complex, best to run and refer to "widgets_multiselect_xxx" tests in imgui_test_suite.
8308-void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
8317+void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed, ImGuiMultiSelectFlags extra_flags)
83098318 {
83108319 ImGuiContext& g = *GImGui;
83118320 ImGuiWindow* window = g.CurrentWindow;
@@ -8325,7 +8334,7 @@
83258334
83268335 ImGuiSelectionUserData item_data = g.NextItemData.SelectionUserData;
83278336
8328- ImGuiMultiSelectFlags flags = ms->Flags;
8337+ ImGuiMultiSelectFlags flags = ms->Flags | extra_flags;
83298338 const bool is_singleselect = (flags & ImGuiMultiSelectFlags_SingleSelect) != 0;
83308339 bool is_ctrl = (ms->KeyMods & ImGuiMod_Ctrl) != 0;
83318340 bool is_shift = (ms->KeyMods & ImGuiMod_Shift) != 0;
@@ -8479,7 +8488,7 @@
84798488 //IM_ASSERT(storage->HasRangeSrc && storage->HasRangeValue);
84808489 if (storage->RangeSrcItem == ImGuiSelectionUserData_Invalid)
84818490 storage->RangeSrcItem = item_data;
8482- if ((flags & ImGuiMultiSelectFlags_NoAutoSelect) == 0)
8491+ if ((flags & ImGuiMultiSelectFlags_CheckboxMode_) == 0)
84838492 {
84848493 // Shift+Arrow always select
84858494 // Ctrl+Shift+Arrow copy source selection state (already stored by BeginMultiSelect() in storage->RangeSelected)
@@ -8499,7 +8508,7 @@
84998508 else
85008509 {
85018510 // Ctrl inverts selection, otherwise always select
8502- if ((flags & ImGuiMultiSelectFlags_NoAutoSelect) == 0)
8511+ if ((flags & ImGuiMultiSelectFlags_CheckboxMode_) == 0)
85038512 selected = is_ctrl ? !selected : true;
85048513 else
85058514 selected = !selected;
@@ -8950,7 +8959,7 @@
89508959 // Tooltip on hover
89518960 if (hovered && inner_bb.Contains(g.IO.MousePos))
89528961 {
8953- const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f);
8962+ const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.999f);
89548963 const int v_idx = (int)(t * item_count);
89558964 IM_ASSERT(v_idx >= 0 && v_idx < values_count);
89568965
@@ -9163,9 +9172,10 @@
91639172
91649173 // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect.
91659174 // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy.
9166- const float border_top = ImMax(window->WindowBorderSize * 0.5f - window->TitleBarHeight, 0.0f);
9175+ const float border_top = ImMax(IM_ROUND(window->WindowBorderSize * 0.5f - window->TitleBarHeight), 0.0f);
9176+ const float border_half = IM_ROUND(window->WindowBorderSize * 0.5f);
91679177 ImRect bar_rect = window->MenuBarRect();
9168- ImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize * 0.5f), IM_ROUND(bar_rect.Min.y + border_top), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize * 0.5f))), IM_ROUND(bar_rect.Max.y));
9178+ ImRect clip_rect(ImFloor(bar_rect.Min.x + border_half), ImFloor(bar_rect.Min.y + border_top), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, border_half))), ImFloor(bar_rect.Max.y));
91699179 clip_rect.ClipWith(window->OuterRectClipped);
91709180 PushClipRect(clip_rect.Min, clip_rect.Max, false);
91719181
@@ -9246,10 +9256,10 @@
92469256 IM_ASSERT(dir != ImGuiDir_None);
92479257
92489258 ImGuiWindow* bar_window = FindWindowByName(name);
9259+ ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)(viewport_p ? viewport_p : GetMainViewport());
92499260 if (bar_window == NULL || bar_window->BeginCount == 0)
92509261 {
92519262 // Calculate and set window size/position
9252- ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)(viewport_p ? viewport_p : GetMainViewport());
92539263 ImRect avail_rect = viewport->GetBuildWorkRect();
92549264 ImGuiAxis axis = (dir == ImGuiDir_Up || dir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X;
92559265 ImVec2 pos = avail_rect.Min;
@@ -9267,7 +9277,8 @@
92679277 viewport->BuildWorkInsetMax[axis] += axis_size;
92689278 }
92699279
9270- window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
9280+ window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDocking;
9281+ SetNextWindowViewport(viewport->ID); // Enforce viewport so we don't create our own viewport when ImGuiConfigFlags_ViewportsNoMerge is set.
92719282 PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
92729283 PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint
92739284 bool is_open = Begin(name, NULL, window_flags);
@@ -9281,6 +9292,9 @@
92819292 ImGuiContext& g = *GImGui;
92829293 ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport();
92839294
9295+ // Notify of viewport change so GetFrameHeight() can be accurate in case of DPI change
9296+ SetCurrentViewport(NULL, viewport);
9297+
92849298 // For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set.
92859299 // FIXME: This could be generalized as an opt-in way to clamp window->DC.CursorStartPos to avoid SafeArea?
92869300 // FIXME: Consider removing support for safe area down the line... it's messy. Nowadays consoles have support for TV calibration in OS settings.
@@ -9338,7 +9352,7 @@
93389352 const ImGuiPopupData* upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size];
93399353 if (window->DC.NavLayerCurrent != upper_popup->ParentNavLayer)
93409354 return false;
9341- return upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && ImGui::IsWindowChildOf(upper_popup->Window, window, true);
9355+ return upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && ImGui::IsWindowChildOf(upper_popup->Window, window, true, false);
93429356 }
93439357
93449358 bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
@@ -9348,7 +9362,7 @@
93489362 return false;
93499363
93509364 ImGuiContext& g = *GImGui;
9351- const ImGuiStyle& style = g.Style;
9365+ ImGuiStyle& style = g.Style;
93529366 const ImGuiID id = window->GetID(label);
93539367 bool menu_is_open = IsPopupOpen(id, ImGuiPopupFlags_None);
93549368
@@ -9393,6 +9407,8 @@
93939407
93949408 bool pressed;
93959409
9410+ const float backup_rounding = style.SelectableRounding;
9411+ style.SelectableRounding = style.MenuItemRounding;
93969412 const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoAutoClosePopups | (ImGuiSelectableFlags)ImGuiSelectableFlags_SelectOnClick;
93979413 ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
93989414 if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
@@ -9428,6 +9444,7 @@
94289444 RenderArrow(window->DrawList, ImVec2(text_pos.x + offsets->OffsetMark + extra_w + g.FontSize * 0.30f, text_pos.y), GetColorU32(ImGuiCol_Text), ImGuiDir_Right);
94299445 popup_pos = ImVec2(pos.x, text_pos.y - style.WindowPadding.y);
94309446 }
9447+ style.SelectableRounding = backup_rounding;
94319448 if (!enabled)
94329449 EndDisabled();
94339450
@@ -9614,6 +9631,8 @@
96149631 BeginDisabled();
96159632
96169633 // We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another.
9634+ const float backup_rounding = style.SelectableRounding;
9635+ style.SelectableRounding = style.MenuItemRounding;
96179636 const ImGuiSelectableFlags selectable_flags = (ImGuiSelectableFlags)ImGuiSelectableFlags_SelectOnRelease | (ImGuiSelectableFlags)ImGuiSelectableFlags_SetNavIdOnHover;
96189637 ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
96199638 if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
@@ -9636,7 +9655,7 @@
96369655 // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.)
96379656 float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f;
96389657 float shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut, NULL).x : 0.0f;
9639- float checkmark_w = IM_TRUNC(g.FontSize * 1.20f);
9658+ float checkmark_w = IM_TRUNC(g.FontSize * 1.20f); // FIXME: Always accounted for, even in a menu with none, because 'selected' has no neutral setting.
96409659 float min_w = offsets->DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame
96419660 float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
96429661 ImVec2 text_pos(pos.x, pos.y + window->DC.CurrLineTextBaseOffset);
@@ -9657,6 +9676,7 @@
96579676 RenderCheckMark(window->DrawList, text_pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f);
96589677 }
96599678 }
9679+ style.SelectableRounding = backup_rounding;
96609680
96619681 // Once dragged, release ActiveId + key ownership. This is to allow the idiom of mouse down a menu, dragging elsewhere, up on some other MenuItem(). (#8233, #9394)
96629682 // Could move logic into lower-level ImGuiButtonFlags_AutoReleaseActiveId + ImGuiButtonFlags_AutoReleaseKeyOwner? Easier once we get rid of the Selectable() middle-man here.
@@ -9705,8 +9725,10 @@
97059725 // - TabBarCalcMaxTabWidth() [Internal]
97069726 // - TabBarFindTabById() [Internal]
97079727 // - TabBarFindTabByOrder() [Internal]
9728+// - TabBarFindMostRecentlySelectedTabForActiveWindow() [Internal]
97089729 // - TabBarGetCurrentTab() [Internal]
97099730 // - TabBarGetTabName() [Internal]
9731+// - TabBarAddTab() [Internal]
97109732 // - TabBarRemoveTab() [Internal]
97119733 // - TabBarCloseTab() [Internal]
97129734 // - TabBarScrollClamp() [Internal]
@@ -9823,7 +9845,7 @@
98239845 return false;
98249846
98259847 IM_ASSERT(tab_bar->ID != 0);
9826- if ((flags & ImGuiTabBarFlags_DockNode) == 0)
9848+ if ((flags & ImGuiTabBarFlags_DockNode) == 0) // Already done
98279849 PushOverrideID(tab_bar->ID);
98289850
98299851 // Add to stack
@@ -9842,7 +9864,8 @@
98429864
98439865 // Ensure correct ordering when toggling ImGuiTabBarFlags_Reorderable flag, or when a new tab was added while being not reorderable
98449866 if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable)))
9845- ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder);
9867+ if ((flags & ImGuiTabBarFlags_DockNode) == 0) // FIXME: TabBar with DockNode can now be hybrid
9868+ ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder);
98469869 tab_bar->TabsAddedNew = false;
98479870
98489871 // Flags
@@ -9905,7 +9928,7 @@
99059928 window->DC.CursorPos = tab_bar->BackupCursorPos;
99069929
99079930 tab_bar->LastTabItemIdx = -1;
9908- if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0)
9931+ if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) // Already done
99099932 PopID();
99109933
99119934 g.CurrentTabBarStack.pop_back();
@@ -10147,6 +10170,10 @@
1014710170 tab_bar->VisibleTabId = tab_bar->SelectedTabId;
1014810171 tab_bar->VisibleTabWasSubmitted = false;
1014910172
10173+ // CTRL+TAB can override visible tab temporarily
10174+ if (g.NavWindowingTarget != NULL && g.NavWindowingTarget->DockNode && g.NavWindowingTarget->DockNode->TabBar == tab_bar)
10175+ tab_bar->VisibleTabId = scroll_to_tab_id = g.NavWindowingTarget->TabId;
10176+
1015010177 // Apply request requests
1015110178 if (scroll_to_tab_id != 0)
1015210179 TabBarScrollToTab(tab_bar, scroll_to_tab_id, sections);
@@ -10192,11 +10219,11 @@
1019210219 // Dockable windows uses Name/ID in the global namespace. Non-dockable items use the ID stack.
1019310220 static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window)
1019410221 {
10195- IM_ASSERT(docked_window == NULL); // master branch only
10196- IM_UNUSED(docked_window);
10197- if (tab_bar->Flags & ImGuiTabBarFlags_DockNode)
10222+ if (docked_window != NULL)
1019810223 {
10199- ImGuiID id = ImHashStr(label);
10224+ IM_UNUSED(tab_bar);
10225+ IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_DockNode);
10226+ ImGuiID id = docked_window->TabId;
1020010227 KeepAliveID(id);
1020110228 return id;
1020210229 }
@@ -10230,6 +10257,20 @@
1023010257 return &tab_bar->Tabs[order];
1023110258 }
1023210259
10260+// FIXME: See references to #2304 in TODO.txt
10261+ImGuiTabItem* ImGui::TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar)
10262+{
10263+ ImGuiTabItem* most_recently_selected_tab = NULL;
10264+ for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
10265+ {
10266+ ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
10267+ if (most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected)
10268+ if (tab->Window && tab->Window->WasActive)
10269+ most_recently_selected_tab = tab;
10270+ }
10271+ return most_recently_selected_tab;
10272+}
10273+
1023310274 ImGuiTabItem* ImGui::TabBarGetCurrentTab(ImGuiTabBar* tab_bar)
1023410275 {
1023510276 if (tab_bar->LastTabItemIdx < 0 || tab_bar->LastTabItemIdx >= tab_bar->Tabs.Size)
@@ -10239,12 +10280,35 @@
1023910280
1024010281 const char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
1024110282 {
10283+ if (tab->Window)
10284+ return tab->Window->Name;
1024210285 if (tab->NameOffset == -1)
1024310286 return "N/A";
1024410287 IM_ASSERT(tab->NameOffset < tab_bar->TabsNames.Buf.Size);
1024510288 return tab_bar->TabsNames.Buf.Data + tab->NameOffset;
1024610289 }
1024710290
10291+// The purpose of this call is to register tab in advance so we can control their order at the time they appear.
10292+// Otherwise calling this is unnecessary as tabs are appending as needed by the BeginTabItem() function.
10293+void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window)
10294+{
10295+ ImGuiContext& g = *GImGui;
10296+ IM_ASSERT(TabBarFindTabByID(tab_bar, window->TabId) == NULL);
10297+ IM_ASSERT(g.CurrentTabBar != tab_bar); // Can't work while the tab bar is active as our tab doesn't have an X offset yet, in theory we could/should test something like (tab_bar->CurrFrameVisible < g.FrameCount) but we'd need to solve why triggers the commented early-out assert in BeginTabBarEx() (probably dock node going from implicit to explicit in same frame)
10298+
10299+ if (!window->HasCloseButton)
10300+ tab_flags |= ImGuiTabItemFlags_NoCloseButton; // Set _NoCloseButton immediately because it will be used for first-frame width calculation.
10301+
10302+ ImGuiTabItem new_tab;
10303+ new_tab.ID = window->TabId;
10304+ new_tab.Flags = tab_flags;
10305+ new_tab.LastFrameVisible = tab_bar->CurrFrameVisible; // Required so BeginTabBar() doesn't ditch the tab
10306+ if (new_tab.LastFrameVisible == -1)
10307+ new_tab.LastFrameVisible = g.FrameCount - 1;
10308+ new_tab.Window = window; // Required so tab bar layout can compute the tab width before tab submission
10309+ tab_bar->Tabs.push_back(new_tab);
10310+}
10311+
1024810312 // The *TabId fields are already set by the docking system _before_ the actual TabItem was created, so we clear them regardless.
1024910313 void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id)
1025010314 {
@@ -10646,11 +10710,14 @@
1064610710 const bool is_tab_button = (flags & ImGuiTabItemFlags_Button) != 0;
1064710711 tab->LastFrameVisible = g.FrameCount;
1064810712 tab->Flags = flags;
10713+ tab->Window = docked_window;
1064910714
1065010715 // Append name _WITH_ the zero-terminator
10716+ // (regular tabs are permitted in a DockNode tab bar, but window tabs not permitted in a non-DockNode tab bar)
1065110717 if (docked_window != NULL)
1065210718 {
10653- IM_ASSERT(docked_window == NULL); // master branch only
10719+ IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_DockNode);
10720+ tab->NameOffset = -1;
1065410721 }
1065510722 else
1065610723 {
@@ -10675,7 +10742,7 @@
1067510742 tab_bar->VisibleTabWasSubmitted = true;
1067610743
1067710744 // On the very first frame of a tab bar we let first tab contents be visible to minimize appearing glitches
10678- if (!tab_contents_visible && tab_bar->SelectedTabId == 0 && tab_bar_appearing)
10745+ if (!tab_contents_visible && tab_bar->SelectedTabId == 0 && tab_bar_appearing && docked_window == NULL)
1067910746 if (tab_bar->Tabs.Size == 1 && !(tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs))
1068010747 tab_contents_visible = true;
1068110748
@@ -10723,9 +10790,8 @@
1072310790 }
1072410791
1072510792 // Click to Select a tab
10726- // Allow the close button to overlap
1072710793 ImGuiButtonFlags button_flags = ((ImGuiButtonFlags)(is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap);
10728- if (g.DragDropActive)
10794+ if (g.DragDropActive && !g.DragDropPayload.IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW)) // FIXME: May be an opt-in property of the payload to disable this
1072910795 button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
1073010796 bool hovered, held, pressed;
1073110797 if (flags & ImGuiTabItemFlags_Invisible)
@@ -10735,21 +10801,74 @@
1073510801 if (pressed && !is_tab_button)
1073610802 TabBarQueueFocus(tab_bar, tab);
1073710803
10738- // Drag and drop: re-order tabs
10739- if (held && !tab_appearing && IsMouseDragging(0))
10804+ // Transfer active id window so the active id is not owned by the dock host (as StartMouseMovingWindow()
10805+ // will only do it on the drag). This allows FocusWindow() to be more conservative in how it clears active id.
10806+ if (held && docked_window && g.ActiveId == id && g.ActiveIdIsJustActivated)
10807+ g.ActiveIdWindow = docked_window;
10808+
10809+ // Drag and drop a single floating window node moves it
10810+ ImGuiDockNode* node = docked_window ? docked_window->DockNode : NULL;
10811+ const bool single_floating_window_node = node && node->IsFloatingNode() && (node->Windows.Size == 1);
10812+ if (held && single_floating_window_node && IsMouseDragging(0, 0.0f))
1074010813 {
10741- if (!g.DragDropActive && (tab_bar->Flags & ImGuiTabBarFlags_Reorderable))
10814+ // Move
10815+ StartMouseMovingWindow(docked_window);
10816+ }
10817+ else if (held && !tab_appearing && IsMouseDragging(0))
10818+ {
10819+ // Drag and drop: re-order tabs
10820+ int drag_dir = 0;
10821+ float drag_distance_from_edge_x = 0.0f;
10822+ if (!g.DragDropActive && ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (docked_window != NULL)))
1074210823 {
1074310824 // While moving a tab it will jump on the other side of the mouse, so we also test for MouseDelta.x
1074410825 if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x)
1074510826 {
10827+ drag_dir = -1;
10828+ drag_distance_from_edge_x = bb.Min.x - g.IO.MousePos.x;
1074610829 TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos);
1074710830 }
1074810831 else if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x)
1074910832 {
10833+ drag_dir = +1;
10834+ drag_distance_from_edge_x = g.IO.MousePos.x - bb.Max.x;
1075010835 TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos);
1075110836 }
1075210837 }
10838+
10839+ // Extract a Dockable window out of it's tab bar
10840+ const bool can_undock = docked_window != NULL && !(docked_window->Flags & ImGuiWindowFlags_NoMove) && !(node->MergedFlags & ImGuiDockNodeFlags_NoUndocking);
10841+ if (can_undock)
10842+ {
10843+ // We use a variable threshold to distinguish dragging tabs within a tab bar and extracting them out of the tab bar
10844+ bool undocking_tab = (g.DragDropActive && g.DragDropPayload.SourceId == id);
10845+ if (!undocking_tab) //&& (!g.IO.ConfigDockingWithShift || g.IO.KeyShift)
10846+ {
10847+ float threshold_base = g.FontSize;
10848+ float threshold_x = (threshold_base * 2.2f);
10849+ float threshold_y = (threshold_base * 1.5f) + ImClamp((ImFabs(g.IO.MouseDragMaxDistanceAbs[0].x) - threshold_base * 2.0f) * 0.20f, 0.0f, threshold_base * 4.0f);
10850+ //GetForegroundDrawList()->AddRect(ImVec2(bb.Min.x - threshold_x, bb.Min.y - threshold_y), ImVec2(bb.Max.x + threshold_x, bb.Max.y + threshold_y), IM_COL32_WHITE); // [DEBUG]
10851+
10852+ float distance_from_edge_y = ImMax(bb.Min.y - g.IO.MousePos.y, g.IO.MousePos.y - bb.Max.y);
10853+ if (distance_from_edge_y >= threshold_y)
10854+ undocking_tab = true;
10855+ if (drag_distance_from_edge_x > threshold_x)
10856+ if ((drag_dir < 0 && TabBarGetTabOrder(tab_bar, tab) == 0) || (drag_dir > 0 && TabBarGetTabOrder(tab_bar, tab) == tab_bar->Tabs.Size - 1))
10857+ undocking_tab = true;
10858+ }
10859+
10860+ if (undocking_tab)
10861+ {
10862+ // Undock
10863+ // FIXME: refactor to share more code with e.g. StartMouseMovingWindow
10864+ DockContextQueueUndockWindow(&g, docked_window);
10865+ g.MovingWindow = docked_window;
10866+ SetActiveID(g.MovingWindow->MoveId, g.MovingWindow);
10867+ g.ActiveIdClickOffset -= g.MovingWindow->Pos - bb.Min;
10868+ g.ActiveIdNoClearOnFocusLoss = true;
10869+ SetActiveIdUsingAllKeyboardKeys();
10870+ }
10871+ }
1075310872 }
1075410873
1075510874 #if 0
@@ -10798,7 +10917,7 @@
1079810917 flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton;
1079910918
1080010919 // Render tab label, process close button
10801- const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, id) : 0;
10920+ const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, docked_window ? docked_window->ID : id) : 0;
1080210921 bool just_closed;
1080310922 bool text_clipped;
1080410923 TabItemLabelAndCloseButton(display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped);
@@ -10808,6 +10927,11 @@
1080810927 TabBarCloseTab(tab_bar, tab);
1080910928 }
1081010929
10930+ // Forward Hovered state so IsItemHovered() after Begin() can work (even though we are technically hovering our parent)
10931+ // That state is copied to window->DockTabItemStatusFlags by our caller.
10932+ if (docked_window && (hovered || g.HoveredId == close_button_id))
10933+ g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
10934+
1081110935 // Tooltip
1081210936 // (Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer-> seems ok)
1081310937 // (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores)
@@ -10843,6 +10967,16 @@
1084310967 if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id))
1084410968 tab->WantClose = true; // Will be processed by next call to TabBarLayout()
1084510969 }
10970+ else if (ImGuiWindow* window = FindWindowByName(label))
10971+ {
10972+ if (window->DockIsActive)
10973+ if (ImGuiDockNode* node = window->DockNode)
10974+ {
10975+ ImGuiID tab_id = TabBarCalcTabID(node->TabBar, label, window);
10976+ TabBarRemoveTab(node->TabBar, tab_id);
10977+ window->DockTabWantClose = true;
10978+ }
10979+ }
1084610980 }
1084710981
1084810982 ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker)
@@ -10857,10 +10991,9 @@
1085710991 return ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y);
1085810992 }
1085910993
10860-ImVec2 ImGui::TabItemCalcSize(ImGuiWindow*)
10994+ImVec2 ImGui::TabItemCalcSize(ImGuiWindow* window)
1086110995 {
10862- IM_ASSERT(0); // This function exists to facilitate merge with 'docking' branch.
10863- return ImVec2(0.0f, 0.0f);
10996+ return TabItemCalcSize(window->Name, window->HasCloseButton || (window->Flags & ImGuiWindowFlags_UnsavedDocument));
1086410997 }
1086510998
1086610999 void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col)
@@ -10871,13 +11004,9 @@
1087111004 IM_UNUSED(flags);
1087211005 IM_ASSERT(width > 0.0f);
1087311006 const float rounding = ImMax(0.0f, ImMin((flags & ImGuiTabItemFlags_Button) ? g.Style.FrameRounding : g.Style.TabRounding, width * 0.5f - 1.0f));
10874- const float y1 = bb.Min.y + 1.0f;
11007+ const float y1 = bb.Min.y + 1.0f; // Leave a bit of room in title bars.
1087511008 const float y2 = bb.Max.y - g.Style.TabBarBorderSize;
10876- draw_list->PathLineTo(ImVec2(bb.Min.x, y2));
10877- draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9);
10878- draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12);
10879- draw_list->PathLineTo(ImVec2(bb.Max.x, y2));
10880- draw_list->PathFillConvex(col);
11009+ draw_list->AddRectFilled(bb.Min, ImVec2(bb.Max.x, y2), col, rounding, ImDrawFlags_RoundCornersTop);
1088111010 if (g.Style.TabBorderSize > 0.0f)
1088211011 {
1088311012 draw_list->PathLineTo(ImVec2(bb.Min.x + 0.5f, y2));
@@ -55,4 +55,8 @@
5555 <DisplayString>{{Name {Name,s} Active {(Active||WasActive)?1:0,d} Child {(Flags &amp; 0x01000000)?1:0,d} Popup {(Flags &amp; 0x04000000)?1:0,d} Hidden {(Hidden)?1:0,d}}</DisplayString>
5656 </Type>
5757
58+<Type Name="ImGuiDockNode">
59+ <DisplayString>{{ID {ID,x} Pos=({Pos.x,g} {Pos.y,g}) Size=({Size.x,g} {Size.y,g}) Parent {(ParentNode==0)?0:ParentNode->ID,x} Childs {(ChildNodes[0] != 0)+(ChildNodes[1] != 0)} Windows {Windows.Size} }</DisplayString>
60+</Type>
61+
5862 </AutoVisualizer>