From ea9afc6e89278de431a2f4658721eedae6ebcf35 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 23 Jan 2025 05:36:25 +0530 Subject: [PATCH] watchers: Add a new event on_color_scheme_preference_change Fixes #8246 --- docs/changelog.rst | 2 ++ docs/launch.rst | 7 +++++++ kitty/launch.py | 3 +++ kitty/window.py | 17 ++++++++++++++--- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 8463e37fe..918268f24 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -93,6 +93,8 @@ Detailed list of changes - Wayland niri: Fix 250ms delay on startup when using scale 1 (:iss:`8236`) +- :ref:`Watchers `: Add a new event ``on_color_scheme_preference_change`` (:iss:`8246`) + 0.39.0 [2025-01-16] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/launch.rst b/docs/launch.rst index 952754187..b3f7f0d5a 100644 --- a/docs/launch.rst +++ b/docs/launch.rst @@ -168,6 +168,13 @@ create :file:`~/.config/kitty/mywatcher.py` and use :option:`launch --watcher` = # data will contain is_start, cmdline and time. ... + def on_color_scheme_preference_change(boss: Boss, window: Window, data: dict[str, Any]) -> None: + # called when the color scheme preference of this window changes from + # light to dark or vice versa. data contains is_dark and via_escape_code + # the latter will be true if the color scheme was changed via escape + # code received from the program running in the window + ... + Every callback is passed a reference to the global ``Boss`` object as well as the ``Window`` object the action is occurring on. The ``data`` object is a dict that contains event dependent data. You have full access to kitty internals in diff --git a/kitty/launch.py b/kitty/launch.py index eba8898c5..849975e1a 100644 --- a/kitty/launch.py +++ b/kitty/launch.py @@ -460,6 +460,9 @@ def load_watch_modules(watchers: Iterable[str]) -> Optional[Watchers]: w = m.get('on_cmd_startstop') if callable(w): ans.on_cmd_startstop.append(w) + w = m.get('on_color_scheme_preference_change') + if callable(w): + ans.on_color_scheme_preference_change.append(w) return ans diff --git a/kitty/window.py b/kitty/window.py index 92e9f42b5..4194434f8 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -294,6 +294,7 @@ class Watchers: on_set_user_var: list[Watcher] on_title_change: list[Watcher] on_cmd_startstop: list[Watcher] + on_color_scheme_preference_change: list[Watcher] def __init__(self) -> None: self.on_resize = [] @@ -302,6 +303,7 @@ class Watchers: self.on_set_user_var = [] self.on_title_change = [] self.on_cmd_startstop = [] + self.on_color_scheme_preference_change = [] def add(self, others: 'Watchers') -> None: def merge(base: list[Watcher], other: list[Watcher]) -> None: @@ -314,10 +316,12 @@ class Watchers: merge(self.on_set_user_var, others.on_set_user_var) merge(self.on_title_change, others.on_title_change) merge(self.on_cmd_startstop, others.on_cmd_startstop) + merge(self.on_color_scheme_preference_change, others.on_color_scheme_preference_change) def clear(self) -> None: del self.on_close[:], self.on_resize[:], self.on_focus_change[:] del self.on_set_user_var[:], self.on_title_change[:], self.on_cmd_startstop[:] + del self.on_color_scheme_preference_change[:] def copy(self) -> 'Watchers': ans = Watchers() @@ -327,11 +331,12 @@ class Watchers: ans.on_set_user_var = self.on_set_user_var[:] ans.on_title_change = self.on_title_change[:] ans.on_cmd_startstop = self.on_cmd_startstop[:] + ans.on_color_scheme_preference_change = self.on_color_scheme_preference_change[:] return ans @property def has_watchers(self) -> bool: - return bool(self.on_close or self.on_resize or self.on_focus_change + return bool(self.on_close or self.on_resize or self.on_focus_change or self.on_color_scheme_preference_change or self.on_set_user_var or self.on_title_change or self.on_cmd_startstop) @@ -1343,13 +1348,19 @@ class Window: if default_bg_changed: get_boss().default_bg_changed_for(self.id, via_escape_code=True) + @property + def is_dark(self) -> bool: + return self.screen.color_profile.default_bg.is_dark + def on_color_scheme_preference_change(self, via_escape_code: bool = False) -> None: if self.screen.color_preference_notification and not via_escape_code: self.report_color_scheme_preference() + self.call_watchers(self.watchers.on_color_scheme_preference_change, { + 'is_dark': self.is_dark, 'via_escape_code': via_escape_code + }) def report_color_scheme_preference(self) -> None: - cp = self.screen.color_profile - n = 1 if cp.default_bg.is_dark else 2 + n = 1 if self.is_dark else 2 self.screen.send_escape_code_to_child(ESC_CSI, f'?997;{n}n') def set_color_table_color(self, code: int, bvalue: Optional[memoryview] = None) -> None: