Haiku BWindowScreen: Display Ownership, Callbacks, and Safe Fallbacks
Treat BWindowScreen as a display-mode lifecycle, not a framebuffer pointer: check construction, gate rendering on connection, and honor driver limits.
BScreen is the right starting point when an application only needs display geometry or an available mode; its API exposes frame, color space, and supported mode queries. BWindowScreen is a more involved Game Kit class: it is a specialized BWindow that requests a screen mode and receives callbacks as the application becomes connected to or disconnected from the display. That lifecycle is the core of using it safely. A window can be hidden, moved out of the active workspace, or quit; code that assumes its rendering path remains connected through those transitions can keep using stale display state. See the Haiku BScreen API for the passive query and mode interface.
Construction is a request, not proof of framebuffer support
The constructor takes a requested screen-space value and an output status_t*. Check that status before proceeding. Haiku’s implementation first constructs the BWindow base as a borderless, non-movable screen window; the BWindowScreen constructor body then calls _InitData() to initialize its display-mode data. In an application, select a mode that is appropriate for the hardware and retain an ordinary-window path if construction fails:
status_t error = B_ERROR;
BWindowScreen* screen = new BWindowScreen("Demo", requestedSpace, &error);
if (error != B_OK) {
delete screen;
screen = nullptr;
// Keep the normal BWindow renderer available instead.
}
requestedSpace is intentionally supplied by the application; this fragment does not assume a particular mode is supported. The official BWindowScreen header exposes ScreenConnected, ScreenChanged, CanControlFrameBuffer, SetFrameBuffer, and MoveDisplayArea. Those methods describe capabilities and transitions, not a guarantee that every graphics driver can perform every operation.
Make the connection callback your rendering gate
Override ScreenConnected(bool active) and treat active as the point at which screen-specific work may begin or must stop. In the Haiku implementation, activation sets up the accelerant hooks and asserts the requested display mode before calling ScreenConnected(true). Deactivation calls ScreenConnected(false) before it restores the original display mode and releases the screen lock. The API header provides the callback contract; the Kit implementation shows the ordering.
void
DemoScreen::ScreenConnected(bool active)
{
if (!active) {
StopFrameProducerAndReleaseDisplayState();
return;
}
if (!CanControlFrameBuffer()) {
UseOrdinaryWindowRendering();
return;
}
StartFrameProducer();
}
The names in this callback are application hooks, not Haiku methods. Stop the worker and wait for it to exit before returning only if it can stop without acquiring the looper or a lock held through this callback; otherwise signal it and complete teardown through a nonblocking, serialized handoff to avoid deadlock. Restart only after a later active == true. Do not let one thread keep dereferencing a saved framebuffer description while another thread processes a disconnect. If a usable framebuffer path is unavailable, route rendering through an ordinary view/window or disable the feature; do not turn a failed capability check into a raw-memory fallback.
CanControlFrameBuffer() is a narrow capability check: the implementation returns whether the graphics-card flags include B_FRAME_BUFFER_CONTROL. It does not promise a particular pixel format, stride, or mode. Likewise, SetFrameBuffer(width, height) puts the requested dimensions into a candidate mode and asks Haiku to propose and assert it; a larger requested virtual surface is not guaranteed to be accepted. MoveDisplayArea(x, y) can fail if the corresponding accelerant hook is missing or fails. Check every returned status_t; retain the mode and rendering path that worked before the request if an operation fails. The relevant checks are visible in the implementation of CanControlFrameBuffer, SetFrameBuffer, and MoveDisplayArea.
Hide, workspace changes, and quit are real transitions
The implementation makes Hide() disconnect before calling the base BWindow::Hide(). Quit() also calls Disconnect() before the base quit path. Show() delegates to BWindow::Show(); it is not itself a synchronous guarantee that ScreenConnected(true) has already run. Workspace activation and window activation can also participate in connection setup or teardown. Therefore, do not set a permanent screenReady = true immediately after calling Show(), and do not assume that hiding merely pauses drawing while preserving an active screen lease.
Keep the recovery logic simple: stop display workers on the false callback; rebuild any mode-dependent state after the true callback; handle ScreenChanged as an additional geometry/depth change; and retain a non-BWindowScreen route for systems where the request or framebuffer feature is unavailable. For tasks that only need bounds, color space, or mode enumeration, BScreen avoids taking on this display-control lifecycle. For a window-scoped direct-rendering path, compare the separate BDirectWindow buffer lifecycle rather than treating the two classes as interchangeable.
Related:
- Haiku BScreen: Display Geometry, Modes, and Safe Screen Access
- Haiku BDirectWindow: Framebuffer Access and Buffer Lifecycle
Sources: