import logging import os import signal import sys import threading import gi gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Gtk, Gdk, Adw, Gio, GLib from cht.config import APP_ID, APP_NAME from cht.window import ChtWindow class ChtApp(Adw.Application): def __init__(self): super().__init__( application_id=APP_ID, flags=Gio.ApplicationFlags.DEFAULT_FLAGS, ) # Let GLib handle SIGINT/SIGTERM so Ctrl+C triggers graceful shutdown GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, self._on_signal) GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, self._on_signal) def _on_signal(self): log = logging.getLogger("cht") log.info("Signal received — shutting down gracefully") self.quit() return GLib.SOURCE_REMOVE def do_shutdown(self): # Ensure all windows tear down before the process exits for win in self.get_windows(): if hasattr(win, "teardown"): win.teardown() Adw.Application.do_shutdown(self) def do_activate(self): win = self.props.active_window if not win: css = Gtk.CssProvider() css.load_from_string( ".frame-selected { outline: 3px solid @accent_color; outline-offset: -3px; border-radius: 6px; }\n" "row.frame-selected, row.frame-selected:hover { background: alpha(@accent_color, 0.25); outline: none; border-radius: 0; }\n" ".frame-highlight { outline: 2px solid @warning_color; outline-offset: -2px; border-radius: 4px; opacity: 0.9; }\n" "row.frame-highlight { background: alpha(@warning_color, 0.15); }" ) Gtk.StyleContext.add_provider_for_display( Gdk.Display.get_default(), css, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION, ) win = ChtWindow(application=self) win.present() _STDERR_SKIP = [b"eglExportDMABUFImage"] def _filter_stderr(): """Redirect fd 2 through a pipe; drop lines matching _STDERR_SKIP.""" real_stderr_fd = os.dup(2) real_stderr = os.fdopen(real_stderr_fd, "wb", buffering=0) r_fd, w_fd = os.pipe() os.dup2(w_fd, 2) os.close(w_fd) def _pump(): with os.fdopen(r_fd, "rb", buffering=0) as pipe: buf = b"" while True: chunk = pipe.read(4096) if not chunk: break buf += chunk while b"\n" in buf: line, buf = buf.split(b"\n", 1) if line.strip() and not any(skip in line for skip in _STDERR_SKIP): real_stderr.write(line + b"\n") real_stderr.flush() if buf: real_stderr.write(buf) real_stderr.flush() t = threading.Thread(target=_pump, daemon=True, name="stderr_filter") t.start() def main(): _filter_stderr() logging.basicConfig( level=logging.DEBUG, format="%(asctime)s %(levelname)-7s %(name)s: %(message)s", datefmt="%H:%M:%S", ) log = logging.getLogger("cht") log.info("CHT starting") app = ChtApp() return app.run(sys.argv) if __name__ == "__main__": main()