How to Implement Multi-Viewport Support in Dear ImGui: A Complete Guide

To implement multi-viewport support in Dear ImGui, enable the ImGuiConfigFlags_ViewportsEnable flag in your ImGuiIO configuration and ensure your platform backend implements the required window creation and event forwarding callbacks.

Dear ImGui's multi-viewport feature allows UI windows to be dragged outside the main application window into separate native OS windows. This article explains the implementation details based on the ocornut/imgui source code, covering configuration flags, internal viewport management, and backend integration requirements.

What Is Multi-Viewport Support?

Multi-viewport support enables Dear ImGui to render interface elements onto multiple native platform windows simultaneously. Internally, each viewport is represented by an ImGuiViewport object that owns a platform-specific window handle—such as an HWND on Windows or an X11/Wayland window on Linux.

When ImGuiConfigFlags_ViewportsEnable is active, ImGui creates a primary viewport that owns the main rendering context, plus additional secondary viewports on demand whenever an ImGui window is dragged outside the main window boundaries.

Enabling the Multi-Viewport Configuration Flag

The first step to implement multi-viewport support in Dear ImGui is setting the configuration flag immediately after creating the ImGui context. According to imgui.h, the ImGuiConfigFlags_ViewportsEnable value is defined in the ImGuiConfigFlags_ enum alongside other behavioral flags.

// After ImGui::CreateContext()
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;  // Enables multi-viewport

This flag signals ImGui to allocate viewport objects and invoke platform-specific backend callbacks during the frame lifecycle. Without this flag set, all rendering remains constrained to the single main window regardless of user interactions.

Internal Viewport Management

Viewport Creation and Storage

In imgui.cpp, the core engine manages viewports through the global context g.Viewports. During the first frame, ImGui automatically allocates the primary viewport using IM_NEW, as implemented around line 4483 in the source. This viewport is stored in the dynamic array g.Viewports and remains persistent for the application's lifetime.

You can retrieve this primary viewport at any time using:

ImGuiViewport* main_viewport = ImGui::GetMainViewport();

The GetMainViewport() function, defined in imgui.cpp near line 16052, returns the first viewport in the array, which corresponds to the main application window.

Dynamic Viewport Association

When a user drags an ImGui window outside the main work area, ImGui automatically creates secondary viewports. The internal function ImGui::SetWindowViewport, referenced around line 16058 in imgui.cpp, binds the floating window to a new ImGuiViewport object and updates the window's position via window->Viewport->Pos.

This process is transparent to user code—windows automatically gain their own OS window handles when dragged beyond the primary viewport boundaries.

Backend Requirements for Multi-Viewport Support

Multi-viewport functionality requires explicit backend support. Each platform backend (Win32, GLFW, SDL, etc.) must implement callbacks for creating, destroying, and managing platform windows for secondary viewports.

Win32 Backend Implementation

The Win32 backend in backends/imgui_impl_win32.cpp contains platform-specific logic for multi-viewport support. As noted in the comments around line 139, the docking branch contains the necessary multi-viewport code for this backend. The backend registers mouse viewport events using io.AddMouseViewportEvent() to route input to the correct viewport window.

GLFW Backend Implementation

Similarly, backends/imgui_impl_glfw.cpp implements the required platform window creation and destruction routines for GLFW-based applications. Both backends follow the same pattern of implementing the ImGuiPlatformIO interface functions that ImGui calls when viewports are created or destroyed.

Rendering Secondary Viewports

When multi-viewport is enabled, the standard render loop requires additional calls to handle secondary windows. During ImGui::Render(), the internal function UpdateViewportsNewFrame() iterates over g.Viewports (including the primary viewport) and prepares draw data for each one, storing viewport ownership in draw_data->OwnerViewport as seen around line 5957 in imgui.cpp.

Your render loop must explicitly update and render platform windows:

// Standard frame preparation
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplWin32_NewFrame();  // Or your specific backend
ImGui::NewFrame();

// ... your UI code ...

// Standard rendering
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

