Rename pane → window title bar per reviewer feedback

- Rename all options from pane_title_* to window_title_*
- Use foreground/background instead of fg/bg in color option names
- Change color options to to_color_or_none defaulting to None,
  falling back to corresponding tab bar colors
- Add bell_symbol, activity_symbol, progress_percent template vars
  using existing bell_on_tab and tab_activity_symbol options
- Add custom script support via window_title_bar.py in config dir
  (draw_window_title function exposed as {custom} in templates)
- Update C structs, Python references, and regenerate config files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
mcrmck
2026-02-01 11:00:06 -05:00
parent ab3a8ca56a
commit cc32af250b
13 changed files with 593 additions and 436 deletions

View File

@@ -1467,57 +1467,71 @@ actually resize the window itself, but instead, the layout row/column/slot, whic
in multiple windows getting resized.
''')
opt('pane_title_bar', 'none',
opt('window_title_bar', 'none',
choices=('none', 'top', 'bottom'),
long_text='''
Show a title bar for each window/pane when there are multiple windows in a tab.
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.
'''
)
opt('pane_title_template', '"{title}"',
opt('window_title_template', '"{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.window}{progress_percent}{title}"',
option_type='tab_title_template',
long_text='''
A template to render the pane title bar text. Uses the same template syntax as
A template to render the window title bar text. Uses the same template syntax as
:opt:`tab_title_template`. Available variables include: :code:`{title}`,
:code:`{index}`, :code:`{layout_name}`, :code:`{num_windows}`,
:code:`{num_window_groups}`, :code:`{tab.active_wd}`, etc.
:code:`{bell_symbol}`, :code:`{activity_symbol}`, :code:`{progress_percent}`,
:code:`{custom}`, :code:`{fmt}`, :code:`{is_active}`.
You can also provide a custom :code:`draw_window_title(data)` function in
:file:`window_title_bar.py` in the kitty config directory, exposed as :code:`{custom}`.
'''
)
opt('active_pane_title_template', 'none',
opt('active_window_title_template', 'none',
option_type='tab_title_template',
long_text='''
Template to use for the active pane title bar. If not set (the value
:code:`none`), the :opt:`pane_title_template` is used.
Template to use for the active window title bar. If not set (the value
:code:`none`), the :opt:`window_title_template` is used.
'''
)
opt('pane_title_bar_active_fg', '#000000',
option_type='to_color',
long_text='Foreground color for the active pane title bar.'
opt('window_title_bar_active_foreground', 'none',
option_type='to_color_or_none', ctype='color_or_none_as_int',
long_text='''
Foreground color for the active window title bar. Defaults to
:opt:`active_tab_foreground` when set to :code:`none`.
'''
)
opt('pane_title_bar_active_bg', '#00ff00',
option_type='to_color',
long_text='Background color for the active pane title bar.'
opt('window_title_bar_active_background', 'none',
option_type='to_color_or_none', ctype='color_or_none_as_int',
long_text='''
Background color for the active window title bar. Defaults to
:opt:`active_tab_background` when set to :code:`none`.
'''
)
opt('pane_title_bar_inactive_fg', '#cccccc',
option_type='to_color',
long_text='Foreground color for inactive pane title bars.'
opt('window_title_bar_inactive_foreground', 'none',
option_type='to_color_or_none', ctype='color_or_none_as_int',
long_text='''
Foreground color for inactive window title bars. Defaults to
:opt:`inactive_tab_foreground` when set to :code:`none`.
'''
)
opt('pane_title_bar_inactive_bg', '#333333',
option_type='to_color',
long_text='Background color for inactive pane title bars.'
opt('window_title_bar_inactive_background', 'none',
option_type='to_color_or_none', ctype='color_or_none_as_int',
long_text='''
Background color for inactive window title bars. Defaults to
:opt:`inactive_tab_background` when set to :code:`none`.
'''
)
opt('pane_title_bar_align', 'center',
opt('window_title_bar_align', 'center',
choices=('left', 'center', 'right'),
long_text='Horizontal alignment of the text in pane title bars.'
long_text='Horizontal alignment of the text in window title bars.'
)
egr() # }}}

70
kitty/options/parse.py generated
View File

@@ -36,9 +36,6 @@ class Parser:
def active_border_color(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['active_border_color'] = to_color_or_none(val)
def active_pane_title_template(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['active_pane_title_template'] = tab_title_template(val)
def active_tab_background(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['active_tab_background'] = to_color(val)
@@ -51,6 +48,9 @@ class Parser:
def active_tab_title_template(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['active_tab_title_template'] = active_tab_title_template(val)
def active_window_title_template(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['active_window_title_template'] = tab_title_template(val)
def allow_cloning(self, val: str, ans: dict[str, typing.Any]) -> None:
val = val.lower()
if val not in self.choices_for_allow_cloning:
@@ -1168,37 +1168,6 @@ class Parser:
def open_url_with(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['open_url_with'] = to_cmdline(val)
def pane_title_bar(self, val: str, ans: dict[str, typing.Any]) -> None:
val = val.lower()
if val not in self.choices_for_pane_title_bar:
raise ValueError(f"The value {val} is not a valid choice for pane_title_bar")
ans["pane_title_bar"] = val
choices_for_pane_title_bar = frozenset(('none', 'top', 'bottom'))
def pane_title_bar_active_bg(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['pane_title_bar_active_bg'] = to_color(val)
def pane_title_bar_active_fg(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['pane_title_bar_active_fg'] = to_color(val)
def pane_title_bar_align(self, val: str, ans: dict[str, typing.Any]) -> None:
val = val.lower()
if val not in self.choices_for_pane_title_bar_align:
raise ValueError(f"The value {val} is not a valid choice for pane_title_bar_align")
ans["pane_title_bar_align"] = val
choices_for_pane_title_bar_align = frozenset(('left', 'center', 'right'))
def pane_title_bar_inactive_bg(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['pane_title_bar_inactive_bg'] = to_color(val)
def pane_title_bar_inactive_fg(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['pane_title_bar_inactive_fg'] = to_color(val)
def pane_title_template(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['pane_title_template'] = tab_title_template(val)
def paste_actions(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['paste_actions'] = paste_actions(val)
@@ -1356,7 +1325,7 @@ class Parser:
raise ValueError(f"The value {val} is not a valid choice for tab_bar_align")
ans["tab_bar_align"] = val
choices_for_tab_bar_align = choices_for_pane_title_bar_align
choices_for_tab_bar_align = frozenset(('left', 'center', 'right'))
def tab_bar_background(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['tab_bar_background'] = to_color_or_none(val)
@@ -1538,6 +1507,37 @@ class Parser:
def window_resize_step_lines(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['window_resize_step_lines'] = positive_int(val)
def window_title_bar(self, val: str, ans: dict[str, typing.Any]) -> None:
val = val.lower()
if val not in self.choices_for_window_title_bar:
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'))
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)
def window_title_bar_active_foreground(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['window_title_bar_active_foreground'] = to_color_or_none(val)
def window_title_bar_align(self, val: str, ans: dict[str, typing.Any]) -> None:
val = val.lower()
if val not in self.choices_for_window_title_bar_align:
raise ValueError(f"The value {val} is not a valid choice for window_title_bar_align")
ans["window_title_bar_align"] = val
choices_for_window_title_bar_align = choices_for_tab_bar_align
def window_title_bar_inactive_background(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['window_title_bar_inactive_background'] = to_color_or_none(val)
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_template(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['window_title_template'] = tab_title_template(val)
def x11_hide_window_decorations(self, val: str, ans: dict[str, typing.Any]) -> None:
deprecated_hide_window_decorations_aliases('x11_hide_window_decorations', val, ans)

View File

@@ -993,6 +993,58 @@ convert_from_opts_window_drag_tolerance(PyObject *py_opts, Options *opts) {
Py_DECREF(ret);
}
static void
convert_from_python_window_title_bar_active_foreground(PyObject *val, Options *opts) {
opts->window_title_bar_active_foreground = color_or_none_as_int(val);
}
static void
convert_from_opts_window_title_bar_active_foreground(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "window_title_bar_active_foreground");
if (ret == NULL) return;
convert_from_python_window_title_bar_active_foreground(ret, opts);
Py_DECREF(ret);
}
static void
convert_from_python_window_title_bar_active_background(PyObject *val, Options *opts) {
opts->window_title_bar_active_background = color_or_none_as_int(val);
}
static void
convert_from_opts_window_title_bar_active_background(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "window_title_bar_active_background");
if (ret == NULL) return;
convert_from_python_window_title_bar_active_background(ret, opts);
Py_DECREF(ret);
}
static void
convert_from_python_window_title_bar_inactive_foreground(PyObject *val, Options *opts) {
opts->window_title_bar_inactive_foreground = color_or_none_as_int(val);
}
static void
convert_from_opts_window_title_bar_inactive_foreground(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "window_title_bar_inactive_foreground");
if (ret == NULL) return;
convert_from_python_window_title_bar_inactive_foreground(ret, opts);
Py_DECREF(ret);
}
static void
convert_from_python_window_title_bar_inactive_background(PyObject *val, Options *opts) {
opts->window_title_bar_inactive_background = color_or_none_as_int(val);
}
static void
convert_from_opts_window_title_bar_inactive_background(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "window_title_bar_inactive_background");
if (ret == NULL) return;
convert_from_python_window_title_bar_inactive_background(ret, opts);
Py_DECREF(ret);
}
static void
convert_from_python_tab_bar_edge(PyObject *val, Options *opts) {
opts->tab_bar_edge = PyLong_AsLong(val);
@@ -1550,6 +1602,14 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
if (PyErr_Occurred()) return false;
convert_from_opts_window_drag_tolerance(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_window_title_bar_active_foreground(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_window_title_bar_active_background(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_window_title_bar_inactive_foreground(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_window_title_bar_inactive_background(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_tab_bar_edge(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_tab_bar_margin_height(py_opts, opts);

42
kitty/options/types.py generated
View File

@@ -25,13 +25,11 @@ choices_for_default_pointer_shape = typing.Literal['arrow', 'beam', 'text', 'poi
choices_for_linux_display_server = typing.Literal['auto', 'wayland', 'x11']
choices_for_macos_colorspace = typing.Literal['srgb', 'default', 'displayp3']
choices_for_macos_show_window_title_in = typing.Literal['all', 'menubar', 'none', 'window']
choices_for_pane_title_bar = typing.Literal['none', 'top', 'bottom']
choices_for_pane_title_bar_align = typing.Literal['left', 'center', 'right']
choices_for_placement_strategy = typing.Literal['top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right']
choices_for_pointer_shape_when_grabbed = choices_for_default_pointer_shape
choices_for_scrollbar = typing.Literal['scrolled', 'always', 'never', 'hovered', 'scrolled-and-hovered']
choices_for_strip_trailing_spaces = typing.Literal['always', 'never', 'smart']
choices_for_tab_bar_align = choices_for_pane_title_bar_align
choices_for_tab_bar_align = typing.Literal['left', 'center', 'right']
choices_for_tab_bar_style = typing.Literal['fade', 'hidden', 'powerline', 'separator', 'slant', 'custom']
choices_for_tab_powerline_style = typing.Literal['angled', 'round', 'slanted']
choices_for_tab_switch_strategy = typing.Literal['last', 'left', 'previous', 'right']
@@ -39,15 +37,17 @@ choices_for_terminfo_type = typing.Literal['path', 'direct', 'none']
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_align = choices_for_tab_bar_align
option_names = (
'action_alias',
'active_border_color',
'active_pane_title_template',
'active_tab_background',
'active_tab_font_style',
'active_tab_foreground',
'active_tab_title_template',
'active_window_title_template',
'allow_cloning',
'allow_hyperlinks',
'allow_remote_control',
@@ -408,13 +408,6 @@ option_names = (
'narrow_symbols',
'notify_on_cmd_finish',
'open_url_with',
'pane_title_bar',
'pane_title_bar_active_bg',
'pane_title_bar_active_fg',
'pane_title_bar_align',
'pane_title_bar_inactive_bg',
'pane_title_bar_inactive_fg',
'pane_title_template',
'paste_actions',
'pixel_scroll',
'placement_strategy',
@@ -507,16 +500,23 @@ option_names = (
'window_padding_width',
'window_resize_step_cells',
'window_resize_step_lines',
'window_title_bar',
'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_template',
)
class Options:
active_border_color: kitty.fast_data_types.Color | None = Color(0, 255, 0)
active_pane_title_template: str = 'none'
active_tab_background: Color = Color(238, 238, 238)
active_tab_font_style: tuple[bool, bool] = (True, True)
active_tab_foreground: Color = Color(0, 0, 0)
active_tab_title_template: str | None = None
active_window_title_template: str = 'none'
allow_cloning: choices_for_allow_cloning = 'ask'
allow_hyperlinks: int = 1
allow_remote_control: choices_for_allow_remote_control = 'no'
@@ -611,13 +611,6 @@ class Options:
mouse_hide_wait: MouseHideWait = MouseHideWait(hide_wait=0.0, show_wait=0.0, show_threshold=40, scroll_show=True) if is_macos else MouseHideWait(hide_wait=3.0, show_wait=0.0, show_threshold=40, scroll_show=True)
notify_on_cmd_finish: NotifyOnCmdFinish = NotifyOnCmdFinish(when='never', duration=5.0, action='notify', cmdline=(), clear_on=('focus', 'next'))
open_url_with: list[str] = ['default']
pane_title_bar: choices_for_pane_title_bar = 'none'
pane_title_bar_active_bg: Color = Color(0, 255, 0)
pane_title_bar_active_fg: Color = Color(0, 0, 0)
pane_title_bar_align: choices_for_pane_title_bar_align = 'center'
pane_title_bar_inactive_bg: Color = Color(51, 51, 51)
pane_title_bar_inactive_fg: Color = Color(204, 204, 204)
pane_title_template: str = '{title}'
paste_actions: frozenset[str] = frozenset({'confirm', 'quote-urls-at-prompt'})
pixel_scroll: bool = True
placement_strategy: choices_for_placement_strategy = 'center'
@@ -707,6 +700,13 @@ 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_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_template: str = '{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.window}{progress_percent}{title}'
action_alias: dict[str, str] = {}
env: dict[str, str] = {}
exe_search_path: dict[str, str] = {}
@@ -1127,6 +1127,10 @@ nullable_colors = frozenset({
'cursor_trail_color',
'visual_bell_color',
'active_border_color',
'window_title_bar_active_foreground',
'window_title_bar_active_background',
'window_title_bar_inactive_foreground',
'window_title_bar_inactive_background',
'tab_bar_background',
'tab_bar_margin_color',
'selection_foreground',