Cleanup previous PR

This commit is contained in:
Kovid Goyal
2026-03-05 09:25:10 +05:30
parent b66703ec85
commit e1a14551fa
10 changed files with 45 additions and 80 deletions

View File

@@ -167,6 +167,9 @@ Detailed list of changes
- Allow dragging window borders to resize kitty windows in all the different
layouts, controlled by :opt:`window_drag_tolerance` (:pull:`9447`)
- Allow showing :opt:`configurable window titles <window_title_bar>` for individual kitty
windows via a window title bar (:pull:`9450`)
- A command palette to browse and trigger all mapped and unmapped actions
(:pull:`9545`)

View File

@@ -813,7 +813,7 @@ prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *
if (WD.screen->start_visual_bell_at != 0) needs_render = true;
// Prepare window title bar screen data for GPU
WindowRenderData *trd = &w->window_title_render_data;
if (trd->screen) {
if (trd->screen && trd->geometry.bottom > trd->geometry.top && trd->geometry.right > trd->geometry.left) {
trd->screen->cursor_render_info.is_visible = false;
if (send_cell_data_to_gpu(trd->vao_idx, trd->screen, os_window)) needs_render = true;
}
@@ -878,7 +878,7 @@ render_prepared_os_window(OSWindow *os_window, unsigned int active_window_id, co
draw_cells(&WD, os_window, is_active_window, false, num_of_visible_windows == 1, w);
if (WD.screen->start_visual_bell_at != 0) set_maximum_wait(ANIMATION_SAMPLE_WAIT);
WindowRenderData *trd = &w->window_title_render_data;
if (trd->screen && num_visible_windows > 1 && trd->geometry.right > trd->geometry.left && trd->geometry.bottom > trd->geometry.top)
if (trd->screen && trd->geometry.right > trd->geometry.left && trd->geometry.bottom > trd->geometry.top)
draw_cells(trd, os_window, i == tab->active_window, true, false, NULL);
}
}

View File

@@ -1389,6 +1389,9 @@ class Screen:
def insert_characters(self, num: int) -> None:
pass
def delete_characters(self, num: int) -> None: ...
def erase_characters(self, num: int) -> None: ...
def line_edge_colors(self) -> Tuple[int, int]:
pass

View File

@@ -369,13 +369,12 @@ class Layout:
self.update_visibility(all_windows)
self.blank_rects = []
# Set show_title_bar flag on each visible window before layout
opts = get_options()
min_windows = opts.window_title_bar_min_windows
visible_groups = list(all_windows.iter_all_layoutable_groups(only_visible=True))
num_visible = len(visible_groups)
min_windows = get_options().window_title_bar_min_windows
visible_groups = tuple(all_windows.iter_all_layoutable_groups(only_visible=True))
show_title_bar = min_windows > 0 and len(visible_groups) >= min_windows
for wg in visible_groups:
for w in wg.windows:
w.show_title_bar = min_windows > 0 and num_visible >= min_windows
w.show_title_bar = show_title_bar
self.do_layout(all_windows)
def layout_single_window_group(self, wg: WindowGroup, add_blank_rects: bool = True) -> None:

View File

@@ -1472,6 +1472,7 @@ opt('window_title_bar', 'top',
long_text='''
Control the position of the window title bar relative to the window content.
Use :opt:`window_title_bar_min_windows` to control when title bars are shown.
Use :opt:`window_title_template` to format the displayed window title.
'''
)

View File

