Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions frontends/rioterm/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use raw_window_handle::HasDisplayHandle;
use rio_backend::clipboard::{Clipboard, ClipboardType};
use rio_backend::config::colors::{ColorRgb, NamedColor};
use rio_backend::config::theme::AppearanceTheme;
use rio_window::application::ApplicationHandler;
use rio_window::event::{
ElementState, Ime, MouseButton, MouseScrollDelta, StartCause, TouchPhase, WindowEvent,
Expand Down Expand Up @@ -395,17 +396,19 @@ impl ApplicationHandler<EventPayload> for Application<'_> {

self.config = config;

let color_scheme = self.config.force_theme.or_else(|| {
event_loop
.system_theme()
.map(AppearanceTheme::from_window_theme)
});
let mut has_checked_adaptive_colors = false;
for (_id, route) in self.router.routes.iter_mut() {
// Apply system theme to ensure colors are consistent
if !has_checked_adaptive_colors {
let system_theme = event_loop.system_theme();
let theme = self
.config
.force_theme
.map(|t| t.to_window_theme())
.or(system_theme);
update_colors_based_on_theme(&mut self.config, theme);
update_colors_based_on_theme(
&mut self.config,
color_scheme.map(AppearanceTheme::to_window_theme),
);
has_checked_adaptive_colors = true;
}

Expand All @@ -425,6 +428,7 @@ impl ApplicationHandler<EventPayload> for Application<'_> {
&self.config,
&self.router.font_library,
has_font_updates,
color_scheme,
);
route.window.configure_window(&self.config);

Expand Down Expand Up @@ -858,7 +862,6 @@ impl ApplicationHandler<EventPayload> for Application<'_> {
}
RioEventType::Rio(RioEvent::ToggleAppearanceTheme) => {
if let Some(route) = self.router.routes.get_mut(&window_id) {
use rio_backend::config::theme::AppearanceTheme;
let current = self
.config
.force_theme
Expand All @@ -880,6 +883,7 @@ impl ApplicationHandler<EventPayload> for Application<'_> {
&self.config,
&self.router.font_library,
false,
Some(toggled),
);
route.window.configure_window(&self.config);
}
Expand Down Expand Up @@ -1185,7 +1189,13 @@ impl ApplicationHandler<EventPayload> for Application<'_> {
// targets a different panel, switch to it regardless
// of mouse mode (e.g. neovim capturing clicks).
if route.window.screen.select_current_based_on_mouse() {
// Focus-switch click: clear the now-focused pane's
// stale selection and reset click_state so the
// in-flight press can't drag-extend the old anchor.
route.window.screen.clear_selection();
route.window.screen.mouse.click_state = ClickState::Click;
route.request_redraw();
return;
} else if !route.window.screen.modifiers.state().shift_key()
&& route.window.screen.mouse_mode()
{
Expand Down Expand Up @@ -1827,6 +1837,7 @@ impl ApplicationHandler<EventPayload> for Application<'_> {
&self.config,
&self.router.font_library,
false,
Some(AppearanceTheme::from_window_theme(new_theme)),
);
route.window.configure_window(&self.config);
route.request_redraw();
Expand Down
5 changes: 5 additions & 0 deletions frontends/rioterm/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ pub struct ContextManagerConfig {
pub title: rio_backend::config::title::Title,
pub keyboard: rio_backend::config::keyboard::Keyboard,
pub scrollback_history_limit: usize,
/// Initial color-scheme polarity for new panes, so the
/// `CSI ? 996 n` query answers correctly before any theme change.
pub color_scheme_is_dark: bool,
}

const DEFAULT_CONTEXT_CAPACITY: usize = 28;
Expand Down Expand Up @@ -245,6 +248,7 @@ impl<T: EventListener + Clone + std::marker::Send + 'static> ContextManager<T> {
config.scrollback_history_limit,
);
terminal.blinking_cursor = cursor_state.1;
terminal.set_color_scheme(config.color_scheme_is_dark);
let terminal: Arc<FairMutex<Crosswords<T>>> = Arc::new(FairMutex::new(terminal));

let pty;
Expand Down Expand Up @@ -1065,6 +1069,7 @@ impl<T: EventListener + Clone + std::marker::Send + 'static> ContextManager<T> {
title: config.title,
keyboard: config.keyboard,
scrollback_history_limit: config.scrollback_history_limit,
color_scheme_is_dark: self.config.color_scheme_is_dark,
};

let current = self.current();
Expand Down
17 changes: 17 additions & 0 deletions frontends/rioterm/src/grid_emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,23 @@ impl GridGlyphRasterizer {
}
}

/// Drop every `font_id`-keyed cache. Called on a font-library
/// swap: the new library reuses the same `font_id` slots, so
/// stale entries would otherwise feed shaping (advances) and
/// `ascent_px` (vertical placement) from the old font.
pub fn reset_font_caches(&mut self) {
self.font_resolve.clear();
self.ascent_cache.clear();
self.synthesis_cache.clear();
for bucket in &mut self.run_cache {
bucket.clear();
}
#[cfg(target_os = "macos")]
self.handle_cache.clear();
#[cfg(not(target_os = "macos"))]
self.font_data_cache.clear();
}

#[inline]
fn resolve_font(
&mut self,
Expand Down
18 changes: 15 additions & 3 deletions frontends/rioterm/src/router/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::screen::{Screen, ScreenWindowProperties};
use assistant::Assistant;
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
use rio_backend::clipboard::Clipboard;
use rio_backend::config::theme::AppearanceTheme;
use rio_backend::config::Config as RioConfig;
use rio_backend::error::{RioError, RioErrorLevel, RioErrorType};

Expand Down Expand Up @@ -89,10 +90,11 @@ impl Route<'_> {
config: &RioConfig,
db: &rio_backend::sugarloaf::font::FontLibrary,
should_update_font: bool,
color_scheme: Option<AppearanceTheme>,
) {
self.window
.screen
.update_config(config, db, should_update_font);
.update_config(config, db, should_update_font, color_scheme);
}

#[inline]
Expand Down Expand Up @@ -703,8 +705,18 @@ impl<'a> RouteWindow<'a> {
window_id: winit_window.id(),
};

let screen = Screen::new(properties, config, event_proxy, font_library, open_url)
.expect("Screen not created");
let color_scheme = config
.force_theme
.or_else(|| winit_window.theme().map(AppearanceTheme::from_window_theme));
let screen = Screen::new(
properties,
config,
event_proxy,
font_library,
open_url,
color_scheme,
)
.expect("Screen not created");

if config.window.columns.is_some() || config.window.rows.is_some() {
let (physical_width, physical_height) = compute_window_size_from_grid(
Expand Down
28 changes: 28 additions & 0 deletions frontends/rioterm/src/screen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use rio_backend::clipboard::Clipboard;
use rio_backend::clipboard::ClipboardType;
use rio_backend::config::layout::Margin;
use rio_backend::config::renderer::Backend;
use rio_backend::config::theme::AppearanceTheme;
use rio_backend::crosswords::pos::{Boundary, CursorState, Direction, Line};
use rio_backend::crosswords::search::RegexSearch;
use rio_backend::error::{RioError, RioErrorLevel, RioErrorType};
Expand Down Expand Up @@ -119,6 +120,7 @@ impl Screen<'_> {
event_proxy: EventProxy,
font_library: &rio_backend::sugarloaf::font::FontLibrary,
open_url: Option<String>,
color_scheme: Option<AppearanceTheme>,
) -> Result<Screen<'screen>, Box<dyn Error>> {
let size = window_properties.size;
let scale = window_properties.scale;
Expand Down Expand Up @@ -228,6 +230,7 @@ impl Screen<'_> {
title: config.title.clone(),
keyboard: config.keyboard,
scrollback_history_limit: config.scrollback_history_limit,
color_scheme_is_dark: !matches!(color_scheme, Some(AppearanceTheme::Light)),
};

let rich_text_id = next_rich_text_id();
Expand Down Expand Up @@ -412,6 +415,7 @@ impl Screen<'_> {
config: &rio_backend::config::Config,
font_library: &rio_backend::sugarloaf::font::FontLibrary,
should_update_font_library: bool,
color_scheme: Option<AppearanceTheme>,
) {
let num_tabs = self.ctx().len();
let padding_y_top = padding_top_from_config(
Expand All @@ -422,8 +426,19 @@ impl Screen<'_> {
);
let padding_y_bottom = config.margin.bottom;

// Resolved OS/adaptive scheme drives the DECSET 2031 notify.
let scheme_is_dark = !matches!(color_scheme, Some(AppearanceTheme::Light));
let color_scheme_changed =
self.context_manager.config.color_scheme_is_dark != scheme_is_dark;

if should_update_font_library {
self.sugarloaf.update_font(font_library);
// New library reuses the same font_ids, so font_id-keyed
// caches must be dropped or they serve old-font data.
self.grid_rasterizer.reset_font_caches();
for grid in self.grids.values_mut() {
grid.clear_glyph_cache();
}
}
let s = self.sugarloaf.style_mut();
s.font_size = config.fonts.size;
Expand Down Expand Up @@ -474,10 +489,20 @@ impl Screen<'_> {
let mut terminal = current_context.terminal.lock();
current_context.renderable_content =
RenderableContent::from_cursor_config(&config.cursor);
// Idle panes are skipped by the render loop, so force a
// full repaint or they keep the old theme.
current_context
.renderable_content
.pending_update
.set_terminal_damage(rio_backend::event::TerminalDamage::Full);
let shape = config.cursor.shape;
terminal.cursor_shape = shape;
terminal.default_cursor_shape = shape;
terminal.blinking_cursor = config.cursor.blinking;
terminal.set_color_scheme(scheme_is_dark);
if color_scheme_changed {
terminal.report_color_scheme(scheme_is_dark);
}
drop(terminal);
}
}
Expand All @@ -487,6 +512,9 @@ impl Screen<'_> {

// Update keyboard config in context manager
self.context_manager.config.keyboard = config.keyboard;
// Panes spawned after a theme change must start with the new
// scheme so their `CSI ? 996 n` query answers correctly.
self.context_manager.config.color_scheme_is_dark = scheme_is_dark;

// Re-evaluate the opaque flag — toggling `window.opacity` /
// `window.blur` at runtime should flip the compositor mode.
Expand Down
4 changes: 4 additions & 0 deletions rio-backend/src/ansi/mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ impl PrivateMode {
1049 => Self::Named(NamedPrivateMode::SwapScreenAndSetRestoreCursor),
2004 => Self::Named(NamedPrivateMode::BracketedPaste),
2026 => Self::Named(NamedPrivateMode::SyncUpdate),
2031 => Self::Named(NamedPrivateMode::ColorSchemeUpdates),
_ => Self::Unknown(mode),
}
}
Expand Down Expand Up @@ -120,6 +121,9 @@ pub enum NamedPrivateMode {
BracketedPaste = 2004,
/// The mode is handled automatically by [`Processor`].
SyncUpdate = 2026,
/// App opts in to unsolicited DSR `CSI ? 997 n` light/dark
/// color-scheme notifications (DECSET 2031).
ColorSchemeUpdates = 2031,
}

/// Mode for clearing line.
Expand Down
Loading
Loading