1use tauri::{
2 plugin::{Builder, TauriPlugin},
3 Manager, RunEvent, Runtime, WindowEvent,
4};
5
6pub use models::*;
7
8#[cfg(desktop)]
9mod desktop;
10#[cfg(mobile)]
11mod mobile;
12
13mod commands;
14mod error;
15mod events;
16mod ipc;
17mod models;
18mod process;
19mod utils;
20
21pub use error::{Error, Result};
22
23#[cfg(desktop)]
24use desktop::Mpv;
25#[cfg(mobile)]
26use mobile::Mpv;
27
28pub trait MpvExt<R: Runtime> {
29 fn mpv(&self) -> &Mpv<R>;
30}
31
32impl<R: Runtime, T: Manager<R>> crate::MpvExt<R> for T {
33 fn mpv(&self) -> &Mpv<R> {
34 self.state::<Mpv<R>>().inner()
35 }
36}
37
38pub fn init<R: Runtime>() -> TauriPlugin<R> {
39 Builder::new("mpv")
40 .invoke_handler(tauri::generate_handler![
41 commands::init,
42 commands::destroy,
43 commands::command,
44 commands::set_video_margin_ratio,
45 ])
46 .setup(|app, api| {
47 unsafe {
48 let locale = std::ffi::CString::new("C").unwrap();
49 libc::setlocale(libc::LC_NUMERIC, locale.as_ptr());
50 }
51
52 #[cfg(mobile)]
53 let mpv = mobile::init(app, api)?;
54 #[cfg(desktop)]
55 let mpv = desktop::init(app, api)?;
56 app.manage(mpv);
57 Ok(())
58 })
59 .on_event(|app_handle, run_event| {
60 if let RunEvent::WindowEvent {
61 label,
62 event: WindowEvent::CloseRequested { api, .. },
63 ..
64 } = run_event
65 {
66 let mpv_state = app_handle.state::<Mpv<R>>();
67
68 let instance_exists = {
69 let instances_lock = match mpv_state.instances.lock() {
70 Ok(guard) => guard,
71 Err(poisoned) => {
72 log::warn!("Mutex for mpv instances was poisoned. Recovering.");
73 poisoned.into_inner()
74 }
75 };
76 instances_lock.contains_key(label)
77 };
78
79 if instance_exists {
80 api.prevent_close();
81
82 let app_handle_clone = app_handle.clone();
83 let window_label = label.to_string();
84
85 tauri::async_runtime::spawn(async move {
86 log::info!(
87 "Close requested for '{}', destroying mpv instance first...",
88 &window_label
89 );
90
91 if let Err(e) = app_handle_clone.mpv().destroy(&window_label) {
92 log::error!(
93 "Failed to destroy mpv for '{}': {}. Still closing.",
94 &window_label,
95 e
96 );
97 }
98
99 if let Some(window) = app_handle_clone.get_webview_window(&window_label) {
100 if let Err(e) = window.close() {
101 log::error!("Failed to close window '{}': {}", &window_label, e);
102 }
103 }
104 });
105 }
106 }
107 })
108 .build()
109}