D-Bus scripting guide

Script layouts, snap windows, and watch PlasmaZones state from the shell.

PlasmaZones exposes 13 D-Bus interfaces on org.plasmazones, object path /PlasmaZones. Nine are meant for scripting; four are internal IPC between the daemon, compositor, editor, and settings app. The per-interface XML files under dbus/ in the source tree are the source of truth for method and signal definitions.

Basics

Everything is on the session bus. Two command-line clients handle most work: qdbus6 for one-shot calls, and gdbus for signal watching. Both ship with standard Qt and GNOME installs.

# Call a method: service object-path interface.method
qdbus6 org.plasmazones /PlasmaZones org.plasmazones.Control.getFullState
# List every interface and method exposed by the daemon at runtime
qdbus6 org.plasmazones /PlasmaZones

qdbus6 org.plasmazones /PlasmaZones with no method prints the full introspection tree. Useful when the XML in the repo is ahead of the version you have installed, or vice versa.

Interfaces

InterfacePurposeAudience
ControlHigh-level convenience: snap a window, toggle autotile, full-state snapshot, support report.Scripting
LayoutRegistryLayout CRUD, active-layout selection, quick-layout slots, per-screen assignment, editor launch.Scripting
AutotilePer-screen autotile enable/disable, algorithm selection, master ratio/count, focus + swap ops.Scripting
ZoneDetectionZone lookup by position, by number, or by direction from another zone. Drag modifier state.Scripting
WindowTrackingWindow-to-zone queries, floating state, pre-tile geometry cache.Scripting
OverlayShow / hide the zone overlay, highlight specific zones, snap-assist thumbnails, shader preview.Scripting
ScreenPhysical and virtual screen topology, primary-screen selection, virtual-screen config.Scripting
SettingsGeneric get / set for every configurable setting, schemas, zone-selector controls.Scripting
ShaderShader enumeration, parameter defaults, user-shader directory, compilation signals.Scripting
CompositorBridgeCompositor-facing IPC: applyWindowGeometry, activateWindow signals.Internal
WindowDragDrag lifecycle (beginDrag, updateDragCursor, endDrag) driven by the compositor.Internal
EditorAppEditor launch handling from the daemon.Internal
SettingsAppSettings-app page switching for single-instance -p / --page flags.Internal

Internal interfaces still respond to calls, but they assume the compositor, editor, or settings-app lifecycle is driving them. Invoking WindowDrag.beginDrag from a shell script will compile and dispatch, but the daemon won't be in the right state to handle the drag.

Scripting recipes

List and switch layouts

# Every known layout (JSON with id, name, zones, ...)
qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.LayoutRegistry.getLayoutList
# Active layout
qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.LayoutRegistry.getActiveLayout
# Switch to a layout by UUID
qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.LayoutRegistry.setActiveLayout \
'{d2a6c1e3-4b88-4f3f-9b2f-7c0a1e5f2b11}'
# Apply a quick-layout slot (1-9) to a specific screen
qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.LayoutRegistry.applyQuickLayout \
3 "$(qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.Screen.getPrimaryScreen)"

Layout IDs are QUuid strings; use them verbatim from getLayoutList output including the braces. Screen IDs come from Screen.getScreens or Screen.getPrimaryScreen.

Snap a window programmatically

# Snap window "$WID" to zone 3 on the primary screen
qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.Control.snapWindowToZone "$WID" 3 ""

windowId is the compositor's stable window handle (on KDE: the KWin window UUID). An empty screenId resolves to the primary screen. The zone number is 1-indexed and matches what shows in the overlay.

Toggle autotile per screen

SCREEN=$(qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.Screen.getPrimaryScreen)
# Flip between snapping and autotile on this screen
qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.Control.toggleAutotileForScreen "$SCREEN"
# Or force an explicit retile of one screen or all screens
qdbus6 org.plasmazones /PlasmaZones org.plasmazones.Autotile.retile "$SCREEN"
qdbus6 org.plasmazones /PlasmaZones org.plasmazones.Autotile.retileAllScreens

Show the overlay without dragging

Handy for demos, screenshots, and pairing with zone lookups from ZoneDetection.

qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.Overlay.showOverlay
# Highlight a specific zone by UUID (see ZoneDetection for how to get one)
qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.Overlay.highlightZone "{...uuid...}"
qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.Overlay.hideOverlay

Read or change a setting

# Dump every setting as JSON
qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.Settings.getAllSettings
# Read one setting by key. Keys mirror the UI hierarchy, e.g.
# "Snapping.Behavior.ZoneSpan.enabled".
qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.Settings.getSetting "Snapping.Behavior.ZoneSpan.enabled"
# Write one. The value is a QVariant; pass it as a literal string.
qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.Settings.setSetting \
"Snapping.Behavior.ZoneSpan.enabled" true

For the full schema, call Settings.getAllSettingSchemas. It returns per-key type, default, and range metadata. The settings app uses the same call to build its UI.

Generate a support report

# 30 minutes of logs (the 0 means "use default")
qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.Control.generateSupportReport 0
# Same thing with a 90-minute log window
qdbus6 org.plasmazones /PlasmaZones \
org.plasmazones.Control.generateSupportReport 90

The return value is a Markdown string with home paths redacted, safe to paste into a GitHub issue. The plasmazones-report CLI calls this method and wraps it with archive and output options; see the Troubleshooting page for the CLI flags.

Watching signals

Most interfaces emit change signals. To watch them from the shell without writing a client, use gdbus monitor:

# Everything under the PlasmaZones object
gdbus monitor --session \
--dest org.plasmazones --object-path /PlasmaZones
# Or filter to one interface
gdbus monitor --session \
--dest org.plasmazones --object-path /PlasmaZones \
| grep org.plasmazones.LayoutRegistry

Useful signals include LayoutRegistry.activeLayoutChanged, Screen.virtualScreensChanged, Overlay.overlayVisibilityChanged, Shader.shadersChanged, and Settings.settingsChanged. Per-interface signal lists are in the XML files linked at the top of this page.

Python, Rust, and other clients

Anything that speaks session D-Bus can talk to the daemon. A few starting points:

Where the source of truth lives

The per-interface XML files under dbus/ carry org.gtk.GDBus.DocString annotations on every method, signal, and argument. Those annotations are the reference for what each call does. The adaptor implementations live next to them under src/dbus/. When scripting against a specific PlasmaZones version, check out the matching tag; method signatures change across releases.

See also