The Screen service provides access to display information and control, including brightness, resolution, dark mode, screenshots, and multi-display management. Access it via app.screen.

info = app.screen.get_info()
print(f"Display: {info.name}")
print(f"Resolution: {info.width}x{info.height} @{info.scale}x")

Methods

get_info()

Get information about the current display, including brightness, dimensions, refresh rate, color space, and native resolution.

app.screen.get_info() -> ScreenInfo

Returns a ScreenInfo dataclass.

list_displays()

List all connected displays with their properties.

app.screen.list_displays() -> list[dict]

Returns a list of dictionaries, each containing:

Key Type Description
index int Display index
displayID int System display ID
name str Display name (e.g., "Built-in Retina Display")
width float Resolution width in points
height float Resolution height in points
scale float Scale factor (e.g., 2.0 for Retina)
isMain bool Whether this is the main display
isBuiltin bool Whether this is the built-in display
refreshRate float Refresh rate in Hz
colorSpace str Color space name

set_brightness(brightness)

Set the screen brightness. Only works on built-in displays.

app.screen.set_brightness(brightness: float) -> bool
Parameter Type Description
brightness float Brightness level from 0.0 (darkest) to 1.0 (brightest). Values are clamped to this range.

Returns True if brightness was set successfully.

set_resolution(width, height)

Change the screen resolution. The target resolution must be one of the available modes from get_info().available_resolutions.

app.screen.set_resolution(width: int, height: int) -> bool
Parameter Type Description
width int Target width in points
height int Target height in points

Returns True if the resolution was changed successfully.

get_dark_mode()

Get the current dark mode status.

app.screen.get_dark_mode() -> DarkModeInfo

Returns a DarkModeInfo dataclass.

set_dark_mode(enabled)

Toggle system dark mode. Requires automation permission for System Events.

app.screen.set_dark_mode(enabled: bool) -> bool
Parameter Type Description
enabled bool True for dark mode, False for light mode

Returns True if the change was applied successfully.

get_color_profile()

Get the current color profile information.

app.screen.get_color_profile() -> ColorProfileInfo

Returns a ColorProfileInfo dataclass.

screenshot(display_id, x, y, width, height)

Capture a screenshot of the full screen or a specified region. Requires screen recording permission.

app.screen.screenshot(
    display_id: int | None = None,
    x: float | None = None,
    y: float | None = None,
    width: float | None = None,
    height: float | None = None,
) -> ScreenshotResult
Parameter Type Default Description
display_id int \| None None Specific display ID. Uses the main display if None
x float \| None None X origin of the capture region
y float \| None None Y origin of the capture region
width float \| None None Width of the capture region
height float \| None None Height of the capture region

All four region parameters (x, y, width, height) must be provided together or omitted entirely for a full-screen capture.

Returns a ScreenshotResult dataclass.


Data Classes

ScreenInfo

Display information returned by get_info().

Property Type Description
brightness float \| None Current brightness level (0.0--1.0). None if unavailable
is_builtin bool Whether this is the built-in display
width float Screen width in points
height float Screen height in points
scale float Display scale factor (e.g., 2.0 for Retina)
visible_width float \| None Visible width excluding dock and menu bar
visible_height float \| None Visible height excluding dock and menu bar
display_id int \| None System display identifier
name str \| None Display name (e.g., "Built-in Retina Display")
refresh_rate float \| None Display refresh rate in Hz
native_width int \| None Native pixel width
native_height int \| None Native pixel height
color_space str \| None Color space name
color_depth int \| None Bits per pixel
available_resolutions list[dict] List of available display modes

DarkModeInfo

Dark mode information returned by get_dark_mode().

Property Type Description
is_dark_mode bool Whether dark mode is currently enabled
appearance_name str \| None Full appearance name (e.g., "NSAppearanceNameDarkAqua")

ColorProfileInfo

Color profile information returned by get_color_profile().

Property Type Description
color_space_name str \| None Color space name
color_component_count int \| None Number of color components
icc_profile_size int \| None Size of ICC profile in bytes

ScreenshotResult

