diff --git a/src/textual/app.py b/src/textual/app.py index fc9e361f08..ee2aa45992 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -789,6 +789,9 @@ def __init__( self._resize_event: events.Resize | None = None """A pending resize event, sent on idle.""" + self._css_update_count: int = 0 + """Incremented when CSS is invalidated.""" + if self.ENABLE_COMMAND_PALETTE: for _key, binding in self._bindings: if binding.action in {"command_palette", "app.command_palette"}: @@ -1192,6 +1195,10 @@ def get_css_variables(self) -> dict[str, str]: variables = design.generate() return variables + def _invalidate_css(self) -> None: + """Invalidate CSS, so it will be refreshed.""" + self._css_update_count += 1 + def watch_dark(self, dark: bool) -> None: """Watches the dark bool. @@ -1201,16 +1208,19 @@ def watch_dark(self, dark: bool) -> None: self.set_class(dark, "-dark-mode", update=False) self.set_class(not dark, "-light-mode", update=False) self._refresh_truecolor_filter(self.ansi_theme) + self._invalidate_css() self.call_next(self.refresh_css) def watch_ansi_theme_dark(self, theme: TerminalTheme) -> None: if self.dark: self._refresh_truecolor_filter(theme) + self._invalidate_css() self.call_next(self.refresh_css) def watch_ansi_theme_light(self, theme: TerminalTheme) -> None: if not self.dark: self._refresh_truecolor_filter(theme) + self._invalidate_css() self.call_next(self.refresh_css) @property @@ -2206,7 +2216,9 @@ def _init_mode(self, mode: str) -> AwaitMount: screen, await_mount = self._get_screen(new_screen) stack.append(screen) self._load_screen_css(screen) - self.refresh_css() + if screen._css_update_count != self._css_update_count: + self.refresh_css() + screen.post_message(events.ScreenResume()) else: # Mode is not defined @@ -2251,7 +2263,8 @@ def switch_mode(self, mode: str) -> AwaitMount: await_mount = AwaitMount(self.screen, []) self._current_mode = mode - self.refresh_css() + if self.screen._css_update_count != self._css_update_count: + self.refresh_css() self.screen._screen_resized(self.size) self.screen.post_message(events.ScreenResume()) @@ -3368,6 +3381,7 @@ def refresh_css(self, animate: bool = True) -> None: stylesheet.update(self.app, animate=animate) try: self.screen._refresh_layout(self.size) + self.screen._css_update_count = self._css_update_count except ScreenError: pass # The other screens in the stack will need to know about some style @@ -3376,6 +3390,7 @@ def refresh_css(self, animate: bool = True) -> None: for screen in self.screen_stack: if screen != self.screen: stylesheet.update(screen, animate=animate) + screen._css_update_count = self._css_update_count def _display(self, screen: Screen, renderable: RenderableType | None) -> None: """Display a renderable within a sync. diff --git a/src/textual/screen.py b/src/textual/screen.py index ee37cb1675..0b025bbba1 100644 --- a/src/textual/screen.py +++ b/src/textual/screen.py @@ -267,6 +267,9 @@ def __init__( self.bindings_updated_signal: Signal[Screen] = Signal(self, "bindings_updated") """A signal published when the bindings have been updated""" + self._css_update_count = -1 + """Track updates to CSS.""" + @property def is_modal(self) -> bool: """Is the screen modal?"""