// Multi-viewport specific rendering
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
    ImGui::UpdatePlatformWindows();        // Create/update platform windows
    ImGui::RenderPlatformWindowsDefault(); // Render secondary viewports
}

UpdatePlatformWindows() processes viewport creation, destruction, and position updates, while RenderPlatformWindowsDefault() handles the actual rendering submission for all secondary viewports.

Working with Viewport Objects Programmatically

Accessing Viewport Draw Lists

For advanced rendering scenarios, you can draw directly onto specific viewports using ImGui::GetForegroundDrawList(viewport). This function, defined around lines 5309-5311 in imgui.cpp, accepts an ImGuiViewport* parameter and returns a draw list that renders on top of all windows within that viewport.

ImGuiViewport* viewport = ImGui::GetMainViewport();
ImDrawList* draw_list = ImGui::GetForegroundDrawList(viewport);
draw_list->AddCircle(viewport->GetCenter(), 50.0f, IM_COL32(255, 0, 0, 255));

Creating Custom Viewports

While ImGui creates viewports automatically for dragged windows, you can manually create viewports for specific embedding scenarios:

ImGuiViewport* secondary = ImGui::CreateViewport();
secondary->Pos = ImVec2(800, 100);
secondary->Size = ImVec2(400, 300);
secondary->Flags = ImGuiViewportFlags_NoTaskBarIcon;
secondary->PlatformHandleRaw = (void*)my_native_hwnd;  // Platform-specific handle

As documented in imgui.cpp around lines 660-665, the PlatformHandleRaw field replaces the deprecated ImeWindowHandle field and stores the native window handle for platform-specific operations.

Summary

  • Enable the flag: Set ImGuiConfigFlags_ViewportsEnable in io.ConfigFlags after creating the ImGui context.
  • Backend support: Ensure your platform backend (Win32, GLFW, SDL) implements the viewport management callbacks required for window creation and event forwarding.
  • Render loop: Call ImGui::UpdatePlatformWindows() and ImGui::RenderPlatformWindowsDefault() after your standard render call to process secondary viewports.
  • Internal storage: Viewports are stored in g.Viewports with the primary viewport accessible via ImGui::GetMainViewport().
  • Native handles: Use PlatformHandleRaw in ImGuiViewport structures for advanced platform-specific window embedding.

Frequently Asked Questions

What is the difference between the primary viewport and secondary viewports?

The primary viewport is created automatically during the first frame and corresponds to the main application window that owns the rendering context. Secondary viewports are created dynamically when ImGui windows are dragged outside the primary viewport boundaries, each owning a separate native OS window. According to imgui.cpp, both are stored in the same g.Viewports array but serve different lifecycle roles.

Which backends support multi-viewport functionality?

The official backends in backends/imgui_impl_win32.cpp, backends/imgui_impl_glfw.cpp, and backends/imgui_impl_sdl.cpp support multi-viewport functionality when using the docking branch of Dear ImGui. Each backend implements the ImGuiPlatformIO interface functions for creating, destroying, and managing platform-specific window handles. The Win32 backend specifically notes in its implementation that the docking branch is required for full multi-viewport support.

How do I render content directly onto a specific viewport?

Use ImGui::GetForegroundDrawList(viewport) to obtain a draw list associated with a specific ImGuiViewport pointer. This function, implemented in imgui.cpp, allows you to submit draw commands that render on top of all windows within that viewport. You can retrieve the main viewport using ImGui::GetMainViewport() or iterate through all viewports via the internal context structure.

Why are my windows not creating separate OS windows when dragged?

If windows remain constrained to the main window when dragged, verify that ImGuiConfigFlags_ViewportsEnable is set in io.ConfigFlags before the first ImGui::NewFrame() call. Additionally, confirm that your backend implements the required viewport callbacks and that you are calling ImGui::UpdatePlatformWindows() and ImGui::RenderPlatformWindowsDefault() in your render loop. Missing any of these steps prevents the automatic creation of secondary viewports.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →