@@ -36,6 +36,7 @@ use rio_backend::clipboard::Clipboard;
3636use rio_backend:: clipboard:: ClipboardType ;
3737use rio_backend:: config:: layout:: Margin ;
3838use rio_backend:: config:: renderer:: Backend ;
39+ use rio_backend:: config:: theme:: AppearanceTheme ;
3940use rio_backend:: crosswords:: pos:: { Boundary , CursorState , Direction , Line } ;
4041use rio_backend:: crosswords:: search:: RegexSearch ;
4142use rio_backend:: error:: { RioError , RioErrorLevel , RioErrorType } ;
@@ -101,6 +102,7 @@ impl Screen<'_> {
101102 event_proxy : EventProxy ,
102103 font_library : & rio_backend:: sugarloaf:: font:: FontLibrary ,
103104 open_url : Option < String > ,
105+ color_scheme : Option < AppearanceTheme > ,
104106 ) -> Result < Screen < ' screen > , Box < dyn Error > > {
105107 let size = window_properties. size ;
106108 let scale = window_properties. scale ;
@@ -210,6 +212,7 @@ impl Screen<'_> {
210212 title : config. title . clone ( ) ,
211213 keyboard : config. keyboard ,
212214 scrollback_history_limit : config. scrollback_history_limit ,
215+ color_scheme_is_dark : !matches ! ( color_scheme, Some ( AppearanceTheme :: Light ) ) ,
213216 } ;
214217
215218 let rich_text_id = next_rich_text_id ( ) ;
@@ -392,6 +395,7 @@ impl Screen<'_> {
392395 config : & rio_backend:: config:: Config ,
393396 font_library : & rio_backend:: sugarloaf:: font:: FontLibrary ,
394397 should_update_font_library : bool ,
398+ color_scheme : Option < AppearanceTheme > ,
395399 ) {
396400 let num_tabs = self . ctx ( ) . len ( ) ;
397401 let padding_y_top = padding_top_from_config (
@@ -402,15 +406,16 @@ impl Screen<'_> {
402406 ) ;
403407 let padding_y_bottom = config. margin . bottom ;
404408
409+ // Resolved OS/adaptive scheme drives the DECSET 2031 notify.
410+ let scheme_is_dark = !matches ! ( color_scheme, Some ( AppearanceTheme :: Light ) ) ;
411+ let color_scheme_changed =
412+ self . context_manager . config . color_scheme_is_dark != scheme_is_dark;
413+
405414 if should_update_font_library {
406415 self . sugarloaf . update_font ( font_library) ;
407- // Drop the grid rasterizer's font_id-keyed caches —
408- // the new library reuses the same ids, so stale handles
409- // and ascents would survive the swap.
416+ // New library reuses the same font_ids, so font_id-keyed
417+ // caches must be dropped or they serve old-font data.
410418 self . grid_rasterizer . reset_font_caches ( ) ;
411- // Each panel's grid atlas caches glyph bitmaps by
412- // (font_id, glyph_id, size); the new font reuses font_ids,
413- // so stale slots would serve the wrong glyph. Flush them.
414419 for grid in self . grids . values_mut ( ) {
415420 grid. clear_glyph_cache ( ) ;
416421 }
@@ -466,12 +471,8 @@ impl Screen<'_> {
466471 let mut terminal = current_context. terminal . lock ( ) ;
467472 current_context. renderable_content =
468473 RenderableContent :: from_cursor_config ( & config. cursor ) ;
469- // Resetting renderable_content clears term_colors and
470- // the dirty flag. Force a full repaint per pane so every
471- // pane (not just the focused one) picks up the new theme
472- // — the render loop skips non-dirty panes, and
473- // resize_all_contexts only repaints via the PTY wakeup,
474- // which idle panes never get.
474+ // Idle panes are skipped by the render loop, so force a
475+ // full repaint or they keep the old theme.
475476 current_context
476477 . renderable_content
477478 . pending_update
@@ -480,6 +481,10 @@ impl Screen<'_> {
480481 terminal. cursor_shape = shape;
481482 terminal. default_cursor_shape = shape;
482483 terminal. blinking_cursor = config. cursor . blinking ;
484+ terminal. set_color_scheme ( scheme_is_dark) ;
485+ if color_scheme_changed {
486+ terminal. report_color_scheme ( scheme_is_dark) ;
487+ }
483488 drop ( terminal) ;
484489 }
485490 }
@@ -489,6 +494,9 @@ impl Screen<'_> {
489494
490495 // Update keyboard config in context manager
491496 self . context_manager . config . keyboard = config. keyboard ;
497+ // Panes spawned after a theme change must start with the new
498+ // scheme so their `CSI ? 996 n` query answers correctly.
499+ self . context_manager . config . color_scheme_is_dark = scheme_is_dark;
492500
493501 // Re-evaluate the opaque flag — toggling `window.opacity` /
494502 // `window.blur` at runtime should flip the compositor mode.
0 commit comments