Add window_title_bar_min_windows option, simplify window_title_bar

- Add window_title_bar_min_windows (0=never, 1=always, 2+=threshold)
  similar to tab_bar_min_tabs, to control when title bars appear
- Remove 'none' choice from window_title_bar so it purely controls
  position (top/bottom); disabling is now via min_windows 0
- Only hide title bar for truly empty template strings, not
  whitespace-only, so users can have intentionally blank bars

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
mcrmck 2026-03-04 21:14:54 -05:00
parent dd26469cb3
commit f2ae5d0028
5 changed files with 26 additions and 13 deletions

View file

@ -369,12 +369,12 @@ def __call__(self, all_windows: WindowList) -> None:
self.blank_rects = []
# Set show_title_bar flag on each visible window before layout
opts = get_options()
title_bar_enabled = opts.window_title_bar != 'none'
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)
for wg in visible_groups:
for w in wg.windows:
w.show_title_bar = title_bar_enabled and num_visible > 1
w.show_title_bar = min_windows > 0 and num_visible >= min_windows
self.do_layout(all_windows)
def layout_single_window_group(self, wg: WindowGroup, add_blank_rects: bool = True) -> None:

View file

@ -1467,16 +1467,24 @@
in multiple windows getting resized.
''')
opt('window_title_bar', 'none',
choices=('none', 'top', 'bottom'),
opt('window_title_bar', 'top',
choices=('top', 'bottom'),
long_text='''
Show a title bar for each window when there are multiple windows in a tab.
The title bar displays the window title and is hidden when only a single window
is visible. The value controls the position of the title bar relative to the
window content. Set to :code:`none` to disable.
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.
'''
)
opt('window_title_bar_min_windows', '0',
option_type='positive_int',
long_text='''
The minimum number of visible windows in a tab before window title bars
are shown. A value of :code:`0` means never show. :code:`1` means always
show. :code:`2` or more means show only when at least that many windows
are visible. Similar to :opt:`tab_bar_min_tabs` for the tab bar.
'''
)
opt('window_title_template', '"{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.window}{progress_percent}{title}"',
option_type='tab_title_template',
long_text='''

View file

@ -1513,7 +1513,10 @@ def window_title_bar(self, val: str, ans: dict[str, typing.Any]) -> None:
raise ValueError(f"The value {val} is not a valid choice for window_title_bar")
ans["window_title_bar"] = val
choices_for_window_title_bar = frozenset(('none', 'top', 'bottom'))
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)

View file

@ -37,7 +37,7 @@
choices_for_undercurl_style = typing.Literal['thin-sparse', 'thin-dense', 'thick-sparse', 'thick-dense']
choices_for_underline_hyperlinks = typing.Literal['hover', 'always', 'never']
choices_for_window_logo_position = choices_for_placement_strategy
choices_for_window_title_bar = typing.Literal['none', 'top', 'bottom']
choices_for_window_title_bar = typing.Literal['top', 'bottom']
choices_for_window_title_bar_align = choices_for_tab_bar_align
option_names = (
@ -501,6 +501,7 @@
'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',
@ -700,7 +701,8 @@ class Options:
window_padding_width: FloatEdges = FloatEdges(left=0, top=0, right=0, bottom=0)
window_resize_step_cells: int = 2
window_resize_step_lines: int = 2
window_title_bar: choices_for_window_title_bar = 'none'
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'

View file

@ -1078,8 +1078,8 @@ def update_title_bar(self, is_active: bool = False) -> None:
)
rendered_title = pts.render(data, progress_percent)
# If template evaluates to empty/whitespace, zero title bar geometry to hide it
if not rendered_title or not rendered_title.strip():
# 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,