i3-companion: switch to asyncio

This commit is contained in:
Vincent Bernat 2021-07-07 00:24:23 +02:00
parent 1925a57b6d
commit b8a6ad1122

View file

@ -12,9 +12,10 @@ import logging.handlers
import os import os
import sys import sys
import re import re
import time import asyncio
from i3ipc import Connection, Event from i3ipc.aio import Connection
from i3ipc import Event
logger = logging.getLogger(os.path.splitext(os.path.basename(sys.argv[0]))[0]) logger = logging.getLogger(os.path.splitext(os.path.basename(sys.argv[0]))[0])
@ -93,9 +94,10 @@ def application_icon(window):
return application_icons["NOMATCH"] return application_icons["NOMATCH"]
def workspace_rename(i3, event): async def workspace_rename(i3, event):
"""Rename workspaces using icons to match what's inside it.""" """Rename workspaces using icons to match what's inside it."""
workspaces = i3.get_tree().workspaces() tree = await i3.get_tree()
workspaces = tree.workspaces()
commands = [] commands = []
for workspace in workspaces: for workspace in workspaces:
icons = set() icons = set()
@ -110,33 +112,35 @@ def workspace_rename(i3, event):
logger.debug(f"rename workspace {workspace.num}") logger.debug(f"rename workspace {workspace.num}")
command = f'rename workspace "{workspace.name}" to "{new_name}"' command = f'rename workspace "{workspace.name}" to "{new_name}"'
commands.append(command) commands.append(command)
i3.command(';'.join(commands)) await i3.command(';'.join(commands))
def new_workspace(i3, event): async def new_workspace(i3, event):
"""Create a new workspace and optionally move a window to it.""" """Create a new workspace and optionally move a window to it."""
if event.payload not in {"new-workspace", "move-to-new-workspace"}: if event.payload not in {"new-workspace", "move-to-new-workspace"}:
return return
# Get the currently focused window # Get the currently focused window
if event.payload == "move-to-new-workspace": if event.payload == "move-to-new-workspace":
current = i3.get_tree().find_focused() tree = await i3.get_tree()
current = tree.find_focused()
if not current: if not current:
return return
# Create a new workspace # Create a new workspace
workspace_nums = {w.num for w in i3.get_workspaces()} workspaces = await i3.get_workspaces()
workspace_nums = {w.num for w in workspaces}
max_num = max(workspace_nums) max_num = max(workspace_nums)
available = (set(range(1, max_num + 2)) - workspace_nums).pop() available = (set(range(1, max_num + 2)) - workspace_nums).pop()
logger.info(f'create new workspace number {available}') logger.info(f'create new workspace number {available}')
i3.command(f'workspace number "{available}"') await i3.command(f'workspace number "{available}"')
# Move the window to this workspace # Move the window to this workspace
if event.payload == "move-to-new-workspace": if event.payload == "move-to-new-workspace":
current.command(f'move container to workspace number "{available}"') await current.command(f'move container to workspace number "{available}"')
def quake_console(i3, event): async def quake_console(i3, event):
"""Spawn a quake console or toggle an existing one.""" """Spawn a quake console or toggle an existing one."""
if type(event.payload) is not str or \ if type(event.payload) is not str or \
not event.payload.startswith("quake-console:"): not event.payload.startswith("quake-console:"):
@ -148,18 +152,21 @@ def quake_console(i3, event):
logger.warn(f"unable to parse payload {event.payload}: {exc}") logger.warn(f"unable to parse payload {event.payload}: {exc}")
return return
term = i3.get_tree().find_instanced(term_name) tree = await i3.get_tree()
term = tree.find_instanced(term_name)
if not term: if not term:
i3.command(f'exec {term_exec} --name {term_name}') await i3.command(f'exec {term_exec} --name {term_name}')
tries = 5 tries = 5
while not term and tries: while not term and tries:
term = i3.get_tree().find_instanced(term_name) tree = await i3.get_tree()
time.sleep(0.2) term = tree.find_instanced(term_name)
await asyncio.sleep(0.2)
tries -= 1 tries -= 1
if not term: if not term:
raise RuntimeError("unable to spawn terminal") raise RuntimeError("unable to spawn terminal")
term = term[0] term = term[0]
workspace = [ws for ws in i3.get_workspaces() if ws.focused][0] workspaces = await i3.get_workspaces()
workspace = [ws for ws in workspaces if ws.focused][0]
ws_x = workspace.rect.x ws_x = workspace.rect.x
ws_y = workspace.rect.y ws_y = workspace.rect.y
ws_width = workspace.rect.width ws_width = workspace.rect.width
@ -174,7 +181,29 @@ def quake_console(i3, event):
'scratchpad show,' 'scratchpad show,'
f'move absolute position {posx}px {posy}px') f'move absolute position {posx}px {posy}px')
logger.debug(f"QuakeConsole: {command}") logger.debug(f"QuakeConsole: {command}")
i3.command(command) await i3.command(command)
async def main(options):
i3 = await Connection().connect()
# Rename workspace depending on what is inside
for event in {Event.WINDOW_MOVE,
Event.WINDOW_NEW,
Event.WINDOW_CLOSE}:
i3.on(event, workspace_rename)
# Create a new workspace or move to a new workspace
i3.on(Event.TICK, new_workspace)
# Create/display a quake console
i3.on(Event.TICK, quake_console)
# Log output event
i3.on(Event.OUTPUT,
lambda _, event: logger.info(f"Output event: {event.ipc_data}"))
await i3.main()
if __name__ == "__main__": if __name__ == "__main__":
@ -182,25 +211,7 @@ if __name__ == "__main__":
setup_logging(options) setup_logging(options)
try: try:
i3 = Connection() asyncio.get_event_loop().run_until_complete(main(options))
# Rename workspace depending on what is inside
for event in {Event.WINDOW_MOVE,
Event.WINDOW_NEW,
Event.WINDOW_CLOSE}:
i3.on(event, workspace_rename)
# Create a new workspace or move to a new workspace
i3.on(Event.TICK, new_workspace)
# Create/display a quake console
i3.on(Event.TICK, quake_console)
# Log output event
i3.on(Event.OUTPUT,
lambda _, event: logger.info(f"Output event: {event.ipc_data}"))
i3.main()
except Exception as e: except Exception as e:
logger.exception("%s", e) logger.exception("%s", e)
sys.exit(1) sys.exit(1)