use std::sync::Arc;
use crate::app::window_state::WindowState;
use crate::app::window_state::config_updates::ConfigChanges;
use crate::config::{Config, resolve_shader_config};
pub(super) fn apply_renderer_config(
window_state: &mut WindowState,
config: &Config,
changes: &ConfigChanges,
) -> (Option<Option<String>>, Option<Option<String>>) {
let renderer = match &mut window_state.renderer {
Some(r) => r,
None => return (None, None),
};
renderer.update_opacity(config.window_opacity);
if changes.transparency_mode {
renderer.set_transparency_affects_only_default_background(
config.transparency_affects_only_default_background,
);
window_state.focus_state.needs_redraw = true;
}
if changes.keep_text_opaque {
renderer.set_keep_text_opaque(config.keep_text_opaque);
window_state.focus_state.needs_redraw = true;
}
if changes.link_underline_style {
renderer.set_link_underline_style(config.link_underline_style);
window_state.focus_state.needs_redraw = true;
}
if changes.vsync_mode {
let (actual_mode, _changed) = renderer.update_vsync_mode(config.vsync_mode);
if actual_mode != config.vsync_mode {
window_state.config.vsync_mode = actual_mode;
log::warn!(
"Vsync mode {:?} is not supported. Using {:?} instead.",
config.vsync_mode,
actual_mode
);
}
}
renderer.update_scrollbar_appearance(
config.scrollbar_width,
config.scrollbar_thumb_color,
config.scrollbar_track_color,
);
window_state.focus_state.needs_redraw = true;
if changes.cursor_color {
renderer.update_cursor_color(config.cursor_color);
}
if changes.cursor_text_color {
renderer.update_cursor_text_color(config.cursor_text_color);
}
if changes.cursor_style || changes.cursor_blink {
use crate::config::CursorStyle as ConfigCursorStyle;
use par_term_emu_core_rust::cursor::CursorStyle as TermCursorStyle;
let term_style = if config.cursor_blink {
match config.cursor_style {
ConfigCursorStyle::Block => TermCursorStyle::BlinkingBlock,
ConfigCursorStyle::Beam => TermCursorStyle::BlinkingBar,
ConfigCursorStyle::Underline => TermCursorStyle::BlinkingUnderline,
}
} else {
match config.cursor_style {
ConfigCursorStyle::Block => TermCursorStyle::SteadyBlock,
ConfigCursorStyle::Beam => TermCursorStyle::SteadyBar,
ConfigCursorStyle::Underline => TermCursorStyle::SteadyUnderline,
}
};
for tab in window_state.tab_manager.tabs_mut() {
if let Ok(mut term) = tab.terminal.try_write() {
term.set_cursor_style(term_style);
}
tab.active_cache_mut().cells = None; }
window_state.focus_state.needs_redraw = true;
}
if changes.cursor_enhancements {
if let Some(renderer) = &mut window_state.renderer {
renderer.update_cursor_guide(config.cursor_guide_enabled, config.cursor_guide_color);
renderer.update_cursor_shadow(
config.cursor_shadow_enabled,
config.cursor_shadow_color,
config.cursor_shadow_offset,
config.cursor_shadow_blur,
);
renderer.update_cursor_boost(config.cursor_boost, config.cursor_boost_color);
renderer.update_unfocused_cursor_style(config.unfocused_cursor_style);
}
window_state.focus_state.needs_redraw = true;
}
if changes.command_separator {
if let Some(renderer) = &mut window_state.renderer {
renderer.update_command_separator(
config.command_separator_enabled,
config.command_separator_thickness,
config.command_separator_opacity,
config.command_separator_exit_color,
config.command_separator_color,
);
}
window_state.focus_state.needs_redraw = true;
}
if changes.any_bg_change() {
let expanded_path = config.background_image.as_ref().map(|p| {
if let Some(rest) = p.strip_prefix("~/")
&& let Some(home) = dirs::home_dir()
{
return home.join(rest).to_string_lossy().to_string();
}
p.clone()
});
if let Some(renderer) = &mut window_state.renderer {
renderer.set_background(
config.background_mode,
config.background_color,
expanded_path.as_deref(),
config.background_image_mode,
config.background_image_opacity,
config.background_image_enabled,
);
}
window_state.focus_state.needs_redraw = true;
}
if changes.pane_backgrounds {
if let Some(renderer) = &mut window_state.renderer {
for pb_config in &config.pane_backgrounds {
if let Err(e) = renderer.load_pane_background(&pb_config.image) {
log::error!(
"Failed to load pane {} background '{}': {}",
pb_config.index,
pb_config.image,
e
);
}
}
}
for tab in window_state.tab_manager.tabs_mut() {
if let Some(pm) = tab.pane_manager_mut() {
let panes = pm.all_panes_mut();
for (index, pane) in panes.into_iter().enumerate() {
if let Some((image_path, mode, opacity, darken)) =
config.get_pane_background(index)
{
let bg = crate::pane::PaneBackground {
image_path: Some(image_path),
mode,
opacity,
darken,
};
pane.set_background(bg);
} else {
pane.set_background(crate::pane::PaneBackground::new());
}
}
}
}
if let Some(renderer) = &mut window_state.renderer {
renderer.mark_dirty();
}
window_state.focus_state.needs_redraw = true;
}
if changes.image_scaling_mode {
if let Some(renderer) = &mut window_state.renderer {
renderer.update_image_scaling_mode(config.image_scaling_mode);
}
window_state.focus_state.needs_redraw = true;
}
if changes.image_preserve_aspect_ratio {
if let Some(renderer) = &mut window_state.renderer {
renderer.update_image_preserve_aspect_ratio(config.image_preserve_aspect_ratio);
}
window_state.focus_state.needs_redraw = true;
}
if changes.theme {
let theme = config.load_theme();
for tab in window_state.tab_manager.tabs_mut() {
if let Ok(mut term) = tab.terminal.try_write() {
term.set_theme(theme.clone());
}
let tab_terminal = Arc::clone(&tab.terminal);
if let Some(pm) = tab.pane_manager_mut() {
for pane in pm.all_panes() {
if !Arc::ptr_eq(&pane.terminal, &tab_terminal)
&& let Ok(mut term) = pane.terminal.try_write()
{
term.set_theme(theme.clone());
}
}
}
}
}
if changes.answerback_string {
let answerback = if config.answerback_string.is_empty() {
None
} else {
Some(config.answerback_string.clone())
};
for tab in window_state.tab_manager.tabs_mut() {
if let Ok(term) = tab.terminal.try_write() {
term.set_answerback_string(answerback.clone());
}
}
}
if changes.unicode_width {
let width_config = par_term_emu_core_rust::WidthConfig::new(
config.unicode.unicode_version,
config.unicode.ambiguous_width,
);
for tab in window_state.tab_manager.tabs_mut() {
if let Ok(term) = tab.terminal.try_write() {
term.set_width_config(width_config);
}
}
}
if changes.normalization_form {
for tab in window_state.tab_manager.tabs_mut() {
if let Ok(term) = tab.terminal.try_write() {
term.set_normalization_form(config.unicode.normalization_form);
}
}
}
let shader_override = config
.shader
.custom_shader
.as_ref()
.and_then(|name| config.shader_configs.get(name));
let metadata = config.shader.custom_shader.as_ref().and_then(|name| {
window_state
.shader_state
.shader_metadata_cache
.get(name)
.cloned()
});
let resolved = resolve_shader_config(shader_override, metadata.as_ref(), config);
let shader_result = if changes.any_shader_change() || changes.shader_per_shader_config {
log::info!(
"SETTINGS: applying shader change: {:?} -> {:?}",
window_state.config.shader.custom_shader,
config.shader.custom_shader
);
window_state.renderer.as_mut().map(|r| {
r.set_custom_shader_enabled(
par_term_render::renderer::shaders::CustomShaderEnableParams {
enabled: config.shader.custom_shader_enabled,
shader_path: config.shader.custom_shader.as_deref(),
window_opacity: config.window_opacity,
animation_enabled: config.shader.custom_shader_animation,
animation_speed: resolved.animation_speed,
full_content: resolved.full_content,
brightness: resolved.brightness,
channel_paths: &resolved.channel_paths(),
cubemap_path: resolved.cubemap_path().map(|p| p.as_path()),
},
)
.err()
})
} else {
None };
if (changes.any_shader_change()
|| changes.shader_use_background_as_channel0
|| changes.any_bg_change()
|| changes.shader_per_shader_config)
&& let Some(renderer) = &mut window_state.renderer
{
renderer.update_background_as_channel0_with_mode(
resolved.use_background_as_channel0,
config.background_mode,
config.background_color,
);
}
let cursor_result = if changes.any_cursor_shader_toggle() {
window_state.renderer.as_mut().map(|r| {
r.set_cursor_shader_enabled(
config.shader.cursor_shader_enabled,
config.shader.cursor_shader.as_deref(),
config.window_opacity,
config.shader.cursor_shader_animation,
config.shader.cursor_shader_animation_speed,
)
.err()
})
} else {
None };
(shader_result, cursor_result)
}