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(event). 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='', 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.

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

  • properties_type (type) – NamedTuple class for typed operator properties. A field annotated Annotated[T, "description"] documents that property. A binding or menu item carries only int, bool, float, str, tuple[str, ...] and None values; other types work only when the operator is called directly.

Return type:

None

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. A field’s Annotated string is its description.


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


class ScratchToggleProperties(NamedTuple):
    name: Annotated[str, "Workspace to toggle."]


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 whether it floats.
    ws = ion.wm.workspaces.get(ws_name)
    if ws is None:
        # Center the floating workspace 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 whether a named workspace floats.",
    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 an operator by identifier.

Applies to any registered operator, including built-ins - ion_utils.config.reset_defaults relies on this and restores the built-ins afterwards.

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()

Re-run the configuration by reloading the ion_init module.

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', 'UP_LEFT', 'UP_RIGHT', 'DOWN_LEFT', 'DOWN_RIGHT']) – Direction to move, a diagonal for the desktop at the corner.

  • 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_all_set(name, mode=-1)

Set the fullscreen state of the focused window over all outputs.

Parameters:
  • name (str) – Name of the shared workspace spanning every output; pick one unlikely to collide with your own workspaces.

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

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 whether a named workspace floats.

Parameters:
  • name (str) – Workspace name.

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

  • use_active_output (bool) – Reposition the workspace to the 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.