Code to allow users to create dark and light themes that are automatically applied when the OS color scheme changes
This commit is contained in:
parent
36074eabc8
commit
e485b3b4a3
3 changed files with 67 additions and 10 deletions
|
|
@ -36,6 +36,7 @@
|
|||
set_clipboard_string,
|
||||
set_primary_selection,
|
||||
)
|
||||
from .colors import ColorsSpec, TransparentBackgroundColors, patch_options_with_color_spec, theme_colors
|
||||
from .conf.utils import BadLine, KeyAction, to_cmdline
|
||||
from .config import common_opts_as_dict, prepare_config_file_for_editing
|
||||
from .constants import (
|
||||
|
|
@ -2637,10 +2638,9 @@ def disable_ligatures_in(self, where: Union[str, Iterable[Window]], strategy: in
|
|||
window.screen.disable_ligatures = strategy
|
||||
window.refresh()
|
||||
|
||||
def patch_colors(self, spec: dict[str, Optional[int]], transparent_background_colors: tuple[tuple[Color, float], ...], configured: bool = False) -> None:
|
||||
def patch_colors(self, spec: ColorsSpec, transparent_background_colors: TransparentBackgroundColors, configured: bool = False) -> None:
|
||||
opts = get_options()
|
||||
if configured:
|
||||
from kitty.colors import patch_options_with_color_spec
|
||||
patch_options_with_color_spec(opts, spec, transparent_background_colors)
|
||||
for tm in self.all_tab_managers:
|
||||
tm.tab_bar.patch_colors(spec)
|
||||
|
|
@ -3063,10 +3063,8 @@ def sanitize_url_for_dispay_to_user(self, url: str) -> str:
|
|||
return sanitize_url_for_dispay_to_user(url)
|
||||
|
||||
def on_system_color_scheme_change(self, appearance: Literal['light', 'dark', 'no_preference'], is_initial_value: bool) -> None:
|
||||
if is_initial_value:
|
||||
pass
|
||||
else:
|
||||
log_error('system color theme changed:', appearance)
|
||||
if not is_initial_value and appearance != 'no_preference':
|
||||
theme_colors.on_system_color_scheme_change(appearance)
|
||||
|
||||
@ac('win', '''
|
||||
Toggle to the tab matching the specified expression
|
||||
|
|
|
|||
|
|
@ -2,15 +2,71 @@
|
|||
# License: GPLv3 Copyright: 2024, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import os
|
||||
from typing import Iterable, Optional, Union
|
||||
from contextlib import suppress
|
||||
from typing import Iterable, Literal, Optional, Union
|
||||
|
||||
from .config import parse_config
|
||||
from .fast_data_types import Color
|
||||
from .constants import config_dir
|
||||
from .fast_data_types import Color, get_boss, glfw_get_system_color_theme
|
||||
from .options.types import Options, nullable_colors
|
||||
from .rgb import color_from_int
|
||||
|
||||
ColorsSpec = dict[str, Optional[int]]
|
||||
TransparentBackgroundColors = tuple[tuple[Color, float], ...]
|
||||
|
||||
def parse_colors(args: Iterable[Union[str, Iterable[str]]]) -> tuple[dict[str, Optional[int]], tuple[tuple[Color, float], ...]]:
|
||||
|
||||
class ThemeColors:
|
||||
|
||||
dark_mtime: float = -1
|
||||
light_mtime: float = -1
|
||||
applied_theme: Literal['light', 'dark', ''] = ''
|
||||
|
||||
def refresh(self) -> None:
|
||||
with suppress(FileNotFoundError), open(os.path.join(config_dir, 'dark-theme.conf')) as f:
|
||||
mtime = os.stat(f.fileno()).st_mtime
|
||||
if mtime > self.dark_mtime:
|
||||
self.dark_spec, self.dark_tbc = parse_colors((f,))
|
||||
self.dark_mtime = mtime
|
||||
with suppress(FileNotFoundError), open(os.path.join(config_dir, 'light-theme.conf')) as f:
|
||||
mtime = os.stat(f.fileno()).st_mtime
|
||||
if mtime > self.light_mtime:
|
||||
self.light_spec, self.light_tbc = parse_colors((f,))
|
||||
self.light_mtime = mtime
|
||||
|
||||
@property
|
||||
def has_dark_theme(self) -> bool:
|
||||
return self.dark_mtime > -1
|
||||
|
||||
@property
|
||||
def has_light_theme(self) -> bool:
|
||||
return self.light_mtime > -1
|
||||
|
||||
def patch_opts(self, opts: Options) -> None:
|
||||
which = glfw_get_system_color_theme()
|
||||
if which == 'dark' and self.has_dark_theme:
|
||||
patch_options_with_color_spec(opts, self.dark_spec, self.dark_tbc)
|
||||
self.applied_theme = 'dark'
|
||||
elif which == 'light' and self.has_light_theme:
|
||||
patch_options_with_color_spec(opts, self.light_spec, self.light_tbc)
|
||||
self.applied_theme = 'light'
|
||||
|
||||
def on_system_color_scheme_change(self, new_value: Literal['light', 'dark']) -> bool:
|
||||
boss = get_boss()
|
||||
if new_value == 'dark' and self.has_dark_theme:
|
||||
boss.patch_colors(self.dark_spec, self.dark_tbc, True)
|
||||
self.applied_theme = 'dark'
|
||||
return True
|
||||
if new_value == 'light' and self.has_light_theme:
|
||||
boss.patch_colors(self.light_spec, self.light_tbc, True)
|
||||
self.applied_theme = 'light'
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
theme_colors = ThemeColors()
|
||||
|
||||
|
||||
def parse_colors(args: Iterable[Union[str, Iterable[str]]]) -> tuple[ColorsSpec, TransparentBackgroundColors]:
|
||||
colors: dict[str, Optional[Color]] = {}
|
||||
nullable_color_map: dict[str, Optional[int]] = {}
|
||||
transparent_background_colors = ()
|
||||
|
|
@ -35,7 +91,7 @@ def parse_colors(args: Iterable[Union[str, Iterable[str]]]) -> tuple[dict[str, O
|
|||
return ans, transparent_background_colors
|
||||
|
||||
|
||||
def patch_options_with_color_spec(opts: Options, spec: dict[str, Optional[int]], transparent_background_colors: tuple[tuple[Color, float], ...]) -> None:
|
||||
def patch_options_with_color_spec(opts: Options, spec: ColorsSpec, transparent_background_colors: TransparentBackgroundColors) -> None:
|
||||
|
||||
for k, v in spec.items():
|
||||
if hasattr(opts, k):
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
from .child import set_default_env, set_LANG_in_default_env
|
||||
from .cli import create_opts, parse_args
|
||||
from .cli_stub import CLIOptions
|
||||
from .colors import theme_colors
|
||||
from .conf.utils import BadLine
|
||||
from .config import cached_values_for
|
||||
from .constants import (
|
||||
|
|
@ -248,6 +249,8 @@ def __init__(self) -> None:
|
|||
def __call__(self, opts: Options, args: CLIOptions, bad_lines: Sequence[BadLine] = (), talk_fd: int = -1) -> None:
|
||||
set_scale(opts.box_drawing_scale)
|
||||
set_options(opts, is_wayland(), args.debug_rendering, args.debug_font_fallback)
|
||||
theme_colors.refresh()
|
||||
theme_colors.patch_opts(opts)
|
||||
try:
|
||||
set_font_family(opts, add_builtin_nerd_font=True)
|
||||
_run_app(opts, args, bad_lines, talk_fd)
|
||||
|
|
|
|||
Loading…
Reference in a new issue