Skip to content

Plugin windows (Plugin Window SPI) ​

Third parties can create QML windows that are multi-instance, positionable, always-on-top, click-through and capture-excluded, without any host source changes. Use cases: OCR translation overlays, standalone assistant windows, tool HUDs, floating hint boards.

Use this page's API for functional persistent windows; for theme/decorative slot replacement see UI slots.


Create ​

python
host.create_plugin_window(
    plugin_id: str,
    qml_path: str,                    # path relative to the plugin package, or a file:// URL
    *,
    window_id: str = "",              # auto-generated when omitted; recreating the same ID closes the old window first
    title: str = "",
    x: int | None = None,
    y: int | None = None,
    width: int = 480,
    height: int = 320,
    always_on_top: bool = True,
    frameless: bool = False,
    click_through: bool = False,
    exclude_from_capture: bool = False,
    context: dict | None = None,      # extra properties injected into the root object
) -> str                              # window_id; "" on failure

Control ​

python
host.show_plugin_window(window_id: str, visible: bool = True) -> bool
host.close_plugin_window(window_id: str) -> bool
host.close_plugin_windows(plugin_id: str | None = None) -> bool
host.move_plugin_window(window_id: str, x: int, y: int) -> bool
host.resize_plugin_window(window_id: str, width: int, height: int) -> bool
host.set_plugin_window_flags(
    window_id: str,
    *,
    always_on_top: bool | None = None,
    click_through: bool | None = None,
    exclude_from_capture: bool | None = None,
) -> bool
host.list_plugin_windows(plugin_id: str = "") -> list[dict]
host.get_plugin_window(window_id: str) -> dict

QML conventions ​

  • The root element can be:
    • Window — fully self-managed (you set visible / position / flags yourself);
    • Item — the host wraps it in a PluginWindowShell automatically (recommended: less work, consistent styling).
  • The host injects: pluginId, windowId, bridge, plus every key from context.
  • Frameless windows handle their own dragging.
  • click_through / exclude_from_capture use host platform capabilities (the latter is SetWindowDisplayAffinity, see Speech & feedback).
  • A plugin's shutdown() should call close_plugin_windows(self.id); a destroyed window leaves the registry automatically.

Minimal example ​

python
# A positioned overlay window (e.g. OCR translation)
wid = self.host.create_plugin_window(
    self.id, "Overlay.qml",
    title="OCR",
    x=100, y=80, width=420, height=120,
    always_on_top=True, frameless=True,
    click_through=True,
    exclude_from_capture=True,
    context={"scale": 1.0},
)
if wid:
    self.host.move_plugin_window(wid, 100, 80)
qml
// Overlay.qml (root is an Item; the host wraps it in the shell)
import QtQuick 2.15

Item {
    property string pluginId: ""
    property string windowId: ""
    property var bridge: null
    property real scale: 1.0     // ← injected via context

    Text { text: "识别结果…"; color: "white" }
}

How this differs from UI slots ​

Plugin windowsUI slots
CountMultipleUsually a single instance (same-level slots are mutually exclusive)
PositionFreely positioned/resized at runtimeDecided by the host layout
Typical useTool HUD, standalone assistant, overlaySwap backplate / VU meter / caption view
DeclarationCode callui_extensions in mod.json

TransBox — empowering borderless cross-language communication for everyone