How to Enable and Implement Multi-Viewport Support for Secondary ImGui Windows
Enable multi-viewport support in Dear ImGui by setting the ImGuiConfigFlags_ViewportsEnable flag in ImGuiIO::ConfigFlags, then ensure your main loop calls ImGui::UpdatePlatformWindows() and ImGui::RenderPlatformWindowsDefault() after rendering the primary viewport.
The multi-viewport feature in the ocornut/imgui repository allows secondary ImGui windows to break out of the main application frame and become independent native OS windows. This capability requires coordination between the core ImGui context defined in imgui.h, platform-specific backend implementations in the backends/ directory, and your rendering loop. When properly configured, you can drag any ImGui window outside the main viewport to automatically spawn a separate native window that can be moved, resized, and layered independently.
Understanding Multi-Viewport Architecture
Multi-viewport support spans three distinct layers in the ImGui architecture. Understanding these layers clarifies why specific configuration steps are necessary for secondary windows to function as independent OS windows.
Configuration Layer
At the highest level, the ImGuiIO structure controls global behavior through bit flags. The system checks io.ConfigFlags for ImGuiConfigFlags_ViewportsEnable to determine whether to instantiate the viewport subsystem. This flag is defined in imgui.h alongside other configuration options.
Platform Abstraction Layer
When viewports are enabled, ImGui delegates window management to the ImGuiPlatformIO interface. This abstraction layer contains function pointers for native window operations. The official backends in backends/imgui_impl_win32.cpp, backends/imgui_impl_glfw.cpp, and backends/imgui_impl_sdl2.cpp provide concrete implementations for these callbacks.
Rendering Infrastructure
Each viewport maintains its own ImDrawData instance. The rendering backend must support drawing from arbitrary draw lists, not just the main viewport's data. The official rendering backends like backends/imgui_impl_opengl3.cpp and backends/imgui_impl_vulkan.cpp handle this automatically by iterating over all active viewports.
Enabling the Viewports Feature
Activation requires a single line of code during initialization. After creating the ImGui context, access the IO structure and set the configuration flag:
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
This modification must occur before the first call to ImGui::NewFrame(). Once enabled, ImGui treats every ImGui::Begin()/ImGui::End() block as a potential candidate for externalization when dragged beyond the main window boundaries.
Platform Backend Requirements
For secondary viewports to materialize as OS windows, the platform backend must implement the PlatformIO callbacks. The ImGuiPlatformIO structure, accessible via ImGui::GetPlatformIO(), requires the following function pointers:
- Platform_CreateWindow / Platform_DestroyWindow: Native window lifecycle management
- Platform_GetWindowPos / Platform_SetWindowPos: Position queries and updates
- Platform_GetWindowSize / Platform_SetWindowSize: Dimension handling
- Platform_SetWindowFocus / Platform_GetWindowFocus: Focus state management
- Platform_GetWindowMinimized: Minimization state detection
- Platform_SetWindowTitle / Platform_GetWindowTitle: Text updates
- Platform_SetWindowAlpha: Optional opacity control
The Win32 backend in backends/imgui_impl_win32.cpp demonstrates a complete implementation using CreateWindowEx, SetWindowPos, and related Win32 APIs. Similarly, backends/imgui_impl_glfw.cpp maps these callbacks to GLFW window functions, while backends/imgui_impl_sdl2.cpp uses SDL2 window management routines.
Rendering Backend Integration
Platform backends handle window creation, but the rendering backend must actually draw the content. When ImGuiConfigFlags_ViewportsEnable is active, your main loop requires additional steps after the standard render call.
The canonical rendering pattern looks like this:
while (!glfwWindowShouldClose(main_window))
{
// Start frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// Build UI
ImGui::Begin("Draggable Window");
ImGui::Text("Drag me outside the main window");
ImGui::End();
// Render main viewport
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
// Handle secondary viewports
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
ImGui::UpdatePlatformWindows(); // Create/destroy OS windows
ImGui::RenderPlatformWindowsDefault(); // Render each viewport
}
glfwSwapBuffers(main_window);
glfwPollEvents();
}
The UpdatePlatformWindows() function, implemented in imgui.cpp, iterates over viewports and invokes the PlatformIO callbacks to synchronize native window states. RenderPlatformWindowsDefault() then calls the rendering backend for each secondary viewport's draw data.
Implementation Examples
Win32 and OpenGL 3 Setup
For Windows applications using OpenGL, initialize both the platform and renderer support:
// Initialization
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
ImGui_ImplWin32_Init(hwnd);
ImGui_ImplOpenGL3_Init("#version 150");
// Main loop
while (running)
{
MSG msg;
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
ImGui::ShowDemoWindow();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
SwapBuffers(hDC);
}
SDL2 and OpenGL 3 Setup
SDL2 follows an identical pattern with different initialization calls:
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
ImGui_ImplOpenGL3_Init("#version 150");
// Per-frame
ImGui_ImplSDL2_NewFrame(window);
ImGui_ImplOpenGL3_NewFrame();
ImGui::NewFrame();
// ... UI code ...
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
Custom Platform Backend Skeleton
When writing a custom backend for an unsupported platform, populate the PlatformIO structure:
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.Platform_CreateWindow = [](ImGuiViewport* vp) {
// Create native window using OS API
};
platform_io.Platform_DestroyWindow = [](ImGuiViewport* vp) {
// Destroy native window
};
platform_io.Platform_SetWindowPos = [](ImGuiViewport* vp, ImVec2 pos) {
// Set native window position
};
platform_io.Platform_GetWindowPos = [](ImGuiViewport* vp) {
// Return current position
};
// ... implement remaining callbacks ...
Common Pitfalls
Several issues commonly prevent multi-viewport from functioning correctly:
Missing Callbacks. If the platform backend omits required PlatformIO functions, ImGui logs warnings to the console and secondary viewports fail to appear. Verify all function pointers are assigned in ImGui::GetPlatformIO().
DPI Scaling Errors. On high-DPI displays, Platform_GetWindowPos and Platform_GetWindowSize must return values in pixels, not logical coordinates. Mismatched units cause viewports to appear at incorrect positions or scales.
Input Routing. Secondary viewports require event forwarding. The official backends automatically route mouse and keyboard events from all OS windows to ImGui, but custom implementations must manually call ImGui::GetIO().AddMousePosEvent() and equivalent functions for each viewport.
Context Management. OpenGL backends using multiple contexts require careful handling of Platform_RenderWindow and Platform_SwapBuffers callbacks. The default implementation in imgui_impl_opengl3.cpp manages context activation automatically, but custom renderers may need explicit glMakeCurrent calls.
Summary
- Enable multi-viewport by setting
ImGuiConfigFlags_ViewportsEnableinImGuiIO::ConfigFlagsimmediately after context creation - Ensure your platform backend implements all required
ImGuiPlatformIOcallbacks (create, destroy, move, resize native windows) - Add
UpdatePlatformWindows()andRenderPlatformWindowsDefault()calls to the end of your main render loop - Official backends in
backends/imgui_impl_win32.cpp,backends/imgui_impl_glfw.cpp, andbackends/imgui_impl_sdl2.cppprovide complete reference implementations - Each viewport generates independent
ImDrawDatathat your renderer must support drawing
Frequently Asked Questions
Why do secondary viewports not appear when I drag windows outside the main area?
Check that ImGuiConfigFlags_ViewportsEnable is actually set in the ConfigFlags before the first NewFrame() call. Also verify your platform backend implements all required ImGuiPlatformIO callbacks. Missing callbacks generate warning messages in the standard error output explaining which function is undefined.
Do I need a special version of Dear ImGui to use multi-viewport?
Multi-viewport support is available in the master branch of the ocornut/imgui repository. Earlier versions required the separate docking branch, but since docking merged into master, the feature is standard. Ensure you use a recent version that includes the ImGuiPlatformIO structure in imgui.h.
Can I use multi-viewport with my custom renderer?
Yes, provided your rendering code can accept and draw any ImDrawData instance, not just the main viewport's data. You must implement the PlatformIO callbacks for window management on your target OS, or use an existing platform backend while providing only the custom renderer. The rendering loop must call RenderPlatformWindowsDefault() to process secondary viewports.
How does input handling work for secondary viewports?
The platform backend is responsible for routing input events from all native windows to ImGui. In backends/imgui_impl_glfw.cpp and backends/imgui_impl_win32.cpp, event handlers iterate over all viewports and translate OS events into ImGui's internal event queue using functions like AddMousePosEvent() and AddKeyEvent(). If writing a custom backend, ensure your window procedure or event loop handles messages for all created viewport windows, not just the main application window.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →