diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c6ff10a6c..d0665c2c4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,9 @@ kitty is a feature full, cross-platform, *fast*, GPU based terminal emulator. version 0.9.1 [future] ------------------------------ +- Show a bell on the tab if a bell occurs in one of the windows in the tab and + the window is not the currently focused window + - macOS: Add support for dead keys - Unicode input: When searching by name search for prefix matches as well as diff --git a/kitty/boss.py b/kitty/boss.py index fe0cbe231..0e5c542ae 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -451,6 +451,7 @@ class Boss: w = tm.active_window if w is not None: w.focus_changed(focused) + tm.update_tab_bar() def on_drop(self, os_window_id, paths): tm = self.os_window_map.get(os_window_id) diff --git a/kitty/screen.c b/kitty/screen.c index 2cd4fc6bc..f256ef6c7 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1077,6 +1077,7 @@ void screen_bell(Screen *self) { request_window_attention(self->window_id, OPT(enable_audio_bell)); if (OPT(visual_bell_duration) > 0.0f) self->start_visual_bell_at = monotonic(); + CALLBACK("on_bell", NULL); } void diff --git a/kitty/tabs.py b/kitty/tabs.py index 675da7f2c..399a5f5bf 100644 --- a/kitty/tabs.py +++ b/kitty/tabs.py @@ -20,7 +20,7 @@ from .session import resolved_shell from .utils import color_as_int, log_error from .window import Window, calculate_gl_geometry -TabbarData = namedtuple('TabbarData', 'title is_active is_last') +TabbarData = namedtuple('TabbarData', 'title is_active is_last needs_attention') SpecialWindowInstance = namedtuple('SpecialWindow', 'cmd stdin override_title cwd_from cwd overlay_for env') @@ -110,6 +110,11 @@ class Tab: # {{{ if tm is not None: tm.update_tab_bar() + def on_bell(self, window): + tm = self.tab_manager_ref() + if tm is not None: + tm.update_tab_bar() + def visible_windows(self): for w in self.windows: if w.is_visible_in_layout: @@ -310,6 +315,7 @@ class TabBar: # {{{ self.active_bg = as_rgb(color_as_int(opts.active_tab_background)) self.active_fg = as_rgb(color_as_int(opts.active_tab_foreground)) + self.bell_fg = as_rgb(0xff0000) def patch_colors(self, spec): if 'active_tab_foreground' in spec: @@ -353,10 +359,18 @@ class TabBar: # {{{ for t in data: s.cursor.bg = self.active_bg if t.is_active else 0 - s.cursor.fg = self.active_fg if t.is_active else 0 + s.cursor.fg = fg = self.active_fg if t.is_active else 0 s.cursor.bold, s.cursor.italic = self.active_font_style if t.is_active else self.inactive_font_style before = s.cursor.x - s.draw(' ' * self.leading_spaces + t.title + ' ' * self.trailing_spaces) + if self.leading_spaces: + s.draw(' ' * self.leading_spaces) + if t.needs_attention: + s.cursor.fg = self.bell_fg + s.draw('🔔 ') + s.cursor.fg = fg + s.draw(t.title) + if self.trailing_spaces: + s.draw(' ' * self.trailing_spaces) extra = s.cursor.x - before - max_title_length if extra > 0: s.cursor.x -= extra + 1 @@ -536,7 +550,12 @@ class TabManager: # {{{ ans = [] for t in self.tabs: title = (t.name or t.title or appname).strip() - ans.append(TabbarData(title, t is at, t is self.tabs[-1])) + needs_attention = False + for w in t: + if w.needs_attention: + needs_attention = True + break + ans.append(TabbarData(title, t is at, t is self.tabs[-1], needs_attention)) return ans def activate_tab_at(self, x): diff --git a/kitty/window.py b/kitty/window.py index 5537ab311..193a48f6a 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -90,6 +90,7 @@ class Window: def __init__(self, tab, child, opts, args, override_title=None): self.action_on_close = None + self.needs_attention = False self.override_title = override_title self.overlay_window_id = None self.overlay_for = None @@ -214,6 +215,7 @@ class Window: def focus_changed(self, focused): if focused: + self.needs_attention = False if self.screen.focus_tracking_enabled: self.screen.send_escape_code_to_child(CSI, 'I') else: @@ -228,6 +230,17 @@ class Window: def icon_changed(self, new_icon): pass # TODO: Implement this + @property + def is_active(self): + return get_boss().active_window is self + + def on_bell(self): + if not self.is_active: + self.needs_attention = True + tab = self.tabref() + if tab is not None: + tab.on_bell(self) + def change_titlebar_color(self): val = self.opts.macos_titlebar_color if val: