From 465c2347cba176802755b68335f75ad26dedc000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geoffrey=20=E2=80=9CFrogeye=E2=80=9D=20Preud=27homme?= Date: Wed, 17 Dec 2025 10:01:57 +0100 Subject: [PATCH] frobar: Gracefully handle zelbar exists Before it would just spam logs with "Unknown command: " --- hm/desktop/frobar/default.nix | 4 +- hm/desktop/frobar/frobar/common.py | 80 +++++++++++++++++------------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/hm/desktop/frobar/default.nix b/hm/desktop/frobar/default.nix index 8b98690..e9e6104 100644 --- a/hm/desktop/frobar/default.nix +++ b/hm/desktop/frobar/default.nix @@ -1,7 +1,7 @@ { zelbarnixpkgs ? builtins.getFlake "github:wlcx/nixpkgs/zelbar", - # nixpkgs ? , - nixpkgs ? builtins.getFlake "nixpkgs/nixos-25.11", + nixpkgs ? , + # nixpkgs ? builtins.getFlake "nixpkgs/nixos-25.11", pkgs ? import nixpkgs { overlays = [ (self: super: { diff --git a/hm/desktop/frobar/frobar/common.py b/hm/desktop/frobar/frobar/common.py index 235d552..a7fa66e 100644 --- a/hm/desktop/frobar/frobar/common.py +++ b/hm/desktop/frobar/frobar/common.py @@ -4,7 +4,6 @@ import datetime import enum import logging import signal -import sys import typing import gi @@ -361,39 +360,51 @@ class Screen(ComposableText): self.output, ] print(" ".join(cmd)) - proc = await asyncio.create_subprocess_exec( - *cmd, - stdout=asyncio.subprocess.PIPE, - stdin=asyncio.subprocess.PIPE, - ) + loop = asyncio.get_running_loop() + while True: + last_start_time = loop.time() + proc = await asyncio.create_subprocess_exec( + *cmd, + stdout=asyncio.subprocess.PIPE, + stdin=asyncio.subprocess.PIPE, + ) - async def refresher() -> None: - assert proc.stdin - while True: - await self.refresh.wait() - self.refresh.clear() - markup = self.get_markup() - # sys.stdout.write(markup) # DEBUG - proc.stdin.write(markup.encode()) + async def refresher(proc: asyncio.subprocess.Process) -> None: + assert proc.stdin + while proc.returncode is None: + markup = self.get_markup() + # sys.stdout.write(markup) # DEBUG + proc.stdin.write(markup.encode()) + await self.refresh.wait() + self.refresh.clear() - async def action_handler() -> None: - assert proc.stdout - while True: - line = await proc.stdout.readline() - try: - command = line.decode().strip() - except UnicodeDecodeError: - # FIXME zelbar seems to have some memory issues - log.exception("Not unicode: %s", str(line)) - continue - callback = self.actions.get(command) - if callback is None: - log.error("Unknown command: %s", command) - continue - callback() + async def action_handler(proc: asyncio.subprocess.Process) -> None: + assert proc.stdout + while proc.returncode is None: + line = await proc.stdout.readline() + try: + command = line.decode().strip() + except UnicodeDecodeError: + # TODO zelbar seems to have some memory issues + log.exception("Not unicode: %s", str(line)) + continue + callback = self.actions.get(command) + if callback is None: + log.error("Unknown command: %s", command) + continue + callback() - self.bar.add_long_running_task(refresher()) - self.bar.add_long_running_task(action_handler()) + refresher_task = self.bar.add_long_running_task(refresher(proc)) + action_handler_task = self.bar.add_long_running_task(action_handler(proc)) + + await proc.wait() + log.error("zelbar exited with code %d", proc.returncode) + refresher_task.cancel() + action_handler_task.cancel() + + # Delay restart if it's been less than 5 seconds to prevent infinite loops + time_since_start = loop.time() - last_start_time + await asyncio.sleep(max(0, 5 - time_since_start)) def add_action(self, callback: typing.Callable) -> str: command = f"com{self.actionIndex:x}" @@ -434,14 +445,15 @@ class Bar(ComposableText): continue Screen(parent=self, output=output.name) - def add_long_running_task(self, coro: typing.Coroutine) -> None: + def add_long_running_task(self, coro: typing.Coroutine) -> asyncio.Task: task = self.taskGroup.create_task(coro) self.longRunningTasks.append(task) + return task async def run(self) -> None: async with self.taskGroup: for screen in self.children: - await screen.run() + self.add_long_running_task(screen.run()) for provider in self.providers: self.add_long_running_task(provider.run()) @@ -630,7 +642,7 @@ class PeriodicProvider(Provider): while True: # TODO Block bar update during the periodic update of the loops loops = [provider.loop() for provider in providers] - asyncio.gather(*loops) + await asyncio.gather(*loops) now = datetime.datetime.now(datetime.UTC) # Hardcoded to 1 second... not sure if we want some more than that,