Compare commits

..

No commits in common. "ba5d560a010e979b0a45af847a5661f57850a211" and "c10b9fdb668be712630f76073ae385fdf213b749" have entirely different histories.

View file

@ -6,7 +6,6 @@ import collections.abc
import asyncio import asyncio
import signal import signal
import os import os
import time
import functools import functools
import json import json
@ -273,7 +272,7 @@ def parse(s: str) -> Expression:
tokens = tokenize(s) tokens = tokenize(s)
return build_expression(tokens) return build_expression(tokens)
def window_new(configs: list[dict], debug: bool, *, lock): def window_new(configs: list[dict], debug: bool):
async def callback(ipc: i3ipc.aio.Connection, e: i3ipc.WorkspaceEvent): async def callback(ipc: i3ipc.aio.Connection, e: i3ipc.WorkspaceEvent):
assert e.change == 'new' assert e.change == 'new'
if debug: if debug:
@ -283,11 +282,9 @@ def window_new(configs: list[dict], debug: bool, *, lock):
workspace = cfg['workspace'] workspace = cfg['workspace']
if filter.reduce(e.ipc_data): if filter.reduce(e.ipc_data):
container_id = e.ipc_data['container']['id'] container_id = e.ipc_data['container']['id']
async with lock: await ipc.command(f'for_window [con_id="{container_id}"] focus')
await ipc.command(f'for_window [con_id="{container_id}"] focus') await ipc.command(f'move container to workspace {workspace}')
await ipc.command(f'move container to workspace {workspace}') configs.pop(i)
await asyncio.sleep(1)
configs.pop(i)
if not configs: if not configs:
ipc.main_quit() ipc.main_quit()
return callback return callback
@ -298,49 +295,33 @@ async def wait_signal(s):
await event.wait() await event.wait()
event.clear() event.clear()
asyncio.get_running_loop().remove_signal_handler(s) asyncio.get_running_loop().remove_signal_handler(s)
asyncio.get_running_loop().add_signal_handler(s, lambda: None)
async def coro_wait_signal(coro, s):
await coro
await wait_signal(s)
async def run(configs: list[dict], *, timeout: int, debug: bool): async def run(configs: list[dict], *, timeout: int, debug: bool):
window_configs = [c for c in configs if c.get('workspace') is not None] window_configs = [c for c in configs if c.get('workspace') is not None]
lock = asyncio.Lock()
ipc = await i3ipc.aio.Connection().connect() # we only wait for configs which spawn a window ipc = await i3ipc.aio.Connection().connect() # we only wait for configs which spawn a window
ipc.on('window::new', window_new(window_configs, debug=debug, lock=lock)) ipc.on('window::new', window_new(window_configs, debug=debug))
variables = { variables = {
'pid': os.getpid(), 'pid': os.getpid(),
} }
coroutines = [] coroutines = []
timeouts = [timeout]
started_at = time.monotonic_ns()
for cfg in configs: for cfg in configs:
cfg['filter'] = parse(cfg['filter']) cfg['filter'] = parse(cfg['filter'])
p = cfg['program'] p = cfg['program']
t = cfg.get('timeout', timeout)
timeouts += [t]
if isinstance(p, collections.abc.Iterable) and not isinstance(p, str): if isinstance(p, collections.abc.Iterable) and not isinstance(p, str):
p = ' '.join(p) p = ' '.join(p)
p = p.format(**variables) p = p.format(**variables)
coro = ipc.command(f'exec {p}') coro = ipc.command(f'exec {p}')
if cfg.get('signal_continue', False): if cfg.get('signal_continue', False):
sig = signal.Signals(cfg.get('signal_continue')) await coro
coro = coro_wait_signal(coro, sig) await wait_signal(signal.Signals(cfg.get('signal_continue')))
try:
await asyncio.wait_for(coro, timeout=t/1000)
except asyncio.TimeoutError:
pass
else: else:
coroutines += [coro] coroutines += [coro]
await asyncio.gather(*coroutines) await asyncio.gather(*coroutines)
try: try:
if window_configs: if window_configs:
# run main loop only if we wait for something # run main loop only if we wait for something
diff = (time.monotonic_ns() - started_at) / (1000*1000) await asyncio.wait_for(ipc.main(), timeout=timeout/1000)
new_timeout = max(max(*timeouts) - diff, 0)
await asyncio.wait_for(ipc.main(), timeout=new_timeout/1000)
except asyncio.TimeoutError: except asyncio.TimeoutError:
return 1 return 1
return 0 return 0