Files
kitty-mirror/kitty/borders.py
Jackie Li 05810722be use draw_window_borders_for_single_window
single window + has focus -> active border
single window + no focus -> inactive border
multiple window + regardless of focus -> active border

a) option set:

    1) Single *visible* window in the layout - always draw a border
    border color = active if os_window is focused else inactive

    2) multiple visible windows in the layout - no change in existing
    behavior, in particular draw_minimal_borders is respected as before.

b) option unset - no changes from present behavior

option default to false.
2025-10-14 18:39:23 +01:00

129 lines
4.6 KiB
Python

#!/usr/bin/env python
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from collections.abc import Iterable
from enum import IntFlag
from functools import partial
from typing import NamedTuple
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
from .window_list import WindowGroup, WindowList
class BorderColor(IntFlag):
# These are indices into the array of colors in the border vertex shader
default_bg, active, inactive, window_bg, bell, tab_bar_bg, tab_bar_margin_color, tab_bar_left_edge_color, tab_bar_right_edge_color = range(9)
class Border(NamedTuple):
left: int
top: int
right: int
bottom: int
color: BorderColor
def vertical_edge(rects: list[Border], color: BorderColor, width: int, top: int, bottom: int, left: int) -> None:
if width > 0:
rects.append(Border(left, top, left + width, bottom, color))
def horizontal_edge(rects: list[Border], color: BorderColor, height: int, left: int, right: int, top: int) -> None:
if height > 0:
rects.append(Border(left, top, right, top + height, color))
def add_borders(rects: list[Border], color: BorderColor, wg: WindowGroup) -> None:
geometry = wg.geometry
if geometry is None:
return
pl, pt = wg.effective_padding('left'), wg.effective_padding('top')
pr, pb = wg.effective_padding('right'), wg.effective_padding('bottom')
left = geometry.left - pl
top = geometry.top - pt
lr = geometry.right
right = lr + pr
bt = geometry.bottom
bottom = bt + pb
h = partial(horizontal_edge, rects, color)
v = partial(vertical_edge, rects, color)
width = wg.effective_border()
bt = bottom
lr = right
left -= width
top -= width
right += width
bottom += width
pl = pr = pb = pt = width
h(pt, left, right, top)
h(pb, left, right, bt)
v(pl, top, bottom, left)
v(pr, top, bottom, lr)
def load_borders_program() -> None:
program_for('border').compile(BORDERS_PROGRAM)
init_borders_program()
class Borders:
def __init__(self, os_window_id: int, tab_id: int):
self.os_window_id = os_window_id
self.tab_id = tab_id
def __call__(
self,
all_windows: WindowList,
current_layout: LayoutType,
tab_bar_rects: Iterable[Border],
draw_window_borders: bool = True,
) -> None:
opts = get_options()
draw_active_borders = opts.active_border_color is not None
rects: list[Border] = []
for br in current_layout.blank_rects:
rects.append(Border(*br, BorderColor.default_bg))
rects.extend(tab_bar_rects)
bw = 0
groups = tuple(all_windows.iter_all_layoutable_groups(only_visible=True))
if groups:
bw = groups[0].effective_border()
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 and os_window_focused:
color = BorderColor.active
else:
color = BorderColor.bell if wg.needs_attention else BorderColor.inactive
add_borders(rects, color, wg)
if draw_minimal_borders:
for border_line in current_layout.get_minimal_borders(all_windows):
rects.append(Border(*border_line.edges, border_line.color))
set_borders_rects(self.os_window_id, self.tab_id, rects)