ion.ops

This module provides operators - named actions that drive the compositor. Operators are bound to keys via ion.app keymaps or called directly from Python callbacks.

Each operator is a NamedTuple class stored on ion.ops. Calling the class creates an immutable operator instance with its properties baked in - and it is that instance, never the class, that is used: pass it to new() as operator=..., or invoke it directly with instance.call(). Because a binding holds an instance, even parameterless operators need empty parens. Parameterized: ion.ops.tiling_split(direction="LEFT"). Parameterless: ion.ops.compositor_quit().

Built-in operator names are prefixed by the entity they act on (e.g. window_, frame_, workspace_).

Custom operators can be defined with ion.ops.register() - the operator provides an exec callback and an optional poll callback that controls when the operator is available.

Operators that can be bound to keys or called directly.

Functions

ion.ops.register(idname, *, name, exec, poll=None, description='', properties=None, pointer_only=False, properties_type)

Register a dynamic operator from Python.

ion.ops.register("my_op", name=MyOp.name, exec=MyOp.exec, properties_type=MyProperties)
Parameters:
  • idname (str) – Unique operator identifier.

  • name (Callable[..., str]) – Display name callback receiving a properties_type instance.

  • exec (Callable[[Any, :class:`~ion.types.Event`], bool | None]) –

    Callback receiving a properties_type instance and an Event. Must return bool or None:

    • True - the operator handled the event (binding consumed).

    • False - the operator failed (binding still consumed).

    • None - pass-through. The operator declined to handle this event. When the same key is bound to multiple operators (across keymaps or within a single keymap), the binding system tries the next matching operator. This allows context-sensitive fall-through where several operators share one key and each checks whether it should act.

  • poll (Callable[..., Any] | None) – Optional callback receiving a properties_type instance, returning None if the operator is available, or a reason string if not.

  • description (str) – Description of the operator.

  • properties (dict[str, Any] | None) – Property definitions for the operator.

  • pointer_only (bool) – If true, operator can only be triggered by pointer bindings.

  • properties_type (type) – NamedTuple class for typed operator properties.

Custom Operator

Register a custom operator with ion.ops.register() and bind it to a key. The exec callback receives a NamedTuple whose fields are declared at registration time via properties_type, and an Event describing the input that triggered it.


import ion
from typing import NamedTuple
from ion.types import Event, MatchKey, Rect
import ion.constants.keys as kbd
import ion.ops as ops


class ScratchToggleProperties(NamedTuple):
    name: str


def _scratch_toggle_name(properties: ScratchToggleProperties) -> str:
    return 'Toggle Scratchpad'


def _scratch_toggle_exec(properties: ScratchToggleProperties, event: Event) -> None:
    ws_name = properties.name
    # Find or create the workspace, then toggle its floating overlay.
    ws = ion.wm.workspaces.get(ws_name)
    if ws is None:
        # Center the overlay at 80 % of the active output.
        output = ion.wm.outputs.active_pointer
        assert output is not None
        r = output.rect
        w, h = int(r.size_x * 0.8), int(r.size_y * 0.8)
        cx, cy = r.center_floor()
        x, y = cx - w // 2, cy - h // 2
        ws = ion.wm.workspaces.new(Rect((x, y), (x + w, y + h)), ws_name)
    desktop = ion.wm.desktops.active
    if ws.is_floating:
        item = desktop.items_floating.find_by_workspace(ws)
        if item is not None:
            desktop.items_floating.remove(item)
    else:
        desktop.items_floating.add(ws)


ion.ops.register(
    "scratch_toggle",
    name=_scratch_toggle_name,
    exec=_scratch_toggle_exec,
    description="Toggle a named workspace as a floating overlay.",
    properties={"name": {"type": "str"}},
    properties_type=ScratchToggleProperties,
)

# Bind Logo+Space to toggle a scratchpad workspace.
ion.app.keymaps['global'].items.new(
    MatchKey(kbd.SPACE, logo=True),
    operator=ops.scratch_toggle(name="scratch"),  # type: ignore[attr-defined]
)
ion.ops.unregister(idname)

Unregister a dynamic operator by identifier.

Only operators registered via register() can be removed. Static (built-in) operators cannot be unregistered.

ion.ops.unregister("my_op")
Parameters:

idname (str) – Operator identifier to remove.

Returns:

Whether the operator was found and removed.

Return type:

bool

Operators

ion.ops.compositor_logout()

Graceful logout: close all windows, exit when none remain.

ion.ops.compositor_quit()

Exit the compositor.

ion.ops.compositor_reload()

Reload the configuration file.

ion.ops.delete_empty_workspace()

Delete the current workspace.

ion.ops.desktop_delete()

Delete the current desktop.

ion.ops.desktop_focus_cycle(direction, wrap=True, animate=False)

Cycle through desktops.

Parameters:
  • direction (int) – Positive for next, negative for previous.

  • wrap (bool) – Wrap around at the ends.

  • animate (bool) – Use zoom animation.

ion.ops.desktop_focus_directional(direction, wrap=True, animate=False)

Focus the adjacent desktop in a direction.

Parameters:
  • direction (Literal['LEFT', 'RIGHT', 'UP', 'DOWN']) – Direction to move.

  • wrap (bool) – Wrap to the opposite desktop when at the edge.

  • animate (bool) – Use zoom animation.

ion.ops.desktop_focus_empty_cycle(direction, wrap=True, name='', animate=False)

Cycle through empty desktops, creating one if none exist.

Parameters:
  • direction (int) – Positive for next, negative for previous.

  • wrap (bool) – Wrap around at the ends.

  • name (str) – Name for the new desktop if one is created.

  • animate (bool) – Use zoom animation.

ion.ops.desktop_focus_occupied_cycle(direction, wrap=True, animate=False)

Cycle through occupied desktops.

Parameters:
  • direction (int) – Positive for next, negative for previous.

  • wrap (bool) – Wrap around at the ends.

  • animate (bool) – Use zoom animation.

Cancel desktop item carousel.

Confirm selection in desktop item carousel.

Show all desktop items on a 3D carousel, select one to focus.

Parameters:

keymap (str) – Keymap name for input handling.

ion.ops.desktop_new(name='')

Create a new empty desktop.

Parameters:

name (str) – Desktop name. Empty string uses a default name.

ion.ops.desktop_overview(keymap, trim_empty=False)

Zoom out to show all desktops, click one to switch.

Parameters:
  • keymap (str) – Keymap name for input handling.

  • trim_empty (bool) – Trim empty desktops from end-points (active desktop always included).

ion.ops.desktop_overview_cancel()

Cancel desktop overview.

ion.ops.desktop_overview_confirm()

Confirm selection in desktop overview.

ion.ops.desktop_overview_navigate(direction)

Navigate selection in desktop overview.

Parameters:

direction (Literal['LEFT', 'RIGHT', 'UP', 'DOWN']) – Direction to move.

ion.ops.desktop_overview_select()

Select desktop at pointer position in desktop overview.

ion.ops.floating_depth_to_back()

Lower a floating item to the back.

ion.ops.floating_depth_to_front()

Raise a floating item to the front.

ion.ops.floating_lower()

Lower the floating item under the pointer (pointer binding only).

ion.ops.floating_move()

Move a floating item by dragging (pointer binding only).

ion.ops.floating_raise()

Raise the floating item under the pointer (pointer binding only).

ion.ops.floating_resize(border=False)

Resize a floating item by dragging (pointer binding only).

Parameters:

border (bool) – Use border-relative edge detection (drag initiated from border).

ion.ops.frame_delete()

Remove the current frame from its parent split.

ion.ops.frame_focus_cycle(direction)

Cycle frame focus in the workspace, wrapping around.

Parameters:

direction (int) – Positive for next, negative for previous.

ion.ops.frame_join()

Recursively merge the parent split into a single frame.

ion.ops.frame_tab_activate()

Activate the tab under the pointer.

ion.ops.frame_tab_cycle(direction)

Cycle tabs in the current frame.

Parameters:

direction (int) – Positive for next, negative for previous.

ion.ops.frame_tab_drag()

Drag a tiled tab to move it between frames (pointer binding only).

ion.ops.frame_tab_index_move(direction)

Move the current tab to the next/previous position.

Parameters:

direction (int) – Positive for next, negative for previous.

ion.ops.frame_tab_nth(tab_index)

Switch to tab N in the current frame.

Parameters:

tab_index (int) – Zero-based tab index.

ion.ops.frame_tile()

Tile floating workspace frame back into the tiling workspace.

ion.ops.frame_untile()

Extract frame from tiling into a floating workspace.

ion.ops.keymap_prompt(name)

Activate a keymap for the next key press (leader key).

Parameters:

name (str) – The keymap name.

ion.ops.menu_show(idname)

Show a named context menu.

Parameters:

idname (str) – The menu identifier.

ion.ops.output_focus_directional(direction, wrap=True)

Focus the adjacent output (monitor) in a direction.

Parameters:
  • direction (Literal['LEFT', 'RIGHT', 'UP', 'DOWN']) – Direction to move.

  • wrap (bool) – Wrap to an aligned or diagonal corner-touch output.

ion.ops.output_move_directional(direction, pointer_warp=True, wrap=True)

Move the focused item (floating, tiled, or fullscreen) to the output in a direction.

Parameters:
  • direction (Literal['LEFT', 'RIGHT', 'UP', 'DOWN']) – Direction to move.

  • pointer_warp (bool) – Warp pointer to follow the moved item.

  • wrap (bool) – Wrap to an aligned or diagonal corner-touch output.

ion.ops.python_exec(filepath)

Execute a Python script.

Parameters:

filepath (str) – Path to the Python file.

ion.ops.system_exec(command)

Execute a command directly (no shell).

Parameters:

command (tuple[str, ...]) – Program and arguments.

ion.ops.system_noop()

Do nothing. Useful for overriding bindings in higher-priority keymaps.

ion.ops.system_shell(command)

Execute a shell command.

Parameters:

command (str) – Shell command to execute.

ion.ops.tag_attach()

Attach all tagged windows to the current frame as tabs.

ion.ops.tag_clear()

Untag all tagged windows.

ion.ops.tag_set(mode=-1)

Set the tagged state of the focused window.

Parameters:

mode (Literal[-1, 0, 1]) – -1 to toggle, 0 to untag, 1 to tag.

ion.ops.tiling_divider_gapless_set(mode=-1, parent_depth=0)

Set whether the split divider renders flush, with no gap between its frames.

Parameters:
  • mode (Literal[-1, 0, 1, 2]) – -1 to toggle, 0 to show the divider, 1 to make it gapless, 2 for automatic.

  • parent_depth (int) – 0 for the frame’s parent, 1 for grandparent, etc. -1 for root.

ion.ops.tiling_divider_resize()

Resize by dragging the split divider under the pointer (pointer binding only).

ion.ops.tiling_floating_split(direction)

Extract the sibling subtree of the current frame into a floating workspace.

Parameters:

direction (Literal['LEFT', 'RIGHT', 'UP', 'DOWN']) – Direction to move.

ion.ops.tiling_focus_directional(direction, wrap=True)

Focus the frame in a direction.

Parameters:
  • direction (Literal['LEFT', 'RIGHT', 'UP', 'DOWN']) – Direction to move.

  • wrap (bool) – Wrap to an aligned output, diagonal output, or this output.

ion.ops.tiling_orient_directional(direction)

Orient the split so the active frame is located in a particular direction. This provides a convenient way to orient the active frame without having to perform separate axis-rotate and swap operation.

Parameters:

direction (Literal['LEFT', 'RIGHT', 'UP', 'DOWN']) – Direction to place the active frame in relation to it’s sibling.

ion.ops.tiling_resize(delta)

Resize the current frame by a delta in logical pixels.

Parameters:

delta (int) – Amount in logical pixels (positive grows, negative shrinks).

ion.ops.tiling_split(direction)

Split the current frame in a direction.

Parameters:

direction (Literal['LEFT', 'RIGHT', 'UP', 'DOWN']) – Direction to place the new frame.

ion.ops.tiling_split_axis_rotate(angle=90, parent_depth=0, pointer_warp=True)

Rotate the split axis by 90, 180, or 270 degrees.

Parameters:
  • angle (Literal[90, 180, 270]) – 90 (left), 180 (flip), or 270 (right).

  • parent_depth (int) – 0 for the frame’s parent, 1 for grandparent, etc. -1 for root.

  • pointer_warp (bool) – Warp pointer to the active frame after changing.

ion.ops.tiling_split_axis_set(axis=-1, parent_depth=0, pointer_warp=True)

Set or toggle the split direction at a given depth.

Parameters:
  • axis (int) – -1 to toggle, 0 for horizontal, 1 for vertical.

  • parent_depth (int) – 0 for the frame’s parent, 1 for grandparent, etc. -1 for root.

  • pointer_warp (bool) – Warp pointer to the active frame after changing.