@@ -1515,9 +1515,6 @@ class Parser:
choices_for_window_title_bar = frozenset(('top', 'bottom'))
def window_title_bar_min_windows(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['window_title_bar_min_windows'] = positive_int(val)
def window_title_bar_active_background(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['window_title_bar_active_background'] = to_color_or_none(val)
@@ -1538,6 +1535,9 @@ class Parser:
def window_title_bar_inactive_foreground(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['window_title_bar_inactive_foreground'] = to_color_or_none(val)
def window_title_bar_min_windows(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['window_title_bar_min_windows'] = positive_int(val)
def window_title_template(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['window_title_template'] = tab_title_template(val)

View File

@@ -501,12 +501,12 @@ option_names = (
'window_resize_step_cells',
'window_resize_step_lines',
'window_title_bar',
'window_title_bar_min_windows',
'window_title_bar_active_background',
'window_title_bar_active_foreground',
'window_title_bar_align',
'window_title_bar_inactive_background',
'window_title_bar_inactive_foreground',
'window_title_bar_min_windows',
'window_title_template',
)
@@ -702,12 +702,12 @@ class Options:
window_resize_step_cells: int = 2
window_resize_step_lines: int = 2
window_title_bar: choices_for_window_title_bar = 'top'
window_title_bar_min_windows: int = 0
window_title_bar_active_background: kitty.fast_data_types.Color | None = None
window_title_bar_active_foreground: kitty.fast_data_types.Color | None = None
window_title_bar_align: choices_for_window_title_bar_align = 'center'
window_title_bar_inactive_background: kitty.fast_data_types.Color | None = None
window_title_bar_inactive_foreground: kitty.fast_data_types.Color | None = None
window_title_bar_min_windows: int = 0
window_title_template: str = '{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.window}{progress_percent}{title}'
action_alias: dict[str, str] = {}
env: dict[str, str] = {}

View File

@@ -61,7 +61,6 @@ from .typing_compat import EdgeLiteral, SessionTab, SessionType, TypedDict
from .utils import cmdline_for_hold, color_as_int, log_error, platform_window_id, resolved_shell, shlex_split, which
from .window import CwdRequest, Watchers, Window, WindowCreationSpec, WindowDict, global_watchers
from .window_list import WindowList
from .window_title_bar import WindowTitleBarManager
P = ParamSpec('P')
T = TypeVar('T')
@@ -171,7 +170,6 @@ class Tab: # {{{
self.name = getattr(session_tab, 'name', '')
self.enabled_layouts = [x.lower() for x in getattr(session_tab, 'enabled_layouts', None) or get_options().enabled_layouts]
self.borders = Borders(self.os_window_id, self.id)
self.window_title_bar_manager = WindowTitleBarManager(self.os_window_id, self.id)
self.windows: WindowList = WindowList(self)
self._last_used_layout: str | None = None
self._current_layout_name: str | None = None
@@ -441,8 +439,15 @@ class Tab: # {{{
self.name = title or ''
self.mark_tab_bar_dirty()
def update_window_title_bars(self) -> None:
active_group = self.windows.active_group
for wg in self.windows.iter_all_layoutable_groups(only_visible=True):
is_active = wg is active_group
for w in wg.windows:
w.update_title_bar(is_active=is_active)
def title_changed(self, window: Window) -> None:
self.window_title_bar_manager.update(self.windows)
self.update_window_title_bars()
if window is self.active_window:
tm = self.tab_manager_ref()
if tm is not None:
@@ -471,7 +476,7 @@ class Tab: # {{{
current_layout=ly, tab_bar_rects=tm.tab_bar_rects,
draw_window_borders=draw_borders
)
self.window_title_bar_manager.update(self.windows)
self.update_window_title_bars()
def create_layout_object(self, name: str) -> Layout:
return create_layout_object_for(name, self.os_window_id, self.id)

View File

@@ -659,6 +659,7 @@ class Window:
creation_spec: WindowCreationSpec | None = None
created_in_session_name: str = ''
serialized_id: int = 0
show_title_bar: bool = False # must be set before calling set_geometry
@classmethod
@contextmanager
@@ -733,7 +734,6 @@ class Window:
self.tabref: Callable[[], TabType | None] = weakref.ref(tab)
self.destroyed = False
self.geometry: WindowGeometry = WindowGeometry(0, 0, 0, 0, 0, 0)
self.show_title_bar: bool = False
self._title_bar_screen: Any = None
self.needs_layout = True
self.is_visible_in_layout: bool = True
@@ -1029,8 +1029,8 @@ class Window:
# Handle title bar screen
if show_tb:
from .window_title_bar import WindowTitleBarScreen
if self._title_bar_screen is None:
from .window_title_bar import WindowTitleBarScreen
self._title_bar_screen = WindowTitleBarScreen(self.os_window_id, cell_width, cell_height)
tb_geom = WindowGeometry(
left=g.left, top=tb_top, right=g.right, bottom=tb_bottom,
@@ -1053,8 +1053,7 @@ class Window:
update_ime_position_for_window(self.id, True)
def update_title_bar(self, is_active: bool = False) -> None:
pts = self._title_bar_screen
if pts is None:
if (pts := self._title_bar_screen) is None:
return
from .progress import ProgressState
from .window_title_bar import WindowTitleData
@@ -1076,20 +1075,18 @@ class Window:
needs_attention=self.needs_attention,
has_activity_since_last_focus=has_activity,
)
rendered_title = pts.render(data, progress_percent)
# If template evaluates to empty string, zero title bar geometry to hide it
if not rendered_title:
set_window_title_bar_render_data(
self.os_window_id, self.tab_id, self.id, pts.screen,
0, 0, 0, 0,
)
else:
if pts.render(data, progress_percent):
g = pts.geometry
set_window_title_bar_render_data(
self.os_window_id, self.tab_id, self.id, pts.screen,
g.left, g.top, g.right, g.bottom,
)
else:
set_window_title_bar_render_data(
self.os_window_id, self.tab_id, self.id, pts.screen,
0, 0, 0, 0,
)
def close(self) -> None:
get_boss().mark_window_for_close(self)

View File

@@ -12,9 +12,9 @@ from .fast_data_types import (
get_options,
)
from .rgb import color_as_sgr, color_from_int, to_color
from .tab_bar import draw_attributed_string, safe_builtins
from .types import WindowGeometry, run_once
from .utils import color_as_int, log_error, sgr_sanitizer_pat
from .window_list import WindowList
from .utils import color_as_int, log_error
@lru_cache
@@ -30,12 +30,6 @@ def _compile_template(template: str) -> Any:
_report_template_failure(template, str(e))
safe_builtins = {
'max': max, 'min': min, 'str': str, 'repr': repr, 'abs': abs,
'len': len, 'chr': chr, 'ord': ord,
}
def _resolve_color(opt_val: Any, fallback_val: Any) -> Any:
if opt_val is None:
return fallback_val
@@ -85,17 +79,6 @@ class WindowTitleFormatter:
noitalic = '\x1b[23m'
def _draw_attributed_string(title: str, screen: Screen) -> None:
if '\x1b' in title:
for x in sgr_sanitizer_pat(for_splitting=True).split(title):
if x.startswith('\x1b') and x.endswith('m'):
screen.apply_sgr(x[2:-1])
else:
screen.draw(x)
else:
screen.draw(title)
class WindowTitleData(NamedTuple):
title: str
is_active: bool
@@ -199,45 +182,19 @@ class WindowTitleBarScreen:
align = opts.window_title_bar_align
if align == 'left':
_draw_attributed_string(title_str, s)
draw_attributed_string(title_str, s)
else:
# Measure the title length by drawing to cursor position 0
# and checking where the cursor ends up
_draw_attributed_string(title_str, s)
draw_attributed_string(title_str, s)
title_len = s.cursor.x
s.cursor.x = 0
s.erase_in_line(2, False)
s.cursor.fg = fg
s.cursor.bg = bg
if align == 'center':
pad = max(0, (s.columns - title_len) // 2)
else: # right
pad = max(0, s.columns - title_len)
for _ in range(pad):
s.draw(' ')
_draw_attributed_string(title_str, s)
# Fill remaining cells with background
while s.cursor.x < s.columns:
s.draw(' ')
if pad:
s.cursor.x = 0
s.insert_characters(pad)
s.cursor.x = 0
s.erase_characters(pad)
return title_str
class WindowTitleBarManager:
def __init__(self, os_window_id: int, tab_id: int):
self.os_window_id = os_window_id
self.tab_id = tab_id
def update(self, all_windows: WindowList) -> None:
active_group = all_windows.active_group
for wg in all_windows.iter_all_layoutable_groups(only_visible=True):
is_active = wg is active_group
for w in wg.windows:
w.update_title_bar(is_active=is_active)
def destroy(self) -> None:
pass