How to Implement Multi-Viewport Support to Render Dear ImGui Windows on Multiple Monitors
Enable ImGuiConfigFlags_ViewportsEnable in your ImGuiIO configuration, ensure your backend implements the viewport API, and call ImGui::UpdatePlatformWindows() followed by ImGui::RenderPlatformWindowsDefault() after ImGui::Render() each frame to render UI windows on multiple monitors.
Dear ImGui's multi-viewport support allows you to drag windows outside the main application frame onto separate monitors, with each viewport rendering as a native platform window. This feature is built into the core library but requires specific configuration flags and backend support according to the ocornut/imgui source code. Below is the complete implementation guide based on the actual codebase.
Enabling the Viewport Configuration Flag
To activate multi-viewport functionality, you must set the configuration flag before the first frame. The flag is defined in imgui.h within the ImGuiConfigFlags_ enum at lines 1728-1734.
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // enable multi-viewport
Critical: Set this flag before calling ImGui::NewFrame() for the first time. If enabled afterward, the main viewport will not be correctly marked as a platform window, causing initialization failures.
Backend Requirements for Platform Windows
Multi-viewport support requires a backend that implements the Platform Window API. Official backends such as GLFW (imgui_impl_glfw.cpp), SDL2 (imgui_impl_sdl2.cpp), and Win32 (imgui_impl_win32.cpp) provide this implementation.
According to the GLFW backend source, the function ImGui_ImplGlfw_CreateWindow() in backends/imgui_impl_glfw.cpp handles the creation of native windows for secondary viewports. The backend must:
- Create a native window handle (e.g.,
GLFWwindow*) when ImGui requests a new viewport - Store the handle in
ImGuiViewport::PlatformHandleRaw - Implement destruction via the corresponding
DestroyWindowfunction
Verify your backend contains viewport-specific functions; otherwise, the system will silently fall back to single-window mode.
Main Loop Integration
After rendering the main viewport, you must explicitly update and render secondary viewports. The core library marks the main viewport as a platform window in imgui.cpp at line 16120, setting the flags ImGuiViewportFlags_IsPlatformWindow and ImGuiViewportFlags_OwnedByApp.
Add these calls after ImGui::Render():
ImGui::Render(); // render main viewport
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
ImGui::UpdatePlatformWindows(); // create/update secondary viewports
ImGui::RenderPlatformWindowsDefault(); // render all platform windows
}
UpdatePlatformWindows() synchronizes viewport geometry and creates new platform windows when you drag ImGui windows to new monitors. RenderPlatformWindowsDefault() iterates through the ImGuiContext::Viewports vector and renders each viewport's ImDrawData.
Understanding the Viewport Architecture
The viewport system uses several key structures defined in the ImGui headers:
| Component | Source Location | Purpose |
|---|---|---|
ImGuiViewport |
imgui.h (lines 4017-4045) |
Represents a platform window with size, position, DPI scale, and platform handles |
ImGuiContext::Viewports |
imgui_internal.h (lines 2379-2381) |
Vector storing all active viewports (ImVector<ImGuiViewport*>) |
ImGuiWindow::Viewport |
imgui_internal.h |
Pointer linking each ImGui window to its host viewport |
| Platform Interface | Backend files (e.g., imgui_impl_glfw.cpp) |
Functions creating native OS windows for each viewport |
When you drag a window to a new monitor, ImGui detects the monitor change, creates a new ImGuiViewport entry, and requests the backend to create a corresponding native window via the platform interface.
DPI Scaling and Multi-Monitor Considerations
Each viewport maintains its own DPI scale factor. Access this via ImGui::GetWindowViewport()->DpiScale or viewport->DpiScale to ensure UI elements scale correctly on high-DPI monitors.
Common implementation pitfalls to avoid:
- Flag initialization order: Always set
ImGuiConfigFlags_ViewportsEnablebefore the firstNewFrame()call - Missing backend support: Custom backends must implement the full viewport interface (create, destroy, show, set position/size)
- Event forwarding: Ensure your platform's event loop forwards input events (mouse, keyboard, focus) to all viewport windows, not just the main window
Complete Implementation Example (GLFW + OpenGL3)
Below is a minimal working example using the official GLFW and OpenGL3 backends. The same pattern applies to SDL, Vulkan, DirectX, and other supported backends.
// Setup
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // enable multi-viewport
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 130");
// Main loop
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
ImGui_ImplGlfw_NewFrame();
ImGui_ImplOpenGL3_NewFrame();
ImGui::NewFrame();
// UI code
ImGui::Begin("Main Window");
ImGui::Text("Drag this window to another monitor");
ImGui::End();
ImGui::Begin("Secondary Window");
ImGui::Text("This renders on its own platform window");
ImGui::End();
// Rendering
ImGui::Render();
int display_w, display_h;
glfwGetFramebufferSize(window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
// Multi-viewport handling
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
glfwSwapBuffers(window);
}
Summary
- Enable the global flag: Set
ImGuiConfigFlags_ViewportsEnablein yourImGuiIOstruct before the first frame - Use a compatible backend: Verify your platform backend implements
CreateWindow,DestroyWindow, and other viewport functions (official GLFW, SDL, and Win32 backends support this) - Update the render loop: Call
ImGui::UpdatePlatformWindows()andImGui::RenderPlatformWindowsDefault()afterImGui::Render()to handle secondary viewports - Handle DPI per viewport: Query
viewport->DpiScalefor monitor-specific scaling instead of using a global scale factor - Reference key files: The feature implementation spans
imgui.h(definitions),imgui.cpp(viewport flags at line 16120), andimgui_internal.h(viewport vector storage)
Frequently Asked Questions
Why do my windows still appear inside the main application window?
You likely set ImGuiConfigFlags_ViewportsEnable after calling ImGui::NewFrame() for the first time. The flag must be enabled during ImGui initialization, before the first frame begins. Additionally, verify that your backend implements the viewport API functions; if using an older custom backend that lacks these functions, multi-viewport support will silently fail.
Do I need to manually create native windows for each monitor?
No. When you enable the viewport flag and use a supporting backend, Dear ImGui automatically creates and manages native platform windows (via the backend) when you drag ImGui windows outside the main viewport. The ImGui::UpdatePlatformWindows() function handles the lifecycle of these native windows based on viewport visibility.
How do I handle different DPI scales across multiple monitors?
Each ImGuiViewport stores its own DpiScale factor. Query this value via ImGui::GetWindowViewport()->DpiScale or iterate through the viewport list to adjust font sizes or spacing per monitor. The backend typically sets this value when the viewport moves to a monitor with different DPI settings.
Can I use multi-viewport with Vulkan or DirectX instead of OpenGL?
Yes. Multi-viewport support is backend-agnostic regarding the graphics API. You can use it with the official Vulkan (imgui_impl_vulkan.cpp), DirectX 11 (imgui_impl_dx11.cpp), or DirectX 12 backends. The requirement is that the platform backend (GLFW, SDL, or Win32) implements the window management interface, while the renderer backend handles the draw calls for each viewport's ImDrawData.
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 →