mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-08 21:25:32 +02:00
Merge branch 'draw-borders-when-focused' of https://github.com/jackielii/kitty
This commit is contained in:
@@ -6,7 +6,7 @@ from enum import IntFlag
|
||||
from functools import partial
|
||||
from typing import NamedTuple
|
||||
|
||||
from .fast_data_types import BORDERS_PROGRAM, get_options, init_borders_program, set_borders_rects
|
||||
from .fast_data_types import BORDERS_PROGRAM, current_focused_os_window_id, get_options, init_borders_program, set_borders_rects
|
||||
from .shaders import program_for
|
||||
from .typing_compat import LayoutType
|
||||
from .utils import color_as_int
|
||||
@@ -84,7 +84,6 @@ class Borders:
|
||||
) -> None:
|
||||
opts = get_options()
|
||||
draw_active_borders = opts.active_border_color is not None
|
||||
draw_minimal_borders = opts.draw_minimal_borders and max(opts.window_margin_width) < 1
|
||||
rects: list[Border] = []
|
||||
for br in current_layout.blank_rects:
|
||||
rects.append(Border(*br, BorderColor.default_bg))
|
||||
@@ -96,12 +95,28 @@ class Borders:
|
||||
draw_borders = bw > 0 and draw_window_borders
|
||||
active_group = all_windows.active_group
|
||||
|
||||
# Count visible windows
|
||||
num_visible_groups = len(groups)
|
||||
|
||||
# When draw_window_borders_for_single_window is set and there's only 1 window,
|
||||
# behave like draw_minimal_borders is False (draw full borders around the window)
|
||||
if opts.draw_window_borders_for_single_window and num_visible_groups == 1:
|
||||
draw_minimal_borders = False
|
||||
else:
|
||||
draw_minimal_borders = opts.draw_minimal_borders and max(opts.window_margin_width) < 1
|
||||
|
||||
# For single window with the option enabled, check OS window focus state
|
||||
# When unfocused, the border should appear inactive
|
||||
os_window_focused = True
|
||||
if opts.draw_window_borders_for_single_window and num_visible_groups == 1:
|
||||
os_window_focused = current_focused_os_window_id() == self.os_window_id
|
||||
|
||||
for i, wg in enumerate(groups):
|
||||
window_bg = color_as_int(wg.default_bg)
|
||||
window_bg = (window_bg << 8) | BorderColor.window_bg
|
||||
if draw_borders and not draw_minimal_borders:
|
||||
# Draw the border rectangles
|
||||
if wg is active_group and draw_active_borders:
|
||||
if wg is active_group and draw_active_borders and os_window_focused:
|
||||
color = BorderColor.active
|
||||
else:
|
||||
color = BorderColor.bell if wg.needs_attention else BorderColor.inactive
|
||||
|
||||
@@ -1854,6 +1854,13 @@ class Boss:
|
||||
if is_macos and focused:
|
||||
cocoa_set_menubar_title(w.title or '')
|
||||
tm.mark_tab_bar_dirty()
|
||||
# Redraw borders when focus changes if draw_window_borders_for_single_window is enabled
|
||||
# and there's only a single window (to show inactive border when OS window loses focus)
|
||||
opts = get_options()
|
||||
if opts.draw_window_borders_for_single_window and tm.active_tab is not None:
|
||||
# Only redraw if there's a single visible window
|
||||
if tm.active_tab.windows.num_visble_groups == 1:
|
||||
tm.active_tab.relayout_borders()
|
||||
|
||||
def on_activity_since_last_focus(self, window: Window) -> None:
|
||||
os_window_id = window.os_window_id
|
||||
|
||||
@@ -7,7 +7,7 @@ from itertools import repeat
|
||||
from typing import Any, Callable, NamedTuple
|
||||
|
||||
from kitty.borders import BorderColor
|
||||
from kitty.fast_data_types import Region, set_active_window, viewport_for_window
|
||||
from kitty.fast_data_types import Region, get_options, set_active_window, viewport_for_window
|
||||
from kitty.options.types import Options
|
||||
from kitty.types import Edges, WindowGeometry, WindowMapper
|
||||
from kitty.typing_compat import TypedDict, WindowType
|
||||
@@ -248,7 +248,7 @@ class Layout:
|
||||
self.set_active_window_in_os_window = partial(set_active_window, os_window_id, tab_id)
|
||||
|
||||
def bias_increment_for_cell(self, all_windows: WindowList, is_horizontal: bool) -> float:
|
||||
self._set_dimensions()
|
||||
self._set_dimensions(all_windows)
|
||||
return self.calculate_bias_increment_for_a_single_cell(all_windows, is_horizontal)
|
||||
|
||||
def calculate_bias_increment_for_a_single_cell(self, all_windows: WindowList, is_horizontal: bool) -> float:
|
||||
@@ -335,7 +335,7 @@ class Layout:
|
||||
if bias is not None:
|
||||
idx = all_windows.group_idx_for_window(window)
|
||||
if idx is not None:
|
||||
self._set_dimensions()
|
||||
self._set_dimensions(all_windows)
|
||||
self._bias_slot(all_windows, idx, bias)
|
||||
|
||||
def _bias_slot(self, all_windows: WindowList, idx: int, bias: float) -> bool:
|
||||
@@ -354,11 +354,23 @@ class Layout:
|
||||
is_visible = window is active_window or (is_group_leader and not self.only_active_window_visible)
|
||||
window.set_visible_in_layout(is_visible)
|
||||
|
||||
def _set_dimensions(self) -> None:
|
||||
def _set_dimensions(self, all_windows: WindowList | None = None) -> None:
|
||||
lgd.central, tab_bar, vw, vh, lgd.cell_width, lgd.cell_height = viewport_for_window(self.os_window_id)
|
||||
# Update lgd.draw_minimal_borders based on the current number of visible windows
|
||||
# and the draw_window_borders_for_single_window option
|
||||
opts = get_options()
|
||||
base_draw_minimal = opts.draw_minimal_borders and sum(opts.window_margin_width) == 0
|
||||
if all_windows is not None and opts.draw_window_borders_for_single_window:
|
||||
num_visible = all_windows.num_groups
|
||||
if num_visible == 1:
|
||||
lgd.draw_minimal_borders = False
|
||||
else:
|
||||
lgd.draw_minimal_borders = base_draw_minimal
|
||||
else:
|
||||
lgd.draw_minimal_borders = base_draw_minimal
|
||||
|
||||
def __call__(self, all_windows: WindowList) -> None:
|
||||
self._set_dimensions()
|
||||
self._set_dimensions(all_windows)
|
||||
self.update_visibility(all_windows)
|
||||
self.blank_rects = []
|
||||
self.do_layout(all_windows)
|
||||
@@ -432,7 +444,7 @@ class Layout:
|
||||
return all_windows.compute_needs_borders_map(lgd.draw_active_borders)
|
||||
|
||||
def get_minimal_borders(self, windows: WindowList) -> Generator[BorderLine, None, None]:
|
||||
self._set_dimensions()
|
||||
self._set_dimensions(windows)
|
||||
yield from self.minimal_borders(windows)
|
||||
|
||||
def minimal_borders(self, windows: WindowList) -> Generator[BorderLine, None, None]:
|
||||
|
||||
@@ -1224,6 +1224,19 @@ drawn.
|
||||
'''
|
||||
)
|
||||
|
||||
opt('draw_window_borders_for_single_window', 'no',
|
||||
option_type='to_bool',
|
||||
long_text='''
|
||||
Draw borders around a window even when there is only a single window visible. When
|
||||
enabled and there is only a single window, full borders are drawn around it (as if
|
||||
:opt:`draw_minimal_borders` is false). The border will show in the active color when
|
||||
the window is focused and the OS window has focus, and in the inactive color when the
|
||||
OS window loses focus. This provides a clear visual indicator of whether the kitty
|
||||
window is focused. When there are multiple windows visible, this option has no effect
|
||||
and normal border drawing rules apply.
|
||||
'''
|
||||
)
|
||||
|
||||
opt('window_margin_width', '0',
|
||||
option_type='edge_width',
|
||||
long_text='''
|
||||
|
||||
3
kitty/options/parse.py
generated
3
kitty/options/parse.py
generated
@@ -971,6 +971,9 @@ class Parser:
|
||||
def draw_minimal_borders(self, val: str, ans: dict[str, typing.Any]) -> None:
|
||||
ans['draw_minimal_borders'] = to_bool(val)
|
||||
|
||||
def draw_window_borders_for_single_window(self, val: str, ans: dict[str, typing.Any]) -> None:
|
||||
ans['draw_window_borders_for_single_window'] = to_bool(val)
|
||||
|
||||
def dynamic_background_opacity(self, val: str, ans: dict[str, typing.Any]) -> None:
|
||||
ans['dynamic_background_opacity'] = to_bool(val)
|
||||
|
||||
|
||||
2
kitty/options/types.py
generated
2
kitty/options/types.py
generated
@@ -346,6 +346,7 @@ option_names = (
|
||||
'dim_opacity',
|
||||
'disable_ligatures',
|
||||
'draw_minimal_borders',
|
||||
'draw_window_borders_for_single_window',
|
||||
'dynamic_background_opacity',
|
||||
'editor',
|
||||
'enable_audio_bell',
|
||||
@@ -544,6 +545,7 @@ class Options:
|
||||
dim_opacity: float = 0.4
|
||||
disable_ligatures: int = 0
|
||||
draw_minimal_borders: bool = True
|
||||
draw_window_borders_for_single_window: bool = False
|
||||
dynamic_background_opacity: bool = False
|
||||
editor: str = '.'
|
||||
enable_audio_bell: bool = True
|
||||
|
||||
@@ -418,10 +418,15 @@ class Tab: # {{{
|
||||
tm = self.tab_manager_ref()
|
||||
if tm is not None:
|
||||
ly = self.current_layout
|
||||
opts = get_options()
|
||||
draw_borders = (
|
||||
(ly.needs_window_borders and self.windows.num_visble_groups > 1) or ly.must_draw_borders
|
||||
or opts.draw_window_borders_for_single_window
|
||||
)
|
||||
self.borders(
|
||||
all_windows=self.windows,
|
||||
current_layout=ly, tab_bar_rects=tm.tab_bar_rects,
|
||||
draw_window_borders=(ly.needs_window_borders and self.windows.num_visble_groups > 1) or ly.must_draw_borders
|
||||
draw_window_borders=draw_borders
|
||||
)
|
||||
|
||||
def create_layout_object(self, name: str) -> Layout:
|
||||
|
||||
@@ -88,6 +88,10 @@ def utils(self, q, windows):
|
||||
|
||||
class TestLayout(BaseTest):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.set_options()
|
||||
|
||||
def do_ops_test(self, q):
|
||||
windows = create_windows(q)
|
||||
ids, visible_ids, expect_ids, check_visible = utils(self, q, windows)
|
||||
|
||||
Reference in New Issue
Block a user