1#!/usr/local/bin/python3.8 2# vim:fileencoding=utf-8 3# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net> 4 5from enum import IntFlag 6from itertools import chain 7from typing import Sequence, Tuple 8 9from .fast_data_types import ( 10 BORDERS_PROGRAM, add_borders_rect, compile_program, get_options, 11 init_borders_program, os_window_has_background_image 12) 13from .typing import LayoutType 14from .utils import load_shaders 15from .window_list import WindowGroup, WindowList 16 17 18class BorderColor(IntFlag): 19 # See the border vertex shader for how these flags become actual colors 20 default_bg, active, inactive, window_bg, bell = ((1 << i) for i in range(5)) 21 22 23def vertical_edge(os_window_id: int, tab_id: int, color: int, width: int, top: int, bottom: int, left: int) -> None: 24 if width > 0: 25 add_borders_rect(os_window_id, tab_id, left, top, left + width, bottom, color) 26 27 28def horizontal_edge(os_window_id: int, tab_id: int, color: int, height: int, left: int, right: int, top: int) -> None: 29 if height > 0: 30 add_borders_rect(os_window_id, tab_id, left, top, right, top + height, color) 31 32 33def draw_edges(os_window_id: int, tab_id: int, colors: Sequence[int], wg: WindowGroup, borders: bool = False) -> None: 34 geometry = wg.geometry 35 if geometry is None: 36 return 37 pl, pt = wg.effective_padding('left'), wg.effective_padding('top') 38 pr, pb = wg.effective_padding('right'), wg.effective_padding('bottom') 39 left = geometry.left - pl 40 top = geometry.top - pt 41 lr = geometry.right 42 right = lr + pr 43 bt = geometry.bottom 44 bottom = bt + pb 45 if borders: 46 width = wg.effective_border() 47 bt = bottom 48 lr = right 49 left -= width 50 top -= width 51 right += width 52 bottom += width 53 pl = pr = pb = pt = width 54 horizontal_edge(os_window_id, tab_id, colors[1], pt, left, right, top) 55 horizontal_edge(os_window_id, tab_id, colors[3], pb, left, right, bt) 56 vertical_edge(os_window_id, tab_id, colors[0], pl, top, bottom, left) 57 vertical_edge(os_window_id, tab_id, colors[2], pr, top, bottom, lr) 58 59 60def load_borders_program() -> None: 61 compile_program(BORDERS_PROGRAM, *load_shaders('border')) 62 init_borders_program() 63 64 65class Borders: 66 67 def __init__(self, os_window_id: int, tab_id: int): 68 self.os_window_id = os_window_id 69 self.tab_id = tab_id 70 71 def __call__( 72 self, 73 all_windows: WindowList, 74 current_layout: LayoutType, 75 extra_blank_rects: Sequence[Tuple[int, int, int, int]], 76 draw_window_borders: bool = True, 77 ) -> None: 78 opts = get_options() 79 draw_active_borders = opts.active_border_color is not None 80 draw_minimal_borders = opts.draw_minimal_borders and max(opts.window_margin_width) < 1 81 add_borders_rect(self.os_window_id, self.tab_id, 0, 0, 0, 0, BorderColor.default_bg) 82 has_background_image = os_window_has_background_image(self.os_window_id) 83 if not has_background_image: 84 for br in chain(current_layout.blank_rects, extra_blank_rects): 85 left, top, right, bottom = br 86 add_borders_rect(self.os_window_id, self.tab_id, left, top, right, bottom, BorderColor.default_bg) 87 bw = 0 88 groups = tuple(all_windows.iter_all_layoutable_groups(only_visible=True)) 89 if groups: 90 bw = groups[0].effective_border() 91 draw_borders = bw > 0 and draw_window_borders 92 active_group = all_windows.active_group 93 94 for i, wg in enumerate(groups): 95 window_bg = wg.default_bg 96 window_bg = (window_bg << 8) | BorderColor.window_bg 97 if draw_borders and not draw_minimal_borders: 98 # Draw the border rectangles 99 if wg is active_group and draw_active_borders: 100 color = BorderColor.active 101 else: 102 color = BorderColor.bell if wg.needs_attention else BorderColor.inactive 103 draw_edges(self.os_window_id, self.tab_id, (color, color, color, color), wg, borders=True) 104 if not has_background_image: 105 # Draw the background rectangles over the padding region 106 colors = window_bg, window_bg, window_bg, window_bg 107 draw_edges(self.os_window_id, self.tab_id, colors, wg) 108 109 if draw_minimal_borders: 110 for border_line in current_layout.get_minimal_borders(all_windows): 111 left, top, right, bottom = border_line.edges 112 add_borders_rect(self.os_window_id, self.tab_id, left, top, right, bottom, border_line.color) 113