Screenshot result returned by screenshot().

Property Type Description
success bool Whether the screenshot was captured successfully
image_data bytes \| None Raw PNG image data
width int \| None Image width in pixels
height int \| None Image height in pixels

ScreenshotResult.save(path)

Save the screenshot to a file.

result.save(path: str) -> bool
Parameter Type Description
path str File path to save to (should end in .png)

Returns True if saved successfully, False if the screenshot was not captured or an I/O error occurred.


Examples

Display information dashboard

import nib

def main(app: nib.App):
    app.title = "Display"
    app.icon = nib.SFSymbol("display")
    app.width = 320
    app.height = 250

    name_text = nib.Text("--", font=nib.Font.HEADLINE)
    res_text = nib.Text("--", foreground_color=nib.Color.SECONDARY)
    brightness_text = nib.Text("--", foreground_color=nib.Color.SECONDARY)
    refresh_text = nib.Text("--", foreground_color=nib.Color.SECONDARY)

    def refresh():
        info = app.screen.get_info()
        name_text.content = info.name or "Display"
        res_text.content = f"{info.width:.0f} x {info.height:.0f} @{info.scale:.0f}x"
        brightness_text.content = (
            f"Brightness: {info.brightness * 100:.0f}%"
            if info.brightness is not None
            else "Brightness: N/A"
        )
        refresh_text.content = (
            f"Refresh rate: {info.refresh_rate:.0f} Hz"
            if info.refresh_rate
            else "Refresh rate: N/A"
        )

    app.on_appear = refresh

    app.build(
        nib.VStack(
            controls=[name_text, res_text, brightness_text, refresh_text],
            spacing=8,
            padding=20,
        )
    )

nib.run(main)

Brightness slider

import nib

def main(app: nib.App):
    app.title = "Brightness"
    app.icon = nib.SFSymbol("sun.max")
    app.width = 300
    app.height = 120

    label = nib.Text("50%")

    def on_change(value):
        app.screen.set_brightness(value / 100)
        label.content = f"{value:.0f}%"

    def load_current():
        info = app.screen.get_info()
        if info.brightness is not None:
            label.content = f"{info.brightness * 100:.0f}%"

    app.on_appear = load_current

    app.build(
        nib.VStack(
            controls=[
                label,
                nib.Slider(value=50, min_value=0, max_value=100, on_change=on_change),
            ],
            spacing=12,
            padding=20,
        )
    )

nib.run(main)

Dark mode toggle

import nib

def main(app: nib.App):
    app.title = "Appearance"
    app.icon = nib.SFSymbol("moon.fill")
    app.width = 280
    app.height = 100

    mode_text = nib.Text("--", font=nib.Font.HEADLINE)

    def refresh():
        info = app.screen.get_dark_mode()
        mode_text.content = "Dark Mode" if info.is_dark_mode else "Light Mode"

    def toggle():
        info = app.screen.get_dark_mode()
        app.screen.set_dark_mode(not info.is_dark_mode)
        refresh()

    app.on_appear = refresh

    app.build(
        nib.VStack(
            controls=[
                mode_text,
                nib.Button("Toggle", action=toggle, style=nib.ButtonStyle.BORDERED),
            ],
            spacing=12,
            padding=20,
        )
    )

nib.run(main)

Take a screenshot

import nib

def main(app: nib.App):
    app.title = "Screenshot"
    app.icon = nib.SFSymbol("camera.viewfinder")
    app.width = 300
    app.height = 120

    status = nib.Text("Ready", foreground_color=nib.Color.SECONDARY)

    def capture():
        result = app.screen.screenshot()
        if result.success:
            saved = result.save("/tmp/nib_screenshot.png")
            if saved:
                status.content = f"Saved {result.width}x{result.height} screenshot"
            else:
                status.content = "Failed to save screenshot"
        else:
            status.content = "Screenshot capture failed"

    app.build(
        nib.VStack(
            controls=[
                nib.Button("Capture Screenshot", action=capture),
                status,
            ],
            spacing=12,
            padding=20,
        )
    )

nib.run(main)