Python library for controlling the i3 window manager and sway compositor through their IPC interface
—
Comprehensive event subscription and handling system for real-time monitoring of window manager state changes. Supports fine-grained event filtering and both synchronous and asynchronous event processing.
def on(self, event: Union[Event, str], handler: Callable[[Connection, IpcBaseEvent], None]) -> None:
"""
Subscribe to window manager events.
Parameters:
- event: Union[Event, str], event type to subscribe to
- handler: Callable, function called when event occurs (receives connection and event data)
"""
def off(self, handler: Callable[[Connection, IpcBaseEvent], None]) -> None:
"""
Unsubscribe event handler from all events.
Parameters:
- handler: Callable, handler function to remove from all subscriptions
"""def main(self, timeout: float = 0.0) -> None:
"""
Start the main event loop to process subscribed events.
Parameters:
- timeout: float, timeout in seconds (0 = run forever until main_quit called)
"""
def main_quit(self) -> None:
"""
Stop the main event loop and exit event processing.
"""class Event(Enum):
"""Enumeration of all available event types for subscription."""
# Primary event categories
WORKSPACE = 'workspace' # Any workspace change
WINDOW = 'window' # Any window change
OUTPUT = 'output' # Output/monitor changes
MODE = 'mode' # Binding mode changes
BARCONFIG_UPDATE = 'barconfig_update' # Bar configuration changes
BINDING = 'binding' # Key/mouse binding events
SHUTDOWN = 'shutdown' # Window manager shutdown events
TICK = 'tick' # Tick events from send_tick()
INPUT = 'input' # Input device changes (sway only)
# Specific workspace events
WORKSPACE_FOCUS = 'workspace::focus' # Workspace gained focus
WORKSPACE_INIT = 'workspace::init' # New workspace created
WORKSPACE_EMPTY = 'workspace::empty' # Workspace became empty
WORKSPACE_URGENT = 'workspace::urgent' # Workspace urgency changed
WORKSPACE_RELOAD = 'workspace::reload' # Workspace configuration reloaded
WORKSPACE_RENAME = 'workspace::rename' # Workspace was renamed
WORKSPACE_RESTORED = 'workspace::restored' # Workspace restored from session
WORKSPACE_MOVE = 'workspace::move' # Workspace moved to different output
# Specific window events
WINDOW_NEW = 'window::new' # New window created
WINDOW_CLOSE = 'window::close' # Window closed
WINDOW_FOCUS = 'window::focus' # Window gained focus
WINDOW_TITLE = 'window::title' # Window title changed
WINDOW_FULLSCREEN_MODE = 'window::fullscreen_mode' # Fullscreen state changed
WINDOW_MOVE = 'window::move' # Window moved to different container
WINDOW_FLOATING = 'window::floating' # Window floating state changed
WINDOW_URGENT = 'window::urgent' # Window urgency changed
WINDOW_MARK = 'window::mark' # Window mark added/removed
# Shutdown events
SHUTDOWN_RESTART = 'shutdown::restart' # Window manager restarting
SHUTDOWN_EXIT = 'shutdown::exit' # Window manager exiting
# Input events (sway only)
INPUT_ADDED = 'input::added' # Input device connected
INPUT_REMOVED = 'input::removed' # Input device disconnectedclass IpcBaseEvent:
"""Abstract base class for all event objects."""
ipc_data: dict # Raw IPC event data from window manager
class WorkspaceEvent(IpcBaseEvent):
"""Workspace-related event information."""
change: str # Type of change (focus, init, empty, urgent, etc.)
current: Con # Current workspace container (may be None)
old: Con # Previous workspace container (may be None)
class WindowEvent(IpcBaseEvent):
"""Window-related event information."""
change: str # Type of change (new, close, focus, title, etc.)
container: Con # Affected window container
class OutputEvent(IpcBaseEvent):
"""Output/monitor-related event information."""
change: str # Type of change (output added, removed, etc.)
class ModeEvent(IpcBaseEvent):
"""Binding mode change event information."""
change: str # Mode change type
pango_markup: bool # Whether pango markup is enabled for mode display
class BarconfigUpdateEvent(BarConfigReply):
"""Bar configuration update event (inherits all BarConfigReply properties)."""
# Inherits: id, mode, position, status_command, font, colors, etc.
class BindingEvent(IpcBaseEvent):
"""Key or mouse binding event information."""
change: str # Binding change type
binding: BindingInfo # Details about the binding
class ShutdownEvent(IpcBaseEvent):
"""Window manager shutdown event information."""
change: str # Shutdown type (restart, exit)
class TickEvent(IpcBaseEvent):
"""Tick event information from send_tick() calls."""
first: Optional[bool] # Whether this is the first tick (None in i3 ≤4.15)
payload: str # Payload data sent with tick
class InputEvent(IpcBaseEvent):
"""Input device change event (sway only)."""
change: str # Change type (added, removed)
input: InputReply # Input device informationclass BindingInfo:
"""Detailed information about key/mouse bindings."""
command: str # Command associated with binding
event_state_mask: List[str] # Modifier keys (Shift, Ctrl, Alt, etc.)
input_code: int # Key code or mouse button code
symbol: Optional[str] # Key symbol or mouse button name (may be None)
input_type: str # Input type ('keyboard' or 'mouse')
symbols: List[str] # Additional symbols for binding (sway only)
mods: List[str] # Modifier keys (i3 only, not included in sway)
ipc_data: dict # Raw IPC binding data# Simple event handler
def on_window_focus(i3, event):
print(f"Window focused: {event.container.name}")
# Handler with event data access
def on_workspace_change(connection, event):
if event.change == 'focus':
print(f"Switched to workspace: {event.current.name}")
if event.old:
print(f"Previous workspace: {event.old.name}")
# Handler for binding events
def on_binding(i3, event):
binding = event.binding
print(f"Key pressed: {binding.symbol} -> {binding.command}")
print(f"Modifiers: {', '.join(binding.event_state_mask)}")
# Subscribe to events
i3.on(Event.WINDOW_FOCUS, on_window_focus)
i3.on(Event.WORKSPACE_FOCUS, on_workspace_change)
i3.on(Event.BINDING, on_binding)
# Start event processing
i3.main() # Runs until main_quit() calledInstall with Tessl CLI
npx tessl i tessl/pypi-i3ipc