ion.ops.tiling_swap(parent_depth=0, pointer_warp=True)

Swap the two children at a given depth.

Parameters:
  • parent_depth (int) – 0 for the frame’s parent, 1 for grandparent, etc. -1 for root.

  • pointer_warp (bool) – Warp pointer to the active frame after swapping.

Cancel window carousel.

Confirm selection in window carousel.

ion.ops.window_close(delete_empty_frame=False, delete_empty_workspace=False)

Close focused window, or remove frame if empty.

Parameters:
  • delete_empty_frame (bool) – Remove the frame when it has no windows.

  • delete_empty_workspace (bool) – Delete the workspace if it has only one empty frame.

Show all windows on a 3D carousel, select one to focus.

Parameters:

keymap (str) – Keymap name for input handling.

ion.ops.window_floating_set(mode=-1)

Set the floating state of the focused window.

Parameters:

mode (Literal[-1, 0, 1]) – -1 to toggle, 0 to tile, 1 to float.

ion.ops.window_focus_last()

Focus the previously focused window.

ion.ops.window_fullscreen_set(mode=-1)

Set the fullscreen state of the focused window.

Parameters:

mode (Literal[-1, 0, 1]) – -1 to toggle, 0 to disable, 1 to enable.

ion.ops.window_kill()

Force-kill an unresponsive window.

ion.ops.window_overview(keymap)

Zoom out to show all windows across desktops in a grid.

Parameters:

keymap (str) – Keymap name for input handling.

ion.ops.window_overview_cancel()

Cancel window overview.

ion.ops.window_overview_confirm()

Confirm selection in window overview.

ion.ops.window_overview_navigate(direction)

Navigate selection in window overview.

Parameters:

direction (Literal['LEFT', 'RIGHT', 'UP', 'DOWN']) – Direction to move.

ion.ops.window_overview_select()

Select window at pointer position in window overview.

ion.ops.window_switcher(keymap, direction=1)

Alt-Tab style switcher for windows on the current desktop.

Parameters:
  • keymap (str) – Keymap name for input handling.

  • direction (int) – Initial step applied on invocation: 1 keeps the active window selected (forward shortcut), -1 steps one backwards (reverse shortcut).

ion.ops.window_switcher_cancel()

Cancel the window switcher without activating a window.

ion.ops.window_switcher_next()

Advance the window switcher selection.

ion.ops.window_switcher_prev()

Retreat the window switcher selection.

ion.ops.window_tiling_move_directional(direction, wrap=True)

Move the focused window to a frame in a direction.

Parameters:
  • direction (Literal['LEFT', 'RIGHT', 'UP', 'DOWN']) – Direction to move.

  • wrap (bool) – Wrap to an aligned output, diagonal output, or this output.

ion.ops.window_workspace_pop(name, window_index=-1)

Move a window from a named workspace to the focused frame.

Parameters:
  • name (str) – Source workspace name.

  • window_index (int) – Window index. -1 is the most recently added window, 0 is the oldest. Supports negative indexing, clamped to range.

ion.ops.window_workspace_push(name)

Send focused window to named workspace.

Parameters:

name (str) – Target workspace name.

ion.ops.workspace_floating_set(name, mode=-1, use_active_output=True)

Set a named workspace as floating overlay.

Parameters:
  • name (str) – Workspace name.

  • mode (Literal[-1, 0, 1]) – -1 to toggle, 0 to hide, 1 to show.

  • use_active_output (bool) – Reposition overlay to active output when showing.

ion.ops.workspace_new_floating(name='')

Create a new floating workspace.

Parameters:

name (str) – Workspace name. Empty string uses a default name.

ion.ops.workspace_new_tiling_on_desktop(name='')

Create a new tiling workspace.

Parameters:

name (str) – Workspace name. Empty string uses a default name.

ion.ops.workspace_new_tiling_on_output(name='')

Create a new tiling workspace confined to the output under the cursor.

Parameters:

name (str) – Workspace name. Empty string uses a default name.

ion.ops.workspace_tile_on_desktop()

Convert floating workspace to a tiled workspace.

ion.ops.workspace_tile_on_output()

Convert floating workspace to a per-output tiled workspace.

ion.ops.workspace_untile()

Convert tiled workspace to a floating workspace.