diff --git a/src/textual/_xterm_parser.py b/src/textual/_xterm_parser.py index 5b810273fa9..af34892ede3 100644 --- a/src/textual/_xterm_parser.py +++ b/src/textual/_xterm_parser.py @@ -14,7 +14,7 @@ # When trying to determine whether the current sequence is a supported/valid # escape sequence, at which length should we give up and consider our search # to be unsuccessful? -_MAX_SEQUENCE_SEARCH_THRESHOLD = 20 +_MAX_SEQUENCE_SEARCH_THRESHOLD = 24 _re_mouse_event = re.compile("^" + re.escape("\x1b[") + r"( None: bracketed_paste = False break + if sequence.startswith(BG_COLOR) and len(sequence) == BG_COLOR_LEN: + rgb_str = sequence[len(BG_COLOR):] + rgb = rgb_str.split("/") + if len(rgb) == 3: + r = int(rgb[0], 16) + g = int(rgb[1], 16) + b = int(rgb[2], 16) + self.debug_log(f"Detected BG_COLOR response {r:02x}/{g:02x}/{b:02x}") + on_token(events.BackgroundColor(r, g, b)) + break + if not bracketed_paste: # Check cursor position report if ( diff --git a/src/textual/app.py b/src/textual/app.py index f34ca203703..db277606df2 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -3275,6 +3275,15 @@ async def _on_app_blur(self, event: events.AppBlur) -> None: self.app_focus = False self.screen.refresh_bindings() + def _is_dark_color(self, r: int, g: int, b: int) -> bool: + # perceived brightness formula + perceived_brightness = 0.2126 * r + 0.7152 * g + 0.0722 * b + return perceived_brightness < 128 + + async def _on_background_color(self, event: events.BackgroundColor) -> None: + """Background color detected""" + self.dark = self._is_dark_color(event.r & 0xff, event.g & 0xff, event.b & 0xff) + def _detach_from_dom(self, widgets: list[Widget]) -> list[Widget]: """Detach a list of widgets from the DOM. diff --git a/src/textual/drivers/linux_driver.py b/src/textual/drivers/linux_driver.py index cd6a4c0130c..835ba636752 100644 --- a/src/textual/drivers/linux_driver.py +++ b/src/textual/drivers/linux_driver.py @@ -248,6 +248,7 @@ def on_terminal_resize(signum, stack) -> None: self.flush() self._key_thread = Thread(target=self._run_input_thread) send_size_event() + self.write("\x1b]11;?\x07") # Detect background color self._key_thread.start() self._request_terminal_sync_mode_support() self._enable_bracketed_paste() diff --git a/src/textual/events.py b/src/textual/events.py index ce5ecac4e3d..b9f28ecfb08 100644 --- a/src/textual/events.py +++ b/src/textual/events.py @@ -707,3 +707,13 @@ def __init__(self, text: str, stderr: bool = False) -> None: def __rich_repr__(self) -> rich.repr.Result: yield self.text yield self.stderr + +@dataclass +class BackgroundColor(Event, bubble=False): + """Internal event used when background color of the terminal is + detected + """ + + r: int + g: int + b: int