diff --git a/config/src/terminal.rs b/config/src/terminal.rs index 8ab92d0ef01..02da49176b2 100644 --- a/config/src/terminal.rs +++ b/config/src/terminal.rs @@ -17,6 +17,12 @@ impl TermConfig { } } + pub fn with_config(config: ConfigHandle) -> Self { + Self { + config: Mutex::new(Some(config)), + } + } + pub fn set_config(&self, config: ConfigHandle) { self.config.lock().unwrap().replace(config); } diff --git a/mux/src/localpane.rs b/mux/src/localpane.rs index 922905e583c..3021011c8f7 100644 --- a/mux/src/localpane.rs +++ b/mux/src/localpane.rs @@ -6,7 +6,7 @@ use crate::{Domain, Mux, MuxNotification}; use anyhow::Error; use async_trait::async_trait; use config::keyassignment::ScrollbackEraseMode; -use config::{configuration, ExitBehavior, TermConfig}; +use config::{configuration, ExitBehavior}; #[cfg(windows)] use filedescriptor::OwnedHandle; use portable_pty::{Child, ExitStatus, MasterPty, PtySize}; @@ -25,7 +25,7 @@ use url::Url; use wezterm_term::color::ColorPalette; use wezterm_term::{ Alert, AlertHandler, CellAttributes, Clipboard, KeyCode, KeyModifiers, MouseEvent, - SemanticZone, StableRowIndex, Terminal, + SemanticZone, StableRowIndex, Terminal, TerminalConfiguration, }; #[derive(Debug)] @@ -202,10 +202,14 @@ impl Pane for LocalPane { self.terminal.borrow_mut().set_clipboard(clipboard); } - fn set_config(&self, config: Arc) { + fn set_config(&self, config: Arc) { self.terminal.borrow_mut().set_config(config); } + fn get_config(&self) -> Option> { + Some(self.terminal.borrow().get_config()) + } + fn perform_actions(&self, actions: Vec) { self.terminal.borrow_mut().perform_actions(actions) } diff --git a/mux/src/pane.rs b/mux/src/pane.rs index e1d741f089f..17364fbadaa 100644 --- a/mux/src/pane.rs +++ b/mux/src/pane.rs @@ -3,7 +3,6 @@ use crate::renderable::*; use crate::Mux; use async_trait::async_trait; use config::keyassignment::ScrollbackEraseMode; -use config::TermConfig; use downcast_rs::{impl_downcast, Downcast}; use portable_pty::PtySize; use rangeset::RangeSet; @@ -16,7 +15,10 @@ use termwiz::hyperlink::Rule; use termwiz::surface::Line; use url::Url; use wezterm_term::color::ColorPalette; -use wezterm_term::{Clipboard, KeyCode, KeyModifiers, MouseEvent, SemanticZone, StableRowIndex}; +use wezterm_term::{ + Clipboard, KeyCode, KeyModifiers, MouseEvent, SemanticZone, StableRowIndex, + TerminalConfiguration, +}; static PANE_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::AtomicUsize::new(0); pub type PaneId = usize; @@ -341,7 +343,10 @@ pub trait Pane: Downcast { fn is_alt_screen_active(&self) -> bool; fn set_clipboard(&self, _clipboard: &Arc) {} - fn set_config(&self, _config: Arc) {} + fn set_config(&self, _config: Arc) {} + fn get_config(&self) -> Option> { + None + } fn get_current_working_dir(&self) -> Option; diff --git a/term/src/terminalstate.rs b/term/src/terminalstate.rs index 19eee93adf6..7616cdd1ac4 100644 --- a/term/src/terminalstate.rs +++ b/term/src/terminalstate.rs @@ -518,6 +518,10 @@ impl TerminalState { self.config = config; } + pub fn get_config(&self) -> Arc { + Arc::clone(&self.config) + } + pub fn set_clipboard(&mut self, clipboard: &Arc) { self.clipboard.replace(Arc::clone(clipboard)); } diff --git a/wezterm-gui/src/overlay/launcher.rs b/wezterm-gui/src/overlay/launcher.rs index f7a52c9cfb5..7ab1cf04cfd 100644 --- a/wezterm-gui/src/overlay/launcher.rs +++ b/wezterm-gui/src/overlay/launcher.rs @@ -9,14 +9,15 @@ use crate::termwindow::clipboard::ClipboardHelper; use crate::termwindow::spawn::SpawnWhere; use crate::termwindow::TermWindow; use anyhow::anyhow; -use config::configuration; use config::keyassignment::{SpawnCommand, SpawnTabDomain}; +use config::{configuration, TermConfig}; use mux::domain::{DomainId, DomainState}; use mux::tab::TabId; use mux::termwiztermtab::TermWizTerminal; use mux::window::WindowId; use mux::Mux; use portable_pty::PtySize; +use std::sync::Arc; use termwiz::cell::{AttributeChange, CellAttributes}; use termwiz::color::ColorAttribute; use termwiz::input::{InputEvent, KeyCode, KeyEvent, MouseButtons, MouseEvent}; @@ -106,6 +107,7 @@ pub fn launcher( domains: Vec<(DomainId, String, DomainState, String)>, clipboard: ClipboardHelper, size: PtySize, + term_config: Arc, ) -> anyhow::Result<()> { let mut active_idx = 0; let mut entries = vec![]; @@ -205,6 +207,7 @@ pub fn launcher( size: PtySize, mux_window_id: WindowId, clipboard: ClipboardHelper, + term_config: Arc, ) { match entries[active_idx].clone() { Entry::Spawn { @@ -219,6 +222,7 @@ pub fn launcher( size, mux_window_id, clipboard, + term_config, ); }) .detach(); @@ -270,7 +274,14 @@ pub fn launcher( active_idx = y as usize - 1; if mouse_buttons == MouseButtons::LEFT { - launch(active_idx, &entries, size, mux_window_id, clipboard); + launch( + active_idx, + &entries, + size, + mux_window_id, + clipboard, + term_config, + ); break; } } @@ -283,7 +294,14 @@ pub fn launcher( key: KeyCode::Enter, .. }) => { - launch(active_idx, &entries, size, mux_window_id, clipboard); + launch( + active_idx, + &entries, + size, + mux_window_id, + clipboard, + term_config, + ); break; } _ => {} diff --git a/wezterm-gui/src/scripting/guiwin.rs b/wezterm-gui/src/scripting/guiwin.rs index de31b3df4f6..e365825a756 100644 --- a/wezterm-gui/src/scripting/guiwin.rs +++ b/wezterm-gui/src/scripting/guiwin.rs @@ -9,7 +9,7 @@ use mlua::{UserData, UserDataMethods}; use mux::window::WindowId as MuxWindowId; use serde::*; use wezterm_toast_notification::ToastNotification; -use window::WindowOps; +use window::{Connection, ConnectionOps, WindowOps}; #[derive(Clone)] pub struct GuiWin { @@ -43,6 +43,9 @@ impl UserData for GuiWin { Ok(()) }, ); + methods.add_method("get_appearance", |_, _, _: ()| { + Ok(Connection::get().unwrap().get_appearance().to_string()) + }); methods.add_method("set_right_status", |_, this, status: String| { this.window.notify(TermWindowNotif::SetRightStatus(status)); Ok(()) diff --git a/wezterm-gui/src/termwindow/mod.rs b/wezterm-gui/src/termwindow/mod.rs index 6e4c567766b..bfcf081bc1c 100644 --- a/wezterm-gui/src/termwindow/mod.rs +++ b/wezterm-gui/src/termwindow/mod.rs @@ -527,6 +527,7 @@ impl TermWindow { myself.gl.replace(Rc::clone(&gl)); myself.created(&window, Rc::clone(&gl))?; myself.subscribe_to_pane_updates(); + myself.emit_window_event("window-config-reloaded"); myself.emit_status_event(); } @@ -545,6 +546,10 @@ impl TermWindow { self.close_requested(window); Ok(true) } + WindowEvent::AppearanceChanged(_appearance) => { + self.config_was_reloaded(); + Ok(true) + } WindowEvent::FocusChanged(focused) => { self.focus_changed(focused, window); Ok(true) @@ -1012,9 +1017,8 @@ impl TermWindow { } if let Some(window) = mux.get_window(self.mux_window_id) { - let term_config = TermConfig::new(); - term_config.set_config(config.clone()); - let term_config = Arc::new(term_config); + let term_config: Arc = + Arc::new(TermConfig::with_config(config.clone())); for tab in window.iter() { for pane in tab.iter_panes() { pane.pane.set_config(Arc::clone(&term_config)); @@ -1413,6 +1417,7 @@ impl TermWindow { .expect("tab has no panes!") .domain_id(); let size = self.terminal_size; + let term_config = Arc::new(TermConfig::with_config(self.config.clone())); let (overlay, future) = start_overlay(self, &tab, move |tab_id, term| { launcher( @@ -1423,6 +1428,7 @@ impl TermWindow { domains, clipboard, size, + term_config, ) }); self.assign_overlay(tab.tab_id(), overlay); diff --git a/wezterm-gui/src/termwindow/spawn.rs b/wezterm-gui/src/termwindow/spawn.rs index 5caf3066c44..ea06097c4c4 100644 --- a/wezterm-gui/src/termwindow/spawn.rs +++ b/wezterm-gui/src/termwindow/spawn.rs @@ -1,6 +1,7 @@ use crate::termwindow::{ClipboardHelper, MuxWindowId}; use anyhow::{anyhow, bail}; use config::keyassignment::{SpawnCommand, SpawnTabDomain}; +use config::TermConfig; use mux::activity::Activity; use mux::domain::DomainState; use mux::tab::SplitDirection; @@ -23,6 +24,8 @@ impl super::TermWindow { } else { self.terminal_size }; + let term_config = Arc::new(TermConfig::with_config(self.config.clone())); + Self::spawn_command_impl( spawn, spawn_where, @@ -31,6 +34,7 @@ impl super::TermWindow { ClipboardHelper { window: self.window.as_ref().unwrap().clone(), }, + term_config, ) } @@ -40,13 +44,20 @@ impl super::TermWindow { size: PtySize, src_window_id: MuxWindowId, clipboard: ClipboardHelper, + term_config: Arc, ) { let spawn = spawn.clone(); promise::spawn::spawn(async move { - if let Err(err) = - Self::spawn_command_internal(spawn, spawn_where, size, src_window_id, clipboard) - .await + if let Err(err) = Self::spawn_command_internal( + spawn, + spawn_where, + size, + src_window_id, + clipboard, + term_config, + ) + .await { log::error!("Failed to spawn: {:#}", err); } @@ -60,6 +71,7 @@ impl super::TermWindow { size: PtySize, src_window_id: MuxWindowId, clipboard: ClipboardHelper, + term_config: Arc, ) -> anyhow::Result<()> { let mux = Mux::get().unwrap(); let activity = Activity::new(); @@ -173,9 +185,10 @@ impl super::TermWindow { let pane = domain .split_pane(cmd_builder, cwd, tab.tab_id(), pane.pane_id(), direction) .await?; + pane.set_config(term_config); pane.set_clipboard(&clipboard); } else { - log::error!("there is no active tab while splitting pane!?"); + bail!("there is no active tab while splitting pane!?"); } } _ => { @@ -186,6 +199,7 @@ impl super::TermWindow { let pane = tab .get_active_pane() .ok_or_else(|| anyhow!("newly spawned tab to have a pane"))?; + pane.set_config(term_config); if spawn_where != SpawnWhere::NewWindow { pane.set_clipboard(&clipboard); diff --git a/wezterm-mux-server-impl/src/sessionhandler.rs b/wezterm-mux-server-impl/src/sessionhandler.rs index 01d128b6798..2d2920ed88d 100644 --- a/wezterm-mux-server-impl/src/sessionhandler.rs +++ b/wezterm-mux-server-impl/src/sessionhandler.rs @@ -648,6 +648,11 @@ async fn split_pane(split: SplitPane, sender: PduSender) -> anyhow::Result }; let pane_id = split.pane_id; + let current_pane = mux + .get_pane(pane_id) + .ok_or_else(|| anyhow!("pane_id {} is invalid", pane_id))?; + let term_config = current_pane.get_config(); + let cwd = split.command_dir.or_else(|| { mux.get_pane(pane_id) .and_then(|pane| pane.get_current_working_dir()) @@ -686,6 +691,9 @@ async fn split_pane(split: SplitPane, sender: PduSender) -> anyhow::Result sender, }); pane.set_clipboard(&clip); + if let Some(config) = term_config { + pane.set_config(config); + } Ok::(Pdu::SpawnResponse(SpawnResponse { pane_id: pane.pane_id(), @@ -745,12 +753,23 @@ async fn domain_spawn_v2(spawn: SpawnV2, sender: PduSender) -> anyhow::Result anyhow::Result = Arc::new(RemoteClipboard { pane_id: pane.pane_id(), sender, diff --git a/window/examples/async.rs b/window/examples/async.rs index 56699a13774..1f78935fc71 100644 --- a/window/examples/async.rs +++ b/window/examples/async.rs @@ -70,7 +70,9 @@ impl MyWindow { win.finish_frame(frame).unwrap(); } } - WindowEvent::Notification(_) | WindowEvent::FocusChanged(_) => {} + WindowEvent::AppearanceChanged(_) + | WindowEvent::Notification(_) + | WindowEvent::FocusChanged(_) => {} } } } diff --git a/window/examples/wgpu.rs b/window/examples/wgpu.rs index f152507f8f2..d90d11b35bf 100644 --- a/window/examples/wgpu.rs +++ b/window/examples/wgpu.rs @@ -245,7 +245,9 @@ impl MyWindow { WindowEvent::NeedRepaint => { self.paint(win).unwrap(); } - WindowEvent::Notification(_) | WindowEvent::FocusChanged(_) => {} + WindowEvent::AppearanceChanged(_) + | WindowEvent::Notification(_) + | WindowEvent::FocusChanged(_) => {} } } } diff --git a/window/src/lib.rs b/window/src/lib.rs index 2a5632712dc..1937a0f67f2 100644 --- a/window/src/lib.rs +++ b/window/src/lib.rs @@ -123,6 +123,8 @@ pub enum WindowEvent { MouseEvent(MouseEvent), + AppearanceChanged(Appearance), + Notification(Box), } @@ -144,8 +146,10 @@ impl WindowEventSender { } pub fn dispatch(&mut self, event: WindowEvent) { - log::trace!("{:?}", event); - (self.handler)(event, self.window.as_ref().unwrap()); + if let Some(window) = self.window.as_ref() { + log::trace!("{:?}", event); + (self.handler)(event, window); + } } } diff --git a/window/src/os/macos/window.rs b/window/src/os/macos/window.rs index 90c4531f6e1..35fba6b6800 100644 --- a/window/src/os/macos/window.rs +++ b/window/src/os/macos/window.rs @@ -1476,6 +1476,16 @@ impl WindowView { YES } + extern "C" fn view_did_change_effective_appearance(this: &mut Object, _sel: Sel) { + if let Some(this) = Self::get_this(this) { + let appearance = Connection::get().unwrap().get_appearance(); + this.inner + .borrow_mut() + .events + .dispatch(WindowEvent::AppearanceChanged(appearance)); + } + } + extern "C" fn window_should_close(this: &mut Object, _sel: Sel, _id: id) -> BOOL { unsafe { let () = msg_send![this, setNeedsDisplay: YES]; @@ -2100,6 +2110,11 @@ impl WindowView { Self::accepts_first_mouse as extern "C" fn(&mut Object, Sel, id) -> BOOL, ); + cls.add_method( + sel!(viewDidChangeEffectiveAppearance), + Self::view_did_change_effective_appearance as extern "C" fn(&mut Object, Sel), + ); + // NSTextInputClient cls.add_method(