| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- use crate::{
- constants::{UPDATER_ENABLED, window_state_flags},
- server::get_wsl_config,
- };
- use std::{ops::Deref, time::Duration};
- use tauri::{AppHandle, Manager, Runtime, WebviewUrl, WebviewWindow, WebviewWindowBuilder};
- use tauri_plugin_window_state::AppHandleExt;
- use tokio::sync::mpsc;
- #[cfg(target_os = "linux")]
- use std::sync::OnceLock;
- #[cfg(target_os = "linux")]
- fn use_decorations() -> bool {
- static DECORATIONS: OnceLock<bool> = OnceLock::new();
- *DECORATIONS.get_or_init(|| {
- crate::linux_windowing::use_decorations(&crate::linux_windowing::SessionEnv::capture())
- })
- }
- #[cfg(not(target_os = "linux"))]
- fn use_decorations() -> bool {
- true
- }
- pub struct MainWindow(WebviewWindow);
- impl Deref for MainWindow {
- type Target = WebviewWindow;
- fn deref(&self) -> &Self::Target {
- &self.0
- }
- }
- impl MainWindow {
- pub const LABEL: &str = "main";
- pub fn create(app: &AppHandle) -> Result<Self, tauri::Error> {
- if let Some(window) = app.get_webview_window(Self::LABEL) {
- let _ = window.set_focus();
- let _ = window.unminimize();
- return Ok(Self(window));
- }
- let wsl_enabled = get_wsl_config(app.clone())
- .ok()
- .map(|v| v.enabled)
- .unwrap_or(false);
- let decorations = use_decorations();
- let window_builder = base_window_config(
- WebviewWindowBuilder::new(app, Self::LABEL, WebviewUrl::App("/".into())),
- app,
- decorations,
- )
- .title("OpenCode")
- .disable_drag_drop_handler()
- .zoom_hotkeys_enabled(false)
- .visible(true)
- .maximized(true)
- .initialization_script(format!(
- r#"
- window.__OPENCODE__ ??= {{}};
- window.__OPENCODE__.updaterEnabled = {UPDATER_ENABLED};
- window.__OPENCODE__.wsl = {wsl_enabled};
- "#
- ));
- let window = window_builder.build()?;
- // Ensure window is focused after creation (e.g., after update/relaunch)
- let _ = window.set_focus();
- setup_window_state_listener(app, &window);
- #[cfg(windows)]
- {
- use tauri_plugin_decorum::WebviewWindowExt;
- let _ = window.create_overlay_titlebar();
- }
- Ok(Self(window))
- }
- }
- fn setup_window_state_listener(app: &AppHandle, window: &WebviewWindow) {
- let (tx, mut rx) = mpsc::channel::<()>(1);
- window.on_window_event(move |event| {
- use tauri::WindowEvent;
- if !matches!(event, WindowEvent::Moved(_) | WindowEvent::Resized(_)) {
- return;
- }
- let _ = tx.try_send(());
- });
- tokio::spawn({
- let app = app.clone();
- async move {
- let save = || {
- let handle = app.clone();
- let app = app.clone();
- let _ = handle.run_on_main_thread(move || {
- let _ = app.save_window_state(window_state_flags());
- });
- };
- while rx.recv().await.is_some() {
- tokio::time::sleep(Duration::from_millis(200)).await;
- save();
- }
- }
- });
- }
- pub struct LoadingWindow(WebviewWindow);
- impl Deref for LoadingWindow {
- type Target = WebviewWindow;
- fn deref(&self) -> &Self::Target {
- &self.0
- }
- }
- impl LoadingWindow {
- pub const LABEL: &str = "loading";
- pub fn create(app: &AppHandle) -> Result<Self, tauri::Error> {
- let decorations = use_decorations();
- let window_builder = base_window_config(
- WebviewWindowBuilder::new(app, Self::LABEL, tauri::WebviewUrl::App("/loading".into())),
- app,
- decorations,
- )
- .center()
- .resizable(false)
- .inner_size(640.0, 480.0)
- .visible(true);
- Ok(Self(window_builder.build()?))
- }
- }
- fn base_window_config<'a, R: Runtime, M: Manager<R>>(
- window_builder: WebviewWindowBuilder<'a, R, M>,
- _app: &AppHandle,
- decorations: bool,
- ) -> WebviewWindowBuilder<'a, R, M> {
- let window_builder = window_builder.decorations(decorations);
- #[cfg(windows)]
- let window_builder = window_builder
- // Some VPNs set a global/system proxy that WebView2 applies even for loopback
- // connections, which breaks the app's localhost sidecar server.
- // Note: when setting additional args, we must re-apply wry's default
- // `--disable-features=...` flags.
- .additional_browser_args(
- "--proxy-bypass-list=<-loopback> --disable-features=msWebOOUI,msPdfOOUI,msSmartScreenProtection",
- )
- .data_directory(_app.path().config_dir().expect("Failed to get config dir").join(_app.config().product_name.clone().unwrap()))
- .decorations(false);
- #[cfg(target_os = "macos")]
- let window_builder = window_builder
- .title_bar_style(tauri::TitleBarStyle::Overlay)
- .hidden_title(true)
- .traffic_light_position(tauri::LogicalPosition::new(12.0, 18.0));
- window_builder
- }
|