#![cfg_attr( all(not(debug_assertions), target_os = "windows"), windows_subsystem = "windows" )] // mod menu; use tauri::{webview::{NewWindowResponse, WebviewWindowBuilder}, WebviewUrl}; use tauri_plugin_opener::OpenerExt; // Automatically grant camera and microphone permissions in WebView2 (Windows). // macOS handles this via Info.plist; Windows requires an explicit PermissionRequested handler. #[cfg(target_os = "windows")] mod win_permissions { use webview2_com::Microsoft::Web::WebView2::Win32::{ ICoreWebView2, ICoreWebView2PermissionRequestedEventArgs, ICoreWebView2PermissionRequestedEventHandler, ICoreWebView2PermissionRequestedEventHandler_Impl, COREWEBVIEW2_PERMISSION_KIND_CAMERA, COREWEBVIEW2_PERMISSION_KIND_MICROPHONE, COREWEBVIEW2_PERMISSION_STATE_ALLOW, }; use windows::core::implement; #[implement(ICoreWebView2PermissionRequestedEventHandler)] pub struct PermissionHandler; impl ICoreWebView2PermissionRequestedEventHandler_Impl for PermissionHandler { fn Invoke( &self, _sender: Option<&ICoreWebView2>, args: Option<&ICoreWebView2PermissionRequestedEventArgs>, ) -> windows::core::Result<()> { if let Some(args) = args { let kind = unsafe { args.PermissionKind() }?; if kind == COREWEBVIEW2_PERMISSION_KIND_MICROPHONE || kind == COREWEBVIEW2_PERMISSION_KIND_CAMERA { unsafe { args.SetState(COREWEBVIEW2_PERMISSION_STATE_ALLOW) }?; } } Ok(()) } } } pub fn run() { let port: u16 = 44548; let context = tauri::generate_context!(); let builder = tauri::Builder::default(); builder .plugin(tauri_plugin_localhost::Builder::new(port).build()) .plugin(tauri_plugin_window_state::Builder::default().build()) .plugin(tauri_plugin_opener::init()) .setup(move |app| { #[cfg(debug_assertions)] let window_url = WebviewUrl::App(Default::default()); #[cfg(not(debug_assertions))] let window_url = { let url = format!("http://localhost:{}", port).parse().unwrap(); WebviewUrl::External(url) }; let app_handle = app.handle().clone(); let builder = WebviewWindowBuilder::new(app, "main".to_string(), window_url) .title("Cinny") .disable_drag_drop_handler() .on_new_window(move |url, _features| { let _ = app_handle.opener().open_url(url.as_str(), None::<&str>); NewWindowResponse::Deny }); #[cfg(target_os = "windows")] let builder = builder.with_webview(|webview| { use webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2PermissionRequestedEventHandler; use windows::core::EventRegistrationToken; use win_permissions::PermissionHandler; let controller = webview.controller(); if let Ok(core) = unsafe { controller.CoreWebView2() } { let handler: ICoreWebView2PermissionRequestedEventHandler = PermissionHandler.into(); let mut token = EventRegistrationToken(0); let _ = unsafe { core.add_PermissionRequested(&handler, &mut token) }; std::mem::forget(handler); } }); builder.build()?; Ok(()) }) .run(context) .expect("error while building tauri application"); }