Skip to content

SD: Multi Monitor Support

Lukas Dürrenberger edited this page May 19, 2024 · 16 revisions

Current Situation

SFML 1 & 2 don't provide any API to the user to infer monitor information nor any way to define on which monitor to open a window on.

Currently, SFML will always use the default monitor, which is usually the primary monitor.

sf::VideoMode serves multiple purposes:

  • Querying desktop (getDesktopMode) and fullscreen resolutions (getFullscreenModes) of the "default" monitor
  • Hold a fullscreen resolution (for fullscreen windows) or window size (for non-fullscreen windows)
  • Hold a color bit depth (bitsPerPixel)

Target Situation

Overview

Multi-Monitor

Looking at the bigger picture you have three objects interacting with each other:

  • Monitor / Display (These terms are used interchangeably on this wiki page to refer to the same concept)
  • Window
  • Context

A monitor can provide information about its available/supported resolutions, be it for fullscreen or desktop modes. It's also the one that has a specific color bit depth set.

A window can have a size either in a floating of fullscreen state. It can also have other states (minimized, maximized), as well as different styling (only relevant in floating state).

A context (usually OpenGL context) will have a size, which in most cases will match the window's size, and a color bit depth, which in most cases will match the monitor's color bit depth.

Use Cases

Primary

  • Create a window on a specific monitor
  • Provide a sensible default monitor for most users
  • Retrieve a list of available monitors
  • Retrieve the primary (or default) monitor
  • Retrieve supported resolutions for a specific monitor
  • Retrieve the active resolution of a selected monitor
  • Retrieve the monitor a window is currently on
  • Retrieve the active bit depth of a selected monitor

Secondary

  • Retrieve the refresh rates for a specific monitor
  • Retrieve the active refresh rate of a selected monitor
  • Change the refresh rate of a monitor

Tertiary

  • Retrieve the relative relation of the monitors to each other
  • Retrieve the active color format of a selected monitor

API

Given below is a proposed API architecture, some details unrelated to Monitor support were ommitted. display_architecture drawio

List of Breaking Changes from API 2.x

This Chapter contains only the necessary breaking changes in the API compared to 2.x. Everything that is not in this list, can be added at a later time in the 3.x lifecycle.

VideoMode::getDesktopMode()/VideoMode::getFullscreenModes() -> auto display = Display::getDefaultDisplay(); display.getDesktopMode():

  • Currently these functions make the assumption that you are only interested in the default monitor. It is not possible to get this information about other monitors.
  • The VideoModes are very much linked to the monitor they are being requested from, and it is not a good idea to add an overload VideoMode::getDesktopMode(Display display = Display::Default) as this would encourage writing deceptive code. For this reason, it is better to outright remove the 2.x functions and replace them with something else.

Window::Window():

  • This constructor needs to be made aware of what monitor to spawn the fullscreen window on.
  • This constructor should be made aware of what position to spawn the windowed window on.
  • Rather than pile on even more arguments that are conditionally useless depending on the fullscreen/windowed switch, this is a good opportunity to address this now.

Rationale

WindowState separated from fullscreen/windowed:

Different platforms support different combinations of FullscreenState x WindowState: For example on windows you can minimize a fullscreen window just like a windowed window, on macos you cannot.

platform-independent Display class vs platform-independent DisplayIndex type:

  • Index would require querying and sorting all the displays upon every usage of a display. This is somewhat wasteful compared to a direct Display class, but low impact overall due to infrequent usage of the monitor API.
  • DisplayIndex lends itself slightly better to functions with default parameters, while a Display class is more explicit.
    • However default displayparameter should not be overused. Window(display = default_display) is okay, VideoMode::getDesktopMode(display = default_display) is not because the VideoMode concept does not make any sense outside of the context of a specific monitor. Therefore, Display::getDesktopMode() is the better option in this case.

Naming

There are 2 hard problems in computer science: cache invalidation, naming things, and off-by-1 errors.
-- Leon Bambrick

Monitor / Display / Screen

I think there's a good argument to be had, why monitor is too specific, given that it mostly refers to a device purpose build to the PC. While display is much more generic in anything that can display something (monitor, phone screen, tv, etc.), while still representing a complete displaying device. A screen limits itself to just the displaying surface and doesn't represent the specific device itself, as such I feel it's unfit, since certain properties aren't direct properties of the physical surface itself. Then there could be a generic term like VideoDevice, which might be technically correct, but not something anyone would really use when talking about a monitor or display, plus it most likely will cause confusion with people thinking it's about video playback.

Library/API Term Used
GLFW Monitor
SDL Display
X11 Screen/Display
macOS Display
Windows API Monitor / Display

Personally, I'm leaning more towards Display, but it feels like Monitor is also a perfectly valid naming.

Primary / Default / Main

OS Term Used
Windows Primary
macOS Main display
Linux Primary
Clone this wiki locally