diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-04-21 17:37:41 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-04-21 17:37:41 +0300 |
| commit | b1c9833b828d12e7e0196c5607ae63372998e25a (patch) | |
| tree | c8b1ff84cea1cf4367c5163e4721d028cf7856cf /src | |
| parent | 8a4571198d013451743d1238f80a6bd69d67b32d (diff) | |
fix: stop headless idle spin and skip unnecessary macos probes
Diffstat (limited to 'src')
| -rw-r--r-- | src/app/mod.rs | 29 | ||||
| -rw-r--r-- | src/app/runtime.rs | 19 | ||||
| -rw-r--r-- | src/pane/terminal.rs | 98 | ||||
| -rw-r--r-- | src/server/headless.rs | 2 |
4 files changed, 146 insertions, 2 deletions
diff --git a/src/app/mod.rs b/src/app/mod.rs index 51a6678e..a598100a 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1148,6 +1148,35 @@ mod tests { } #[test] + fn headless_next_loop_deadline_ignores_resize_poll() { + let mut app = test_app(); + let now = Instant::now(); + app.next_resize_poll = now + Duration::from_millis(100); + app.session_save_deadline = Some(now + Duration::from_secs(2)); + app.next_auto_update_check = Some(now + Duration::from_secs(6)); + + assert_eq!( + app.next_headless_loop_deadline(now, false), + app.session_save_deadline + ); + } + + #[test] + fn headless_next_loop_deadline_returns_none_when_resize_poll_is_only_deadline() { + let mut app = test_app(); + let now = Instant::now(); + app.next_resize_poll = now - Duration::from_millis(1); + app.config_diagnostic_deadline = None; + app.toast_deadline = None; + app.next_animation_tick = None; + app.next_auto_update_check = None; + app.session_save_deadline = None; + app.state.workspaces.clear(); + + assert_eq!(app.next_headless_loop_deadline(now, false), None); + } + + #[test] fn due_session_save_deadline_is_cleared() { let mut app = test_app(); app.session_save_deadline = Some(Instant::now() - Duration::from_secs(1)); diff --git a/src/app/runtime.rs b/src/app/runtime.rs index d82f6440..b6ad806b 100644 --- a/src/app/runtime.rs +++ b/src/app/runtime.rs @@ -227,6 +227,23 @@ impl App { } pub(crate) fn next_loop_deadline(&self, now: Instant, needs_render: bool) -> Option<Instant> { + self.next_loop_deadline_with_resize_poll(now, needs_render, true) + } + + pub(crate) fn next_headless_loop_deadline( + &self, + now: Instant, + needs_render: bool, + ) -> Option<Instant> { + self.next_loop_deadline_with_resize_poll(now, needs_render, false) + } + + fn next_loop_deadline_with_resize_poll( + &self, + now: Instant, + needs_render: bool, + include_resize_poll: bool, + ) -> Option<Instant> { let render_deadline = if needs_render { self.last_render_at .map(|last_render_at| last_render_at + MIN_RENDER_INTERVAL) @@ -236,7 +253,7 @@ impl App { }; [ - Some(self.next_resize_poll), + include_resize_poll.then_some(self.next_resize_poll), self.config_diagnostic_deadline, self.toast_deadline, self.next_animation_tick, diff --git a/src/pane/terminal.rs b/src/pane/terminal.rs index 796220b9..28b4186e 100644 --- a/src/pane/terminal.rs +++ b/src/pane/terminal.rs @@ -237,6 +237,15 @@ impl GhosttyPaneTerminal { } pub fn maybe_restore_host_terminal_theme(&self, pane_id: PaneId, shell_pid: u32) -> bool { + { + let Ok(core) = self.core.lock() else { + return false; + }; + if !should_probe_host_terminal_theme_restore(&core) { + return false; + } + } + let foreground_job = crate::detect::foreground_job(shell_pid); let Ok(mut core) = self.core.lock() else { return false; @@ -883,6 +892,18 @@ fn recent_text_from_rows(rows: &[String], lines: usize) -> String { } } +fn should_probe_host_terminal_theme_restore(core: &GhosttyPaneCore) -> bool { + if core.transient_default_color_owner_pgid.is_none() || core.host_terminal_theme.is_empty() { + return false; + } + + !core + .terminal + .active_screen() + .map(|screen| screen == crate::ghostty::ActiveScreen::Alternate) + .unwrap_or(false) +} + #[cfg(test)] mod tests { use super::*; @@ -896,6 +917,83 @@ mod tests { } #[test] + fn host_terminal_theme_restore_probe_skips_when_no_transient_override() { + let (tx, _rx) = mpsc::channel(4); + let terminal = crate::ghostty::Terminal::new(80, 24, 0).unwrap(); + let pane = GhosttyPaneTerminal::new(terminal, tx).unwrap(); + let core = pane.core.lock().unwrap(); + + assert!(!should_probe_host_terminal_theme_restore(&core)); + } + + #[test] + fn host_terminal_theme_restore_probe_skips_when_host_theme_unknown() { + let (tx, _rx) = mpsc::channel(4); + let terminal = crate::ghostty::Terminal::new(80, 24, 0).unwrap(); + let pane = GhosttyPaneTerminal::new(terminal, tx).unwrap(); + { + let mut core = pane.core.lock().unwrap(); + core.transient_default_color_owner_pgid = Some(42); + } + let core = pane.core.lock().unwrap(); + + assert!(!should_probe_host_terminal_theme_restore(&core)); + } + + #[test] + fn host_terminal_theme_restore_probe_skips_on_alternate_screen() { + let (tx, _rx) = mpsc::channel(4); + let mut terminal = crate::ghostty::Terminal::new(80, 24, 0).unwrap(); + terminal.write(b"\x1b[?1049h"); + let pane = GhosttyPaneTerminal::new(terminal, tx).unwrap(); + { + let mut core = pane.core.lock().unwrap(); + core.transient_default_color_owner_pgid = Some(42); + core.host_terminal_theme = crate::terminal_theme::TerminalTheme { + foreground: Some(crate::terminal_theme::RgbColor { + r: 0xaa, + g: 0xbb, + b: 0xcc, + }), + background: Some(crate::terminal_theme::RgbColor { + r: 0x11, + g: 0x22, + b: 0x33, + }), + }; + } + let core = pane.core.lock().unwrap(); + + assert!(!should_probe_host_terminal_theme_restore(&core)); + } + + #[test] + fn host_terminal_theme_restore_probe_runs_when_restore_is_pending() { + let (tx, _rx) = mpsc::channel(4); + let terminal = crate::ghostty::Terminal::new(80, 24, 0).unwrap(); + let pane = GhosttyPaneTerminal::new(terminal, tx).unwrap(); + { + let mut core = pane.core.lock().unwrap(); + core.transient_default_color_owner_pgid = Some(42); + core.host_terminal_theme = crate::terminal_theme::TerminalTheme { + foreground: Some(crate::terminal_theme::RgbColor { + r: 0xaa, + g: 0xbb, + b: 0xcc, + }), + background: Some(crate::terminal_theme::RgbColor { + r: 0x11, + g: 0x22, + b: 0x33, + }), + }; + } + let core = pane.core.lock().unwrap(); + + assert!(should_probe_host_terminal_theme_restore(&core)); + } + + #[test] fn ghostty_render_can_suppress_cursor_position() { let (tx, _rx) = mpsc::channel(4); let mut first_terminal = crate::ghostty::Terminal::new(20, 5, 0).unwrap(); diff --git a/src/server/headless.rs b/src/server/headless.rs index ba6098df..d120d21b 100644 --- a/src/server/headless.rs +++ b/src/server/headless.rs @@ -477,7 +477,7 @@ impl HeadlessServer { } // 8. Wait for next event. - let next_deadline = self.app.next_loop_deadline(now, needs_render); + let next_deadline = self.app.next_headless_loop_deadline(now, needs_render); let event = { tokio::select! { maybe_api = self.app.api_rx.recv() => match maybe_api { |
