Skip to content

ext_display

The ext_display crate provides display and monitor information for Forge applications through the runtime:display module.

Overview

ext_display handles:

  • Monitor enumeration - List connected displays
  • Display properties - Resolution, scale, bounds
  • Primary display - Identify main monitor
  • Display events - Monitor connect/disconnect
  • Cursor position - Global cursor coordinates

Module: runtime:display

import {
getAll,
getPrimary,
getFromPoint,
getCursorPosition,
onDisplayChange
} from "runtime:display";

Key Types

Error Types

enum DisplayErrorCode {
Generic = 9700,
NotFound = 9701,
QueryFailed = 9702,
}
struct DisplayError {
code: DisplayErrorCode,
message: String,
}

Display Types

struct Display {
id: u32,
name: String,
bounds: Rect,
work_area: Rect,
scale_factor: f64,
is_primary: bool,
rotation: Rotation,
}
struct Rect {
x: i32,
y: i32,
width: u32,
height: u32,
}
enum Rotation {
Rotate0,
Rotate90,
Rotate180,
Rotate270,
}
struct CursorPosition {
x: i32,
y: i32,
display_id: u32,
}
struct DisplayChangeEvent {
kind: DisplayChangeKind,
display: Display,
}
enum DisplayChangeKind {
Added,
Removed,
Changed,
}

Operations

OpTypeScriptDescription
op_display_get_allgetAll()Get all displays
op_display_get_primarygetPrimary()Get primary display
op_display_get_from_pointgetFromPoint(x, y)Get display at point
op_display_get_cursor_positiongetCursorPosition()Get cursor position
op_display_on_changeonDisplayChange(callback)Listen for changes

Usage Examples

Listing Displays

import { getAll, getPrimary } from "runtime:display";
const displays = await getAll();
for (const display of displays) {
console.log(`Display: ${display.name}`);
console.log(` Resolution: ${display.bounds.width}x${display.bounds.height}`);
console.log(` Scale: ${display.scale_factor}x`);
console.log(` Primary: ${display.is_primary}`);
}
const primary = await getPrimary();
console.log(`Primary display: ${primary.name}`);

Display at Point

import { getFromPoint, getCursorPosition } from "runtime:display";
// Get display under cursor
const cursor = await getCursorPosition();
const display = await getFromPoint(cursor.x, cursor.y);
console.log(`Cursor is on display: ${display.name}`);

Listening for Changes

import { onDisplayChange } from "runtime:display";
const unsubscribe = await onDisplayChange((event) => {
switch (event.kind) {
case "Added":
console.log(`Display connected: ${event.display.name}`);
break;
case "Removed":
console.log(`Display disconnected: ${event.display.name}`);
break;
case "Changed":
console.log(`Display changed: ${event.display.name}`);
break;
}
});
// Later: stop listening
unsubscribe();

Window Positioning

import { getPrimary } from "runtime:display";
import { createWindow } from "runtime:window";
const primary = await getPrimary();
// Center window on primary display
const windowWidth = 800;
const windowHeight = 600;
const x = primary.bounds.x + (primary.bounds.width - windowWidth) / 2;
const y = primary.bounds.y + (primary.bounds.height - windowHeight) / 2;
await createWindow({
title: "Centered Window",
x, y,
width: windowWidth,
height: windowHeight
});

Display Properties

PropertyDescription
idUnique display identifier
nameDisplay name/model
boundsFull display bounds (x, y, width, height)
work_areaUsable area (excludes taskbar/dock)
scale_factorDPI scaling (1.0 = 100%, 2.0 = 200%)
is_primaryWhether this is the main display
rotationDisplay rotation (0°, 90°, 180°, 270°)

File Structure

crates/ext_display/
├── src/
│ └── lib.rs # Extension implementation
├── ts/
│ └── init.ts # TypeScript module shim
├── build.rs # forge-weld build configuration
└── Cargo.toml

Rust Implementation

Operations are annotated with forge-weld macros for automatic TypeScript binding generation:

src/lib.rs
use deno_core::{op2, Extension, OpState};
use forge_weld_macro::{weld_op, weld_struct, weld_enum};
use serde::{Deserialize, Serialize};
#[weld_enum]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Rotation {
Rotate0,
Rotate90,
Rotate180,
Rotate270,
}
#[weld_struct]
#[derive(Debug, Serialize)]
pub struct Display {
pub id: u32,
pub name: String,
pub scale_factor: f64,
pub is_primary: bool,
pub rotation: Rotation,
}
#[weld_op(async)]
#[op2(async)]
#[serde]
pub async fn op_display_get_all(
state: Rc<RefCell<OpState>>,
) -> Result<Vec<Display>, DisplayError> {
// implementation
}

Build Configuration

build.rs
use forge_weld::ExtensionBuilder;
fn main() {
ExtensionBuilder::new("runtime_display", "runtime:display")
.ts_path("ts/init.ts")
.ops(&["op_display_get_all", "op_display_get_primary", "op_display_get_from_point", /* ... */])
.generate_sdk_module("sdk")
.use_inventory_types()
.build()
.expect("Failed to build runtime_display extension");
}

Dependencies

DependencyPurpose
deno_coreOp definitions
taoWindow/display management
serdeSerialization
tokioAsync runtime
forge-weldBuild-time code generation
forge-weld-macro#[weld_op], #[weld_struct], #[weld_enum] macros
linkmeCompile-time symbol collection