Skip to main content

par_term/app/
mod.rs

1//! Application module for par-term
2//!
3//! This module contains the main application logic, including:
4//! - `App`: Entry point that initializes and runs the event loop
5//! - `WindowManager`: Manages multiple windows and coordinates menu events
6//! - `WindowState`: Per-window state including terminal, renderer, and UI
7
8use crate::cli::RuntimeOptions;
9use crate::config::Config;
10use anyhow::Result;
11use std::sync::Arc;
12use tokio::runtime::Runtime;
13use winit::event_loop::{ControlFlow, EventLoop};
14/// Events injected into the winit event loop by platform observers.
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub(crate) enum AppEvent {
17    /// The macOS display topology or parameters changed.
18    #[cfg(target_os = "macos")]
19    DisplayConfigurationChanged,
20}
21
22pub(crate) mod display_recovery;
23
24pub(crate) mod copy_mode;
25mod file_transfers;
26pub mod handler;
27pub mod input_events;
28pub mod mouse_events;
29pub(crate) mod render_pipeline;
30pub mod tab_ops;
31mod tmux_handler;
32mod triggers;
33pub mod window_manager;
34pub mod window_state;
35
36pub(crate) use window_manager::WindowManager;
37
38/// Main application entry point
39pub struct App {
40    config: Config,
41    runtime: Arc<Runtime>,
42    runtime_options: RuntimeOptions,
43}
44
45impl App {
46    /// Create a new application
47    pub fn new(runtime: Arc<Runtime>, runtime_options: RuntimeOptions) -> Result<Self> {
48        let mut config = Config::load()?;
49
50        // Apply CLI shader override if specified
51        if let Some(ref shader) = runtime_options.shader {
52            config.shader.custom_shader = Some(shader.clone());
53            config.shader.custom_shader_enabled = true;
54            // Disable background image so it doesn't compete with the shader
55            config.background.background_image_enabled = false;
56            log::info!("CLI override: using shader '{}'", shader);
57        }
58
59        // Apply CLI session logging override if specified
60        if runtime_options.log_session {
61            config.session_log.auto_log_sessions = true;
62            log::info!("CLI override: session logging enabled");
63        }
64
65        // Apply config log level (unless CLI --log-level was specified)
66        if runtime_options.log_level.is_none() {
67            crate::debug::set_log_level(config.log_level.to_level_filter());
68            log::info!("Config log level: {}", config.log_level.display_name());
69        }
70
71        Ok(Self {
72            config,
73            runtime,
74            runtime_options,
75        })
76    }
77
78    /// Run the application
79    pub fn run(self) -> Result<()> {
80        let event_loop = EventLoop::<AppEvent>::with_user_event().build()?;
81
82        // Use Wait for power-efficient event handling
83        // Combined with WaitUntil in about_to_wait for precise timing
84        event_loop.set_control_flow(ControlFlow::Wait);
85        #[cfg(target_os = "macos")]
86        let _display_observer =
87            display_recovery::register_display_change_observer(event_loop.create_proxy());
88
89        let mut window_manager =
90            WindowManager::new(self.config, self.runtime, self.runtime_options);
91
92        event_loop.run_app(&mut window_manager)?;
93
94        Ok(())
95    }
96}