Skip to content

Window and Displays

shmellyorc edited this page Sep 13, 2026 · 2 revisions

Window & Displays

VOID's public window/display API is platform-neutral.

SDL3 handles the native platform work internally, but normal game code works with VOID types such as:

  • Window
  • DisplayManager
  • DisplayInfo
  • DisplayId
  • DisplayMode
  • WindowCapabilities

Startup Window Settings

var settings = GameSettings.Instance
    .SetWindow(1280, 720)
    .SetViewport(320, 180)
    .SetDisplay(0)
    .SetVsync(true)
    .Build();

SetWindow is the native window size.

SetViewport is the internal render size before presentation/scaling.

Window Scale Modes

GameSettings.Instance.SetWindowScaleMode(
    WindowScaleMode.Fit);

Available modes:

  • Stretch
  • PixelPerfect
  • Fit
  • Fill
  • None

For a low-resolution pixel-art game:

GameSettings.Instance
    .SetWindow(1280, 720)
    .SetViewport(320, 180)
    .SetWindowScaleMode(
        WindowScaleMode.PixelPerfect);

The logical viewport is also the coordinate space used by camera screen/world conversion. Raw mouse positions are window-relative, so keep the presentation scale in mind when using mouse coordinates with a camera.

See Camera → Screen and World Conversion and Input → Mouse.

Runtime Changes

Window setters queue changes.

Call ApplyChanges() when ready:

Game.Instance.Window
    .SetSize(1600, 900)
    .SetTitle("My Game - Level 2")
    .SetVSync(false)
    .ApplyChanges();

Other runtime settings:

Game.Instance.Window
    .SetMode(WindowMode.Borderless)
    .ApplyChanges();

Connected Displays

Get all current displays:

IReadOnlyList<DisplayInfo> displays =
    DisplayManager.GetDisplays();

foreach (var display in displays)
{
    Console.WriteLine(
        $"{display.Index}: {display.Name} " +
        $"{display.CurrentMode} " +
        $"Scale={display.ContentScale:0.##}");
}

Primary display:

DisplayInfo primary =
    DisplayManager.PrimaryDisplay;

By index:

DisplayInfo second =
    DisplayManager.GetDisplay(1);

Stable Display IDs

Display enumeration indices can change when monitors are connected or disconnected.

For a long-lived reference, keep the DisplayId:

DisplayId id =
    DisplayManager.GetDisplay(1).Id;

if (DisplayManager.TryGetDisplay(id, out var display))
{
    Console.WriteLine(display.Name);
}

Move a Window to a Display

At startup:

GameSettings.Instance.SetDisplay(1);

At runtime:

Game.Instance.Window
    .SetDisplay(1)
    .ApplyChanges();

or:

DisplayId id =
    DisplayManager.GetDisplay(1).Id;

Game.Instance.Window
    .SetDisplay(id)
    .ApplyChanges();

Whether the operation is possible depends on the active native backend. See Backend Capabilities.

Desktop Fullscreen

Desktop fullscreen keeps the selected display's current desktop mode:

var settings = GameSettings.Instance
    .SetDisplay(0)
    .SetDesktopFullscreen()
    .Build();

At runtime:

Game.Instance.Window
    .SetDesktopFullscreen()
    .ApplyChanges();

Exclusive Fullscreen

Request a resolution and optional refresh rate:

var settings = GameSettings.Instance
    .SetDisplay(0)
    .SetFullscreenMode(
        1920,
        1080,
        144f)
    .Build();

A refresh rate of 0 lets the platform choose the closest available rate.

At runtime:

Game.Instance.Window
    .SetFullscreenMode(
        1920,
        1080,
        144f)
    .ApplyChanges();

Or select one of the reported modes:

DisplayInfo display =
    DisplayManager.GetDisplay(0);

DisplayMode mode =
    display.SupportedModes[0];

Game.Instance.Window
    .SetFullscreenMode(mode)
    .ApplyChanges();

Window Information

Window window = Game.Instance.Window;

Vect2 windowSize = window.WindowSize;
Vect2 renderSize = window.RenderSize;

WindowMode mode = window.Mode;
bool vsync = window.VSyncEnabled;
bool focused = window.IsFocused;
bool open = window.IsOpen;

DisplayInfo display = window.CurrentDisplay;
int displayIndex = window.DisplayIndex;

Window Events

Game.Instance.Window.OnWindowResized = size =>
{
    Console.WriteLine($"Resized: {size}");
};

Game.Instance.Window.OnFocusGained = () =>
{
    Console.WriteLine("Focus gained");
};

Game.Instance.Window.OnFocusLost = () =>
{
    Console.WriteLine("Focus lost");
};

Game.Instance.Window.OnDisplayChanged = change =>
{
    Console.WriteLine(
        $"{change.Kind}: {change.Display}");
};

Display-wide notifications are also available:

DisplayManager.Changed += change =>
{
    Console.WriteLine(change.Kind);
};

Backend Capabilities

The actual window system matters, especially on Linux.

WindowCapabilities caps =
    Game.Instance.Window.Capabilities;

Console.WriteLine(caps.Backend);
Console.WriteLine(caps.BackendName);
Console.WriteLine(caps.CanPositionWindow);
Console.WriteLine(caps.SupportsDisplayModes);

Useful capability flags include:

  • CanPositionWindow
  • CanSelectWindowedDisplay
  • CanSelectDesktopFullscreenDisplay
  • CanSelectExclusiveFullscreenDisplay
  • SupportsDisplayEnumeration
  • SupportsDisplayModes
  • SupportsContentScale
  • UsesCompositorWindowPlacement

Wayland

Native Wayland generally lets the compositor control placement of ordinary top-level windows.

Do not assume an app can arbitrarily move a normal window from one monitor to another.

If your code depends on display placement, inspect WindowCapabilities rather than assuming the operating system tells the whole story.

Linux Window Backend

VOID's default Linux policy is:

LinuxWindowBackend.X11ThenWayland

It tries X11/XWayland first and falls back to native Wayland.

You can change it:

GameSettings.Instance
    .SetLinuxWindowBackend(
        LinuxWindowBackend.Auto);

or force one:

GameSettings.Instance
    .SetLinuxWindowBackend(
        LinuxWindowBackend.X11);
GameSettings.Instance
    .SetLinuxWindowBackend(
        LinuxWindowBackend.Wayland);

This setting has no effect on Windows or macOS.

A Wayland desktop running VOID through XWayland reports NativeWindowBackend.X11, because that is the backend SDL actually initialized.

Legacy Resolution Helpers

VOID keeps convenience methods for the primary display:

Vect2 desktop =
    Window.GetDesktopResolution();

List<Vect2> modes =
    Window.GetSupportedResolutions();

bool supported =
    Window.IsResolutionSupported(
        1920,
        1080);

For new multi-monitor code, prefer DisplayManager.


Back to Home

Clone this wiki locally