From 767c63ec322b9c76c743f0770d8cb23b7ffa67f3 Mon Sep 17 00:00:00 2001 From: David Vazgenovich Shakaryan Date: Sun, 18 Jan 2026 14:31:43 -0800 Subject: gracefully handle lemonbar crashes --- panel.py | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/panel.py b/panel.py index 8885d4f..854d57d 100755 --- a/panel.py +++ b/panel.py @@ -551,10 +551,7 @@ class Panel: if mod := self.mod_by_id.get(int(mod_id)): mod.process_cmd(cmd) - def run(self): - for mod in self.mods: - mod.run() - + def spawn_panel(self): self.panel = subprocess.Popen( ('/home/david/dev/lemonbar-xft/lemonbar', '-f', 'Monospace:size=10:dpi=96', @@ -567,12 +564,31 @@ class Panel: stdout=subprocess.PIPE, text=True) + # closed pipe terminates thread via EOF when panel dies threading.Thread( target=self.process_cmds, args=(self.panel.stdout,), daemon=True ).start() + def respawn_panel(self): + # silence _io.TextIOWrapper exceptions + for pipe in (self.panel.stdin, self.panel.stdout): + try: + pipe.close() + except BrokenPipeError: + pass + + self.panel.kill() + self.panel.wait() + self.spawn_panel() + + def run(self): + for mod in self.mods: + mod.run() + + self.spawn_panel() + while True: self.e_repaint.wait() self.e_repaint.clear() @@ -585,9 +601,17 @@ class Panel: if self.e_flush.is_set(): break self.e_flush.clear() - print( - ''.join([s for m in self.mods if (s := m.to_paint())]), - file=self.panel.stdin, flush=True) + out = ''.join([s for m in self.mods if (s := m.to_paint())]) + + # sometimes lemonbar crashes with X error BadIDChoice, resulting in + # BrokenPipeError on print. when this happens, we spawn a new panel + # process and trigger a repaint. + try: + print(out, file=self.panel.stdin, flush=True) + except BrokenPipeError: + self.respawn_panel() + self.e_repaint.set() + self.e_flush.set() Panel( ModHLWMTags(spacing=0), -- cgit v1.2.3-70-g09d2