diff --git a/kitty/boss.py b/kitty/boss.py index 0e5c542ae..3e4b5e2d8 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -451,7 +451,12 @@ class Boss: w = tm.active_window if w is not None: w.focus_changed(focused) - tm.update_tab_bar() + tm.mark_tab_bar_dirty() + + def update_tab_bar_data(self, os_window_id): + tm = self.os_window_map.get(os_window_id) + if tm is not None: + tm.update_tab_bar_data() def on_drop(self, os_window_id, paths): tm = self.os_window_map.get(os_window_id) diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index d2d64d02b..df48857c5 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -572,6 +572,10 @@ prepare_to_render_os_window(OSWindow *os_window, double now, unsigned int *activ bool needs_render = os_window->needs_render; os_window->needs_render = false; if (TD.screen && os_window->num_tabs > 1) { + if (!os_window->tab_bar_data_updated) { + call_boss(update_tab_bar_data, "K", os_window->id); + os_window->tab_bar_data_updated = true; + } if (send_cell_data_to_gpu(TD.vao_idx, 0, TD.xstart, TD.ystart, TD.dx, TD.dy, TD.screen, os_window)) needs_render = true; } if (OPT(mouse_hide_wait) > 0 && now - os_window->last_mouse_activity_at > OPT(mouse_hide_wait)) hide_mouse(os_window); diff --git a/kitty/state.c b/kitty/state.c index 25a5190fb..aa8367a31 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -490,6 +490,14 @@ PYWRAP1(set_titlebar_color) { Py_RETURN_FALSE; } +PYWRAP1(mark_tab_bar_dirty) { + id_type os_window_id = PyLong_AsUnsignedLongLong(args); + WITH_OS_WINDOW(os_window_id) + os_window->tab_bar_data_updated = false; + END_WITH_OS_WINDOW + Py_RETURN_NONE; +} + static inline bool fix_window_idx(Tab *tab, id_type window_id, unsigned int *window_idx) { for (id_type fix = 0; fix < tab->num_windows; fix++) { @@ -615,6 +623,7 @@ static PyMethodDef module_methods[] = { MW(viewport_for_window, METH_VARARGS), MW(mark_os_window_for_close, METH_VARARGS), MW(set_titlebar_color, METH_VARARGS), + MW(mark_tab_bar_dirty, METH_O), MW(update_window_visibility, METH_VARARGS), MW(set_boss, METH_O), MW(set_display_state, METH_VARARGS), diff --git a/kitty/state.h b/kitty/state.h index 89243ade1..a72dac8d0 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -105,6 +105,7 @@ typedef struct { unsigned int active_tab, num_tabs, capacity, last_active_tab, last_num_tabs, last_active_window_id; bool focused_at_last_render, needs_render; ScreenRenderData tab_bar_render_data; + bool tab_bar_data_updated; bool is_focused; double cursor_blink_zero_time, last_mouse_activity_at; double mouse_x, mouse_y; diff --git a/kitty/tabs.py b/kitty/tabs.py index ca431bd6d..eba648812 100644 --- a/kitty/tabs.py +++ b/kitty/tabs.py @@ -11,9 +11,9 @@ from .child import Child from .config import build_ansi_color_table from .constants import WindowGeometry, appname, get_boss, is_macos, is_wayland from .fast_data_types import ( - DECAWM, Screen, add_tab, glfw_post_empty_event, remove_tab, remove_window, - set_active_tab, set_tab_bar_render_data, swap_tabs, viewport_for_window, - x11_window_id + DECAWM, Screen, add_tab, glfw_post_empty_event, mark_tab_bar_dirty, + remove_tab, remove_window, set_active_tab, set_tab_bar_render_data, + swap_tabs, viewport_for_window, x11_window_id ) from .layout import Rect, all_layouts from .session import resolved_shell @@ -89,7 +89,7 @@ class Tab: # {{{ tm = self.tab_manager_ref() if tm is not None: self.relayout_borders() - tm.update_tab_bar() + tm.mark_tab_bar_dirty() @property def active_window(self): @@ -103,19 +103,19 @@ class Tab: # {{{ self.name = title or '' tm = self.tab_manager_ref() if tm is not None: - tm.update_tab_bar() + tm.mark_tab_bar_dirty() def title_changed(self, window): if window is self.active_window: tm = self.tab_manager_ref() if tm is not None: - tm.update_tab_bar() + tm.mark_tab_bar_dirty() def on_bell(self, window): tm = self.tab_manager_ref() if tm is not None: self.relayout_borders() - tm.update_tab_bar() + tm.mark_tab_bar_dirty() def visible_windows(self): for w in self.windows: @@ -412,7 +412,6 @@ class TabManager: # {{{ for t in startup_session.tabs: self._add_tab(Tab(self, session_tab=t)) self._set_active_tab(max(0, min(startup_session.active_tab_idx, len(self.tabs) - 1))) - self.update_tab_bar() @property def active_tab_idx(self): @@ -464,21 +463,24 @@ class TabManager: # {{{ self.resize(only_tabs=True) glfw_post_empty_event() - def update_tab_bar(self): + def mark_tab_bar_dirty(self): if len(self.tabs) > 1: - self.tab_bar.update(self.tab_bar_data) + mark_tab_bar_dirty(self.os_window_id) + + def update_tab_bar_data(self): + self.tab_bar.update(self.tab_bar_data) def resize(self, only_tabs=False): if not only_tabs: self.tab_bar.layout() - self.update_tab_bar() + self.mark_tab_bar_dirty() for tab in self.tabs: tab.relayout() def set_active_tab_idx(self, idx): self._set_active_tab(idx) self.active_tab.relayout_borders() - self.update_tab_bar() + self.mark_tab_bar_dirty() def set_active_tab(self, tab): try: @@ -531,19 +533,19 @@ class TabManager: # {{{ self.tabs[idx], self.tabs[nidx] = self.tabs[nidx], self.tabs[idx] swap_tabs(self.os_window_id, idx, nidx) self._set_active_tab(nidx) - self.update_tab_bar() + self.mark_tab_bar_dirty() def new_tab(self, special_window=None, cwd_from=None): idx = len(self.tabs) self._add_tab(Tab(self, special_window=special_window, cwd_from=cwd_from)) self._set_active_tab(idx) - self.update_tab_bar() + self.mark_tab_bar_dirty() return self.tabs[idx] def remove(self, tab): self._remove_tab(tab) self._set_active_tab(max(0, min(self.active_tab_idx, len(self.tabs) - 1))) - self.update_tab_bar() + self.mark_tab_bar_dirty() tab.destroy() @property