Skip to content
Haiku OSDeep Dive Published Updated 7 min readViews unavailable

Haiku BScreen: Display Geometry, Modes, and Safe Screen Access

Inspect Haiku screen identity, geometry, color space, modes, and capture APIs while respecting workspace state and display capability limits.

Haiku’s BScreen is the Interface Kit boundary for reading information about a display and, when appropriate, requesting display changes. It answers questions that are different from a window’s frame: which screen object is being queried, what coordinate rectangle it occupies, what color space is active, and what display modes the graphics stack reports. It also exposes workspace-specific mode calls, monitor/device information, screenshots, desktop colors, brightness, and DPMS operations.

Treat this as an inspection and coordination API, not a shortcut for assuming a modern multi-monitor topology. The current Haiku Book explicitly says that Haiku supports a single display at this time. BScreen has APIs for iterating screen objects and resolving a screen from a window, but those calls do not imply that multiple physical displays are currently supported. Use the public API’s validity and return statuses, and test the actual Haiku revision and graphics driver you ship against.

Select a screen from the operation’s context

The default constructor targets B_MAIN_SCREEN_ID; another constructor accepts a screen_id, and BScreen(BWindow*) chooses the display containing a window. Always call IsValid() before treating the object as a real screen. A window-associated screen is usually the right starting point for positioning a dialog or querying the display relevant to that window. A main-screen object is suitable for system-wide inspection when no window exists.

The class also provides SetToNext() to advance a screen object through the screen list. A defensive enumerator checks the first object and each status instead of assuming a fixed number of screens:

#include <Screen.h>
#include <SupportDefs.h>
#include <stdio.h>

void LogScreens()
{
    BScreen screen(B_MAIN_SCREEN_ID);
    if (!screen.IsValid()) {
        fprintf(stderr, "No valid Haiku screen is available\n");
        return;
    }

    do {
        BRect frame = screen.Frame();
        display_mode mode;
        status_t modeStatus = screen.GetMode(&mode);
        printf("screen=%" B_PRId32 " frame=(%.0f,%.0f)-(%.0f,%.0f) "
            "colorspace=%" B_PRId32 " modeStatus=%" B_PRId32 "\n",
            screen.ID(), frame.left, frame.top, frame.right, frame.bottom,
            static_cast<int32>(screen.ColorSpace()), modeStatus);
    } while (screen.SetToNext() == B_OK);
}

This is a diagnostic sketch; include the appropriate Haiku type definitions and logging policy for your application. The important behavior is that SetToNext() returns a status and IsValid() is not optional. Do not invent monitor count from a desktop’s width or from the number of BScreen objects that a particular driver happens to enumerate.

Interpret geometry in Haiku’s coordinate system

Frame() returns the screen frame in screen coordinates. The API reference’s example for a 1,366 by 768 display is BRect(0, 0, 1365, 767): the right and bottom values are the last included pixel coordinates, not exclusive bounds. Code that treats those values as width and height will be off by one. Prefer BRect operations and the relevant IntegerWidth()/IntegerHeight() methods when you need extents, and be explicit about whether a calculation wants a count of pixels or a maximum coordinate.

A screen frame is not the same thing as a view’s local bounds. A BWindow has a frame in the desktop coordinate system, while a BView draws in its own coordinate system. Use the window’s screen-aware helpers such as CenterOnScreen() or MoveOnScreen() when appropriate rather than applying screen coordinates directly to a child view. For custom placement, obtain the target screen from the window and intersect or clamp the proposed window rectangle against the screen frame before showing it.

This becomes especially important around workspace changes, resolution changes, and restored window frames. Persisted geometry can be outside the current frame after a mode change, and a window may not yet have a stable on-screen location during early construction. Validate the rectangle at the moment you present the window; do not assume that a value saved on another machine, display mode, or Haiku build still fits.

Read mode and color information without changing it

GetMode() fills a display_mode for the current workspace. Its overload accepts a workspace index to query another workspace. ColorSpace() reports the active pixel format, while GetDeviceInfo() and GetMonitorInfo() can fill structures about the graphics adapter and connected monitor when the driver provides that information. These are capability/diagnostic inputs, not a promise that every hardware field is populated or that EDID-derived values are perfect.

GetModeList() allocates a list of modes reported by the graphics card. The caller is responsible for freeing the allocated mode array. More importantly, Haiku’s API reference warns that the monitor may not be able to display every mode returned by that list. A driver-supported timing is not automatically a monitor-supported timing, nor does a resolution entry prove a stable cable, panel, or refresh-rate combination. ProposeMode() can adjust a target to a mode supported by the graphics card, but it is not a substitute for a safe user-visible test and recovery path.

Avoid changing display state merely to probe the API. SetMode() can apply a mode for the current workspace or a named workspace, and makeDefault controls whether the choice becomes the default. A failed or visually unusable mode can leave a user with an inaccessible desktop. For ordinary applications, report current state and direct users to the Screen preferences panel. If a specialized tool must change modes, show the exact target, keep a timed rollback path, and test with the real display hardware before treating success status as proof that the user can see the result.

Haiku exposes screen mode calls that take a workspace index, plus DesktopColor() and SetDesktopColor() overloads that can address workspace-specific backgrounds. This is useful for a settings utility or a diagnostic tool, but the API boundary does not make preferences changes atomic with your own app settings. If your app stores a desired configuration, distinguish that intent from the display server’s currently observed mode and re-read after a workspace transition.

Other methods cover DPMS capability/state, brightness, retrace waiting, color maps, and capture. Check each method’s status or capability before enabling a control. For example, an unsupported DPMS state is not a reason to repeatedly retry a power transition. Do not run WaitForRetrace() on a GUI message loop; a display synchronization wait can stall input and redraw handling. Route measurements or capture work to a bounded worker when it could take noticeable time, and return results to the window through normal messaging.

GetBitmap() allocates a BBitmap containing screen pixels and ReadBitmap() copies pixels into a caller-provided bitmap. Match the bitmap’s bounds and color-space assumptions to the capture operation, check the returned status, and release an allocated bitmap after use. Capturing the whole screen can consume substantial memory; repeated screenshots in a timer can become an allocation and bandwidth problem even when each individual call works. Prefer a requested sub-rectangle when the task only needs a portion of the display, and measure capture time on the target graphics path.

Color values also need context. ColorSpace() tells you the display’s pixel encoding, not the user’s complete color-management intent, physical panel calibration, or how an application should reinterpret every bitmap. Do not treat a color-space enum as a guarantee that a screenshot is colorimetrically accurate. Convert or render through documented drawing APIs and keep color conversion policy explicit.

Failure modes and acceptance checks

An invalid BScreen object, a failed GetMode(), an empty frame, or an error from GetMonitorInfo() means the queried information is unavailable; it does not identify the graphics driver as the cause by itself. Separate display enumeration, mode query, window placement, and rendering into distinct checks. If an application window is off-screen, log the saved frame and live BScreen::Frame() before resetting preferences.

Test on the exact Haiku image and graphics path that matters: virtual machine, VESA/fail-safe mode, accelerated driver, and physical monitor as applicable. Include a small mode, a large mode, a workspace-specific query, a monitor with incomplete identification data, a failed mode query, and a stale saved window rectangle. For capture, compare pixel bounds and expected cursor inclusion; for a mode-changing tool, verify rollback after timeout, user cancellation, and a mode that the card advertises but the monitor cannot display.

Record the Haiku revision, architecture, active driver, screen ID, frame, color space, queried mode, workspace, monitor/device status codes, and whether the test used a VM. That evidence helps distinguish an API misuse from a driver limitation or an unsupported display mode. BScreen is most reliable when applications use it to observe current state, keep coordinate spaces separate, and make state-changing operations explicit and recoverable.

Related:

Sources:

Comments