diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-25 18:39:44 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-25 18:42:33 +0300 |
| commit | 58bcd76bfdb76ecbb8cfee868dabe60b43f16cc6 (patch) | |
| tree | dad4b122401b87c9bc9b8e5b46b854c9534fc983 /src/app | |
| parent | ac9dac0263ba2336710e8fc350600ff8674ebf99 (diff) | |
feat: make focus-gain redraw configurable
refs #282
Diffstat (limited to 'src/app')
| -rw-r--r-- | src/app/mod.rs | 38 | ||||
| -rw-r--r-- | src/app/runtime.rs | 4 | ||||
| -rw-r--r-- | src/app/state.rs | 6 |
3 files changed, 42 insertions, 6 deletions
diff --git a/src/app/mod.rs b/src/app/mod.rs index bcbd40cf..0b4c792c 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -386,7 +386,7 @@ impl App { request_submit_worktree_open: false, request_submit_worktree_remove: false, request_reload_config: false, - request_client_sound_config_reload: false, + request_client_config_reload: false, request_clipboard_write: None, creating_new_tab: false, requested_new_tab_name: None, @@ -458,6 +458,7 @@ impl App { sidebar_section_split, agent_panel_scope, mouse_capture: config.ui.mouse_capture, + redraw_on_focus_gained: config.ui.redraw_on_focus_gained, mouse_scroll_lines: config.ui.mouse_scroll_lines(), confirm_close: config.ui.confirm_close, prompt_new_tab_name: config.ui.prompt_new_tab_name, @@ -1055,6 +1056,10 @@ impl App { .sidebar_width .clamp(self.state.sidebar_min_width, self.state.sidebar_max_width); self.state.mouse_capture = config.ui.mouse_capture; + if self.state.redraw_on_focus_gained != config.ui.redraw_on_focus_gained { + self.state.request_client_config_reload = true; + } + self.state.redraw_on_focus_gained = config.ui.redraw_on_focus_gained; self.state.mouse_scroll_lines = config.ui.mouse_scroll_lines(); self.state.confirm_close = config.ui.confirm_close; self.state.prompt_new_tab_name = config.ui.prompt_new_tab_name; @@ -1065,7 +1070,7 @@ impl App { self.state.agent_panel_scroll = 0; self.state.accent = crate::config::parse_color(&config.ui.accent); if !self.state.local_sound_playback && self.state.sound != config.ui.sound { - self.state.request_client_sound_config_reload = true; + self.state.request_client_config_reload = true; } self.state.sound = config.ui.sound.clone(); self.state.toast_config = config.ui.toast.clone(); @@ -1501,6 +1506,17 @@ mod tests { } #[test] + fn startup_uses_redraw_on_focus_gained_config() { + let mut config = Config::default(); + config.ui.redraw_on_focus_gained = false; + let (_api_tx, api_rx) = tokio::sync::mpsc::unbounded_channel(); + + let app = App::new(&config, true, None, api_rx, crate::api::EventHub::default()); + + assert!(!app.state.redraw_on_focus_gained); + } + + #[test] fn startup_restores_preview_update_available_from_saved_notes() { let _guard = config_env_lock().lock().unwrap(); let path = temp_config_path("startup-preview-update-available"); @@ -1610,7 +1626,7 @@ mod tests { std::fs::create_dir_all(path.parent().unwrap()).unwrap(); std::fs::write( &path, - "[terminal]\ndefault_shell = \"nu\"\nnew_cwd = \"home\"\n[keys]\nnew_workspace = \"prefix+m\"\nprefix = \"ctrl+a\"\n[ui]\nagent_panel_scope = \"current\"\n[ui.toast]\ndelivery = \"herdr\"\n", + "[terminal]\ndefault_shell = \"nu\"\nnew_cwd = \"home\"\n[keys]\nnew_workspace = \"prefix+m\"\nprefix = \"ctrl+a\"\n[ui]\nagent_panel_scope = \"current\"\nredraw_on_focus_gained = false\n[ui.toast]\ndelivery = \"herdr\"\n", ) .unwrap(); std::env::set_var(crate::config::CONFIG_PATH_ENV_VAR, &path); @@ -1634,6 +1650,8 @@ mod tests { app.state.agent_panel_scope, state::AgentPanelScope::CurrentWorkspace ); + assert!(!app.state.redraw_on_focus_gained); + assert!(app.state.request_client_config_reload); assert_eq!(app.state.default_shell, "nu"); assert_eq!( app.state.new_terminal_cwd, @@ -2074,6 +2092,20 @@ mod tests { } #[tokio::test] + async fn outer_focus_gained_does_not_require_full_redraw_when_disabled() { + let mut app = test_app(); + app.state.redraw_on_focus_gained = false; + + let handled = app + .handle_raw_input_event(crate::raw_input::RawInputEvent::OuterFocusGained) + .await; + + assert!(handled); + assert_eq!(app.state.outer_terminal_focus, Some(true)); + assert!(!app.full_redraw_pending); + } + + #[tokio::test] async fn repeat_key_events_are_ignored_outside_terminal_mode() { let mut app = test_app(); app.state.mode = Mode::ReleaseNotes; diff --git a/src/app/runtime.rs b/src/app/runtime.rs index 284fb882..85bdb8dd 100644 --- a/src/app/runtime.rs +++ b/src/app/runtime.rs @@ -106,7 +106,9 @@ impl App { true } crate::raw_input::RawInputEvent::OuterFocusGained => { - self.request_full_redraw(); + if self.state.redraw_on_focus_gained { + self.request_full_redraw(); + } self.state.outer_terminal_focus = Some(true); self.state.mark_active_tab_seen(); true diff --git a/src/app/state.rs b/src/app/state.rs index 422664ff..b22dc6a3 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -1057,7 +1057,7 @@ pub struct AppState { pub request_reload_config: bool, /// Set when the headless server should ask attached clients to reload /// their client-local sound config from disk. - pub request_client_sound_config_reload: bool, + pub request_client_config_reload: bool, /// Set when UI interaction requested a clipboard write that must be /// handled by the outer App/event loop instead of directly from AppState. pub request_clipboard_write: Option<Vec<u8>>, @@ -1115,6 +1115,7 @@ pub struct AppState { /// Capture mouse input for Herdr's own mouse UI. When false, Herdr only /// captures mouse while the focused pane app requests mouse reporting. pub mouse_capture: bool, + pub redraw_on_focus_gained: bool, pub mouse_scroll_lines: usize, pub confirm_close: bool, pub prompt_new_tab_name: bool, @@ -1351,7 +1352,7 @@ impl AppState { request_submit_worktree_open: false, request_submit_worktree_remove: false, request_reload_config: false, - request_client_sound_config_reload: false, + request_client_config_reload: false, request_clipboard_write: None, creating_new_tab: false, requested_new_tab_name: None, @@ -1414,6 +1415,7 @@ impl AppState { sidebar_section_split: 0.5, agent_panel_scope: AgentPanelScope::AllWorkspaces, mouse_capture: true, + redraw_on_focus_gained: true, mouse_scroll_lines: crate::config::DEFAULT_MOUSE_SCROLL_LINES, confirm_close: true, prompt_new_tab_name: true, |
