# Multi-Viewport#

• https://greich.com/2019/03/02/imgui-multiple-viewports/

• https://github.com/ocornut/imgui/issues/1542#issuecomment-595852032

• Viewports Added ImGui::GetMainViewport() as a way to get the bounds and work area of the host display. (#3789, #1542)

• In master branch or without multi-viewports feature enabled:

• GetMainViewport()->Pos is always == (0,0)
• GetMainViewport()->Size is always == io.DisplaySize
• In docking branch and with the multi-viewports feature enabled:
• GetMainViewport() will return information from your host Platform Window.
• In the future, we will support a “no main viewport” mode and this may return bounds of your main monitor.
• For forward compatibility with multi-viewports/multi-monitors:
• Code using (0,0) as a way to signify “upper-left of the host window” should use GetMainViewport()->Pos.
• Code using io.DisplaySize as a way to signify “size of the host window” should use GetMainViewport()->Size.
• We are also exposing a work area in ImGuiViewport (WorkPos, WorkSize vs Pos, Size for full area):
• For a Platform Window, the work area is generally the full area minus space used by menu-bars.
• For a Platform Monitor, the work area is generally the full area minus space used by task-bars.
• All of this has been the case in ‘docking’ branch for a long time. What we’ve done is merely merging a small chunk of the multi-viewport logic into ‘master’ to standardize some concepts ahead of time.

## Enabling Multi-Viewports#

• Steps to use multi-viewports in your application, when using a default backend from the examples/ folder:

• Application: Enable feature with io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable.

• Backend: The backend initialization will setup all necessary ImGuiPlatformIO’s functions and update monitors info every frame.
• Application: In your main loop, call ImGui::UpdatePlatformWindows(), ImGui::RenderPlatformWindowsDefault() after EndFrame() or Render().
• Application: Fix absolute coordinates used in ImGui::SetWindowPos() or ImGui::SetNextWindowPos() calls.
• Steps to use multi-viewports in your application, when using a custom backend:

• Important: THIS IS NOT EASY TO DO and comes with many subtleties not described here!

• It’s also an experimental feature, so some of the requirements may evolve.
• Consider using default backends if you can. Either way, carefully follow and refer to examples/ backends for details.
• Application: Enable feature with io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable.
• Backend: Hook ImGuiPlatformIO’s Platform_* and Renderer_* callbacks (see below).
• Set io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports and io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports.
• Update ImGuiPlatformIO’s Monitors list every frame.
• Update MousePos every frame, in absolute coordinates.
• Application: In your main loop, call ImGui::UpdatePlatformWindows(), ImGui::RenderPlatformWindowsDefault() after EndFrame() or Render().
• You may skip calling RenderPlatformWindowsDefault() if its API is not convenient for your needs. Read comments below.
• Application: Fix absolute coordinates used in ImGui::SetWindowPos() or ImGui::SetNextWindowPos() calls.

### Details#

• ImGui::RenderPlatformWindowsDefault():

• This function is a mostly a helper for the common-most cases, and to facilitate using default backends. You can check its simple source code to understand what it does.

• It basically iterates secondary viewports and call 4 functions that are setup in ImGuiPlatformIO, if available: Platform_RenderWindow(), Renderer_RenderWindow(), Platform_SwapBuffers(), Renderer_SwapBuffers()
• Those functions pointers exists only for the benefit of RenderPlatformWindowsDefault()
• If you have very specific rendering needs (e.g. flipping multiple swap-chain simultaneously, unusual sync/threading issues, etc.), you can ignore RenderPlatformWindowsDefault() and write customized code to perform your rendering
• You can decide to setup the platform_io’s *RenderWindow and *SwapBuffers pointers and call your functions through those pointers,
• You cay decide to never setup those pointers and call your code directly.
• They are a convenience, not an obligatory interface.
• IMPORTANT: When multi-viewports are enabled (with io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable), all coordinates/positions will be in your natural OS coordinates space. It means that:

• Reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are probably not what you want anymore. Use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos).

• Likewise io.MousePos and GetMousePos() will use OS coordinates. If you query mouse positions to interact with non-imgui coordinates you will need to offset them. e.g. subtract GetWindowViewport()->Pos.
• Render function: the ImDrawData structure now contains DisplayPos and DisplaySize fields. To support multi-viewport, you need to use those values when creating your orthographic projection matrix. Use draw_data->DisplaySize instead of io.DisplaySize, and draw_data->DisplayPos instead of (0,0) as the upper-left point. You need to subtract draw_data->DisplayPos from your scissor rectangles to convert them from global coordinates to frame-buffer coordinates.

• IO: Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api.

• IO: Removed io.DisplayVisibleMin, io.DisplayVisibleMax settings (they were marked obsoleted, used to clip within the (0,0)..(DisplaySize) range).

Last update: September 24, 2021