Skip to content
Portal Control Protocol

Surface

A Surface represents a top-level window or popup in the compositor’s surface tree. Each surface is owned by exactly one Application. The Surface primitive carries the window’s geometry, type, workspace assignment, output mapping, and compositor state flags.

When the compositor creates a surface (an application maps a new window), a Surface primitive appears. When the surface is destroyed (the window closes), the primitive is removed.

{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Surface",
"type": "object",
"required": ["id", "app_id", "title", "surface_type", "geometry", "state"],
"properties": {
"id": {
"type": "string",
"pattern": "^surf:[a-z0-9-]+$",
"description": "Unique surface identifier. Stable while the surface exists."
},
"app_id": {
"type": "string",
"description": "Parent application ID."
},
"title": {
"type": "string",
"description": "Window title from xdg-shell or application."
},
"surface_type": {
"type": "string",
"enum": ["toplevel", "popup", "tooltip", "menu", "dialog", "subsurface", "layer_shell", "xdg_shell"],
"description": "Surface type from the Wayland protocol."
},
"geometry": {
"type": "object",
"required": ["x", "y", "w", "h"],
"properties": {
"x": { "type": "integer" },
"y": { "type": "integer" },
"w": { "type": "integer", "minimum": 1 },
"h": { "type": "integer", "minimum": 1 }
},
"description": "Current geometry in compositor coordinates."
},
"workspace": {
"type": ["string", "null"],
"description": "Workspace ID this surface is on. null if on all workspaces (sticky)."
},
"output": {
"type": ["string", "null"],
"description": "Output ID this surface is displayed on."
},
"state": {
"type": "object",
"properties": {
"focused": { "type": "boolean" },
"activated": { "type": "boolean" },
"minimized": { "type": "boolean" },
"fullscreen": { "type": "boolean" },
"tiled": {
"type": ["string", "null"],
"enum": [null, "left", "right", "top", "bottom", "top-left", "top-right", "bottom-left", "bottom-right"]
},
"maximized": { "type": "boolean" },
"occluded": { "type": "boolean" },
"floating": { "type": "boolean" }
}
},
"atspi2_root": {
"type": ["string", "null"],
"description": "Root element ID of the AT-SPI2 accessibility tree for this surface. null if no AT-SPI2 support."
},
"parent_surface": {
"type": ["string", "null"],
"description": "Parent surface ID for popups/dialogs. null for toplevels."
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Surface {
pub id: SurfaceId,
pub app_id: AppId,
pub title: String,
pub surface_type: SurfaceType,
pub geometry: Geometry,
pub workspace: Option<WorkspaceId>,
pub output: Option<OutputId>,
pub state: SurfaceState,
pub atspi2_root: Option<ElementId>,
pub parent_surface: Option<SurfaceId>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct SurfaceId(pub String);
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum SurfaceType {
Toplevel,
Popup,
Tooltip,
Menu,
Dialog,
Subsurface,
LayerShell,
XdgShell,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Geometry {
pub x: i32,
pub y: i32,
pub w: u32,
pub h: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SurfaceState {
pub focused: bool,
pub activated: bool,
pub minimized: bool,
pub fullscreen: bool,
pub tiled: Option<TileEdge>,
pub maximized: bool,
pub occluded: bool,
pub floating: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum TileEdge {
Left,
Right,
Top,
Bottom,
TopLeft,
TopRight,
BottomLeft,
BottomRight,
}

Format surf:{app_client}-{window_index}. Stable while the surface exists. If the window is destroyed and recreated, it gets a new ID.

Mirrors the Wayland protocol surface roles. The most common type is toplevel (a regular application window). Other types include popups, menus, dialogs, tooltips, layer shell surfaces (panels, notifications), and generic xdg-shell surfaces.

Position and size in compositor logical coordinates. The w and h fields have a minimum of 1. Coordinates are relative to the output origin, not the workspace.

The compositor maintains these flags in real time. Several flags can be true simultaneously. For example, a surface can be activated and maximized at the same time.

Flag Meaning
focused This surface currently holds keyboard focus.
activated The surface is the active window of its application (may not have keyboard focus).
minimized The surface is minimized to a taskbar or equivalent.
fullscreen The surface covers the entire output.
tiled The surface is snapped to one or two edges. Null when not tiled.
maximized The surface is maximized within its output.
occluded The surface is fully hidden behind other surfaces.
floating The surface is in floating mode (not tiled, not maximized).

When set, this points to the root Element of the AT-SPI2 accessibility tree for this surface. All elements within the window are descendants of this root. When null, the application has no AT-SPI2 support and elements will use compositor-only fallback representations.

For popups, menus, and dialogs, this points to the parent toplevel surface. Null for toplevel windows.

{
"id": "surf:47-w1",
"app_id": "app:wl-47",
"title": "Inbox — Evolution Mail",
"surface_type": "toplevel",
"geometry": { "x": 100, "y": 50, "w": 1200, "h": 800 },
"workspace": "ws:1",
"output": "out:HDMI-A-1",
"state": {
"focused": true,
"activated": true,
"minimized": false,
"fullscreen": false,
"tiled": null,
"maximized": false,
"occluded": false,
"floating": false
},
"atspi2_root": "atspi:root-47-w1",
"parent_surface": null
}

This is a focused, activated toplevel window on workspace ws:1, displayed on output out:HDMI-A-1. The AT-SPI2 root is set, meaning the full accessibility tree is available for element inspection.

Last updated: