mock_runtime.rs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236
  1. // Copyright 2019-2024 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. #![allow(dead_code)]
  5. #![allow(missing_docs)]
  6. use tauri_runtime::{
  7. dpi::{PhysicalPosition, PhysicalSize, Position, Size},
  8. monitor::Monitor,
  9. webview::{DetachedWebview, PendingWebview},
  10. window::{CursorIcon, DetachedWindow, PendingWindow, RawWindow, WindowEvent, WindowId},
  11. window::{WindowBuilder, WindowBuilderBase},
  12. DeviceEventFilter, Error, EventLoopProxy, ExitRequestedEventAction, Icon, ProgressBarState,
  13. Result, RunEvent, Runtime, RuntimeHandle, RuntimeInitArgs, UserAttentionType, UserEvent,
  14. WebviewDispatch, WindowDispatch, WindowEventId,
  15. };
  16. #[cfg(target_os = "macos")]
  17. use tauri_utils::TitleBarStyle;
  18. use tauri_utils::{config::WindowConfig, Theme};
  19. use url::Url;
  20. #[cfg(windows)]
  21. use windows::Win32::Foundation::HWND;
  22. use std::{
  23. cell::RefCell,
  24. collections::HashMap,
  25. fmt,
  26. sync::{
  27. atomic::{AtomicBool, AtomicU32, Ordering},
  28. mpsc::{channel, sync_channel, Receiver, SyncSender},
  29. Arc, Mutex,
  30. },
  31. };
  32. type ShortcutMap = HashMap<String, Box<dyn Fn() + Send + 'static>>;
  33. enum Message {
  34. Task(Box<dyn FnOnce() + Send>),
  35. CloseWindow(WindowId),
  36. DestroyWindow(WindowId),
  37. }
  38. struct Webview;
  39. struct Window {
  40. label: String,
  41. webviews: Vec<Webview>,
  42. }
  43. #[derive(Clone)]
  44. pub struct RuntimeContext {
  45. is_running: Arc<AtomicBool>,
  46. windows: Arc<RefCell<HashMap<WindowId, Window>>>,
  47. shortcuts: Arc<Mutex<ShortcutMap>>,
  48. run_tx: SyncSender<Message>,
  49. next_window_id: Arc<AtomicU32>,
  50. next_webview_id: Arc<AtomicU32>,
  51. next_window_event_id: Arc<AtomicU32>,
  52. next_webview_event_id: Arc<AtomicU32>,
  53. }
  54. // SAFETY: we ensure this type is only used on the main thread.
  55. #[allow(clippy::non_send_fields_in_send_ty)]
  56. unsafe impl Send for RuntimeContext {}
  57. // SAFETY: we ensure this type is only used on the main thread.
  58. #[allow(clippy::non_send_fields_in_send_ty)]
  59. unsafe impl Sync for RuntimeContext {}
  60. impl RuntimeContext {
  61. fn send_message(&self, message: Message) -> Result<()> {
  62. if self.is_running.load(Ordering::Relaxed) {
  63. self
  64. .run_tx
  65. .send(message)
  66. .map_err(|_| Error::FailedToSendMessage)
  67. } else {
  68. match message {
  69. Message::Task(task) => task(),
  70. Message::CloseWindow(id) | Message::DestroyWindow(id) => {
  71. self.windows.borrow_mut().remove(&id);
  72. }
  73. }
  74. Ok(())
  75. }
  76. }
  77. fn next_window_id(&self) -> WindowId {
  78. self.next_window_id.fetch_add(1, Ordering::Relaxed).into()
  79. }
  80. fn next_webview_id(&self) -> u32 {
  81. self.next_webview_id.fetch_add(1, Ordering::Relaxed)
  82. }
  83. fn next_window_event_id(&self) -> WindowEventId {
  84. self.next_window_event_id.fetch_add(1, Ordering::Relaxed)
  85. }
  86. fn next_webview_event_id(&self) -> WindowEventId {
  87. self.next_webview_event_id.fetch_add(1, Ordering::Relaxed)
  88. }
  89. }
  90. impl fmt::Debug for RuntimeContext {
  91. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  92. f.debug_struct("RuntimeContext").finish()
  93. }
  94. }
  95. #[derive(Debug, Clone)]
  96. pub struct MockRuntimeHandle {
  97. context: RuntimeContext,
  98. }
  99. impl<T: UserEvent> RuntimeHandle<T> for MockRuntimeHandle {
  100. type Runtime = MockRuntime;
  101. fn create_proxy(&self) -> EventProxy {
  102. EventProxy {}
  103. }
  104. #[cfg(target_os = "macos")]
  105. #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
  106. fn set_activation_policy(
  107. &self,
  108. activation_policy: tauri_runtime::ActivationPolicy,
  109. ) -> Result<()> {
  110. Ok(())
  111. }
  112. fn request_exit(&self, code: i32) -> Result<()> {
  113. unimplemented!()
  114. }
  115. /// Create a new webview window.
  116. fn create_window<F: Fn(RawWindow<'_>) + Send + 'static>(
  117. &self,
  118. pending: PendingWindow<T, Self::Runtime>,
  119. _after_window_creation: Option<F>,
  120. ) -> Result<DetachedWindow<T, Self::Runtime>> {
  121. let id = self.context.next_window_id();
  122. let (webview_id, webviews) = if let Some(w) = &pending.webview {
  123. (Some(self.context.next_webview_id()), vec![Webview])
  124. } else {
  125. (None, Vec::new())
  126. };
  127. self.context.windows.borrow_mut().insert(
  128. id,
  129. Window {
  130. label: pending.label.clone(),
  131. webviews,
  132. },
  133. );
  134. let webview = webview_id.map(|id| DetachedWebview {
  135. label: pending.label.clone(),
  136. dispatcher: MockWebviewDispatcher {
  137. id,
  138. context: self.context.clone(),
  139. url: Arc::new(Mutex::new(pending.webview.unwrap().url)),
  140. last_evaluated_script: Default::default(),
  141. },
  142. });
  143. Ok(DetachedWindow {
  144. id,
  145. label: pending.label,
  146. dispatcher: MockWindowDispatcher {
  147. id,
  148. context: self.context.clone(),
  149. },
  150. webview,
  151. })
  152. }
  153. fn create_webview(
  154. &self,
  155. window_id: WindowId,
  156. pending: PendingWebview<T, Self::Runtime>,
  157. ) -> Result<DetachedWebview<T, Self::Runtime>> {
  158. let id = self.context.next_webview_id();
  159. let webview = Webview;
  160. if let Some(w) = self.context.windows.borrow_mut().get_mut(&window_id) {
  161. w.webviews.push(webview);
  162. }
  163. Ok(DetachedWebview {
  164. label: pending.label,
  165. dispatcher: MockWebviewDispatcher {
  166. id,
  167. context: self.context.clone(),
  168. last_evaluated_script: Default::default(),
  169. url: Arc::new(Mutex::new(pending.url)),
  170. },
  171. })
  172. }
  173. /// Run a task on the main thread.
  174. fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
  175. self.context.send_message(Message::Task(Box::new(f)))
  176. }
  177. fn display_handle(
  178. &self,
  179. ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {
  180. #[cfg(target_os = "linux")]
  181. return Ok(unsafe {
  182. raw_window_handle::DisplayHandle::borrow_raw(raw_window_handle::RawDisplayHandle::Xlib(
  183. raw_window_handle::XlibDisplayHandle::new(None, 0),
  184. ))
  185. });
  186. #[cfg(target_os = "macos")]
  187. return Ok(unsafe {
  188. raw_window_handle::DisplayHandle::borrow_raw(raw_window_handle::RawDisplayHandle::AppKit(
  189. raw_window_handle::AppKitDisplayHandle::new(),
  190. ))
  191. });
  192. #[cfg(windows)]
  193. return Ok(unsafe {
  194. raw_window_handle::DisplayHandle::borrow_raw(raw_window_handle::RawDisplayHandle::Windows(
  195. raw_window_handle::WindowsDisplayHandle::new(),
  196. ))
  197. });
  198. #[cfg(not(any(target_os = "linux", target_os = "macos", windows)))]
  199. unimplemented!();
  200. }
  201. fn primary_monitor(&self) -> Option<Monitor> {
  202. unimplemented!()
  203. }
  204. fn monitor_from_point(&self, x: f64, y: f64) -> Option<Monitor> {
  205. unimplemented!()
  206. }
  207. fn available_monitors(&self) -> Vec<Monitor> {
  208. unimplemented!()
  209. }
  210. fn set_theme(&self, theme: Option<Theme>) {
  211. unimplemented!()
  212. }
  213. /// Shows the application, but does not automatically focus it.
  214. #[cfg(target_os = "macos")]
  215. fn show(&self) -> Result<()> {
  216. Ok(())
  217. }
  218. /// Hides the application.
  219. #[cfg(target_os = "macos")]
  220. fn hide(&self) -> Result<()> {
  221. Ok(())
  222. }
  223. #[cfg(target_os = "android")]
  224. fn find_class<'a>(
  225. &self,
  226. env: &mut jni::JNIEnv<'a>,
  227. activity: &jni::objects::JObject<'_>,
  228. name: impl Into<String>,
  229. ) -> std::result::Result<jni::objects::JClass<'a>, jni::errors::Error> {
  230. todo!()
  231. }
  232. #[cfg(target_os = "android")]
  233. fn run_on_android_context<F>(&self, f: F)
  234. where
  235. F: FnOnce(&mut jni::JNIEnv, &jni::objects::JObject, &jni::objects::JObject) + Send + 'static,
  236. {
  237. todo!()
  238. }
  239. fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
  240. Ok(PhysicalPosition::new(0.0, 0.0))
  241. }
  242. }
  243. #[derive(Debug, Clone)]
  244. pub struct MockWebviewDispatcher {
  245. id: u32,
  246. context: RuntimeContext,
  247. url: Arc<Mutex<String>>,
  248. last_evaluated_script: Arc<Mutex<Option<String>>>,
  249. }
  250. impl MockWebviewDispatcher {
  251. pub fn last_evaluated_script(&self) -> Option<String> {
  252. self.last_evaluated_script.lock().unwrap().clone()
  253. }
  254. }
  255. #[derive(Debug, Clone)]
  256. pub struct MockWindowDispatcher {
  257. id: WindowId,
  258. context: RuntimeContext,
  259. }
  260. #[derive(Debug, Clone)]
  261. pub struct MockWindowBuilder {}
  262. impl WindowBuilderBase for MockWindowBuilder {}
  263. impl WindowBuilder for MockWindowBuilder {
  264. fn new() -> Self {
  265. Self {}
  266. }
  267. fn with_config(config: &WindowConfig) -> Self {
  268. Self {}
  269. }
  270. fn center(self) -> Self {
  271. self
  272. }
  273. fn position(self, x: f64, y: f64) -> Self {
  274. self
  275. }
  276. fn inner_size(self, min_width: f64, min_height: f64) -> Self {
  277. self
  278. }
  279. fn min_inner_size(self, min_width: f64, min_height: f64) -> Self {
  280. self
  281. }
  282. fn max_inner_size(self, max_width: f64, max_height: f64) -> Self {
  283. self
  284. }
  285. fn inner_size_constraints(
  286. self,
  287. constraints: tauri_runtime::window::WindowSizeConstraints,
  288. ) -> Self {
  289. self
  290. }
  291. fn resizable(self, resizable: bool) -> Self {
  292. self
  293. }
  294. fn maximizable(self, resizable: bool) -> Self {
  295. self
  296. }
  297. fn minimizable(self, resizable: bool) -> Self {
  298. self
  299. }
  300. fn closable(self, resizable: bool) -> Self {
  301. self
  302. }
  303. fn title<S: Into<String>>(self, title: S) -> Self {
  304. self
  305. }
  306. fn fullscreen(self, fullscreen: bool) -> Self {
  307. self
  308. }
  309. fn focused(self, focused: bool) -> Self {
  310. self
  311. }
  312. fn maximized(self, maximized: bool) -> Self {
  313. self
  314. }
  315. fn visible(self, visible: bool) -> Self {
  316. self
  317. }
  318. #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
  319. #[cfg_attr(
  320. docsrs,
  321. doc(cfg(any(not(target_os = "macos"), feature = "macos-private-api")))
  322. )]
  323. fn transparent(self, transparent: bool) -> Self {
  324. self
  325. }
  326. fn decorations(self, decorations: bool) -> Self {
  327. self
  328. }
  329. fn always_on_bottom(self, always_on_bottom: bool) -> Self {
  330. self
  331. }
  332. fn always_on_top(self, always_on_top: bool) -> Self {
  333. self
  334. }
  335. fn visible_on_all_workspaces(self, visible_on_all_workspaces: bool) -> Self {
  336. self
  337. }
  338. fn content_protected(self, protected: bool) -> Self {
  339. self
  340. }
  341. fn icon(self, icon: Icon<'_>) -> Result<Self> {
  342. Ok(self)
  343. }
  344. fn skip_taskbar(self, skip: bool) -> Self {
  345. self
  346. }
  347. fn shadow(self, enable: bool) -> Self {
  348. self
  349. }
  350. #[cfg(windows)]
  351. fn owner(self, owner: HWND) -> Self {
  352. self
  353. }
  354. #[cfg(windows)]
  355. fn parent(self, parent: HWND) -> Self {
  356. self
  357. }
  358. #[cfg(target_os = "macos")]
  359. fn parent(self, parent: *mut std::ffi::c_void) -> Self {
  360. self
  361. }
  362. #[cfg(any(
  363. target_os = "linux",
  364. target_os = "dragonfly",
  365. target_os = "freebsd",
  366. target_os = "netbsd",
  367. target_os = "openbsd"
  368. ))]
  369. fn transient_for(self, parent: &impl gtk::glib::IsA<gtk::Window>) -> Self {
  370. self
  371. }
  372. #[cfg(windows)]
  373. fn drag_and_drop(self, enabled: bool) -> Self {
  374. self
  375. }
  376. #[cfg(target_os = "macos")]
  377. fn title_bar_style(self, style: TitleBarStyle) -> Self {
  378. self
  379. }
  380. #[cfg(target_os = "macos")]
  381. fn hidden_title(self, transparent: bool) -> Self {
  382. self
  383. }
  384. #[cfg(target_os = "macos")]
  385. fn tabbing_identifier(self, identifier: &str) -> Self {
  386. self
  387. }
  388. fn theme(self, theme: Option<Theme>) -> Self {
  389. self
  390. }
  391. fn has_icon(&self) -> bool {
  392. false
  393. }
  394. fn get_theme(&self) -> Option<Theme> {
  395. None
  396. }
  397. fn background_color(self, _color: tauri_utils::config::Color) -> Self {
  398. self
  399. }
  400. }
  401. impl<T: UserEvent> WebviewDispatch<T> for MockWebviewDispatcher {
  402. type Runtime = MockRuntime;
  403. fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
  404. self.context.send_message(Message::Task(Box::new(f)))
  405. }
  406. fn on_webview_event<F: Fn(&tauri_runtime::window::WebviewEvent) + Send + 'static>(
  407. &self,
  408. f: F,
  409. ) -> tauri_runtime::WebviewEventId {
  410. self.context.next_window_event_id()
  411. }
  412. fn with_webview<F: FnOnce(Box<dyn std::any::Any>) + Send + 'static>(&self, f: F) -> Result<()> {
  413. Ok(())
  414. }
  415. #[cfg(any(debug_assertions, feature = "devtools"))]
  416. fn open_devtools(&self) {}
  417. #[cfg(any(debug_assertions, feature = "devtools"))]
  418. fn close_devtools(&self) {}
  419. #[cfg(any(debug_assertions, feature = "devtools"))]
  420. fn is_devtools_open(&self) -> Result<bool> {
  421. Ok(false)
  422. }
  423. fn set_zoom(&self, scale_factor: f64) -> Result<()> {
  424. Ok(())
  425. }
  426. fn eval_script<S: Into<String>>(&self, script: S) -> Result<()> {
  427. self
  428. .last_evaluated_script
  429. .lock()
  430. .unwrap()
  431. .replace(script.into());
  432. Ok(())
  433. }
  434. fn url(&self) -> Result<String> {
  435. Ok(self.url.lock().unwrap().clone())
  436. }
  437. fn bounds(&self) -> Result<tauri_runtime::Rect> {
  438. Ok(tauri_runtime::Rect::default())
  439. }
  440. fn position(&self) -> Result<PhysicalPosition<i32>> {
  441. Ok(PhysicalPosition { x: 0, y: 0 })
  442. }
  443. fn size(&self) -> Result<PhysicalSize<u32>> {
  444. Ok(PhysicalSize {
  445. width: 0,
  446. height: 0,
  447. })
  448. }
  449. fn navigate(&self, url: Url) -> Result<()> {
  450. *self.url.lock().unwrap() = url.to_string();
  451. Ok(())
  452. }
  453. fn print(&self) -> Result<()> {
  454. Ok(())
  455. }
  456. fn close(&self) -> Result<()> {
  457. Ok(())
  458. }
  459. fn set_bounds(&self, bounds: tauri_runtime::Rect) -> Result<()> {
  460. Ok(())
  461. }
  462. fn set_size(&self, _size: Size) -> Result<()> {
  463. Ok(())
  464. }
  465. fn set_position(&self, _position: Position) -> Result<()> {
  466. Ok(())
  467. }
  468. fn set_focus(&self) -> Result<()> {
  469. Ok(())
  470. }
  471. fn reparent(&self, window_id: WindowId) -> Result<()> {
  472. Ok(())
  473. }
  474. fn set_auto_resize(&self, auto_resize: bool) -> Result<()> {
  475. Ok(())
  476. }
  477. fn clear_all_browsing_data(&self) -> Result<()> {
  478. Ok(())
  479. }
  480. fn hide(&self) -> Result<()> {
  481. Ok(())
  482. }
  483. fn show(&self) -> Result<()> {
  484. Ok(())
  485. }
  486. fn set_background_color(&self, color: Option<tauri_utils::config::Color>) -> Result<()> {
  487. Ok(())
  488. }
  489. }
  490. impl<T: UserEvent> WindowDispatch<T> for MockWindowDispatcher {
  491. type Runtime = MockRuntime;
  492. type WindowBuilder = MockWindowBuilder;
  493. fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
  494. self.context.send_message(Message::Task(Box::new(f)))
  495. }
  496. fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) -> WindowEventId {
  497. self.context.next_window_event_id()
  498. }
  499. fn scale_factor(&self) -> Result<f64> {
  500. Ok(1.0)
  501. }
  502. fn inner_position(&self) -> Result<PhysicalPosition<i32>> {
  503. Ok(PhysicalPosition { x: 0, y: 0 })
  504. }
  505. fn outer_position(&self) -> Result<PhysicalPosition<i32>> {
  506. Ok(PhysicalPosition { x: 0, y: 0 })
  507. }
  508. fn inner_size(&self) -> Result<PhysicalSize<u32>> {
  509. Ok(PhysicalSize {
  510. width: 0,
  511. height: 0,
  512. })
  513. }
  514. fn outer_size(&self) -> Result<PhysicalSize<u32>> {
  515. Ok(PhysicalSize {
  516. width: 0,
  517. height: 0,
  518. })
  519. }
  520. fn is_fullscreen(&self) -> Result<bool> {
  521. Ok(false)
  522. }
  523. fn is_minimized(&self) -> Result<bool> {
  524. Ok(false)
  525. }
  526. fn is_maximized(&self) -> Result<bool> {
  527. Ok(false)
  528. }
  529. fn is_focused(&self) -> Result<bool> {
  530. Ok(false)
  531. }
  532. fn is_decorated(&self) -> Result<bool> {
  533. Ok(false)
  534. }
  535. fn is_resizable(&self) -> Result<bool> {
  536. Ok(false)
  537. }
  538. fn is_maximizable(&self) -> Result<bool> {
  539. Ok(true)
  540. }
  541. fn is_minimizable(&self) -> Result<bool> {
  542. Ok(true)
  543. }
  544. fn is_closable(&self) -> Result<bool> {
  545. Ok(true)
  546. }
  547. fn is_visible(&self) -> Result<bool> {
  548. Ok(true)
  549. }
  550. fn title(&self) -> Result<String> {
  551. Ok(String::new())
  552. }
  553. fn current_monitor(&self) -> Result<Option<Monitor>> {
  554. Ok(None)
  555. }
  556. fn primary_monitor(&self) -> Result<Option<Monitor>> {
  557. Ok(None)
  558. }
  559. fn monitor_from_point(&self, x: f64, y: f64) -> Result<Option<Monitor>> {
  560. Ok(None)
  561. }
  562. fn available_monitors(&self) -> Result<Vec<Monitor>> {
  563. Ok(Vec::new())
  564. }
  565. fn theme(&self) -> Result<Theme> {
  566. Ok(Theme::Light)
  567. }
  568. #[cfg(any(
  569. target_os = "linux",
  570. target_os = "dragonfly",
  571. target_os = "freebsd",
  572. target_os = "netbsd",
  573. target_os = "openbsd"
  574. ))]
  575. fn gtk_window(&self) -> Result<gtk::ApplicationWindow> {
  576. unimplemented!()
  577. }
  578. #[cfg(any(
  579. target_os = "linux",
  580. target_os = "dragonfly",
  581. target_os = "freebsd",
  582. target_os = "netbsd",
  583. target_os = "openbsd"
  584. ))]
  585. fn default_vbox(&self) -> Result<gtk::Box> {
  586. unimplemented!()
  587. }
  588. fn window_handle(
  589. &self,
  590. ) -> std::result::Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
  591. #[cfg(target_os = "linux")]
  592. return unsafe {
  593. Ok(raw_window_handle::WindowHandle::borrow_raw(
  594. raw_window_handle::RawWindowHandle::Xlib(raw_window_handle::XlibWindowHandle::new(0)),
  595. ))
  596. };
  597. #[cfg(target_os = "macos")]
  598. return unsafe {
  599. Ok(raw_window_handle::WindowHandle::borrow_raw(
  600. raw_window_handle::RawWindowHandle::AppKit(raw_window_handle::AppKitWindowHandle::new(
  601. std::ptr::NonNull::from(&()).cast(),
  602. )),
  603. ))
  604. };
  605. #[cfg(windows)]
  606. return unsafe {
  607. Ok(raw_window_handle::WindowHandle::borrow_raw(
  608. raw_window_handle::RawWindowHandle::Win32(raw_window_handle::Win32WindowHandle::new(
  609. std::num::NonZeroIsize::MIN,
  610. )),
  611. ))
  612. };
  613. #[cfg(not(any(target_os = "linux", target_os = "macos", windows)))]
  614. unimplemented!();
  615. }
  616. fn center(&self) -> Result<()> {
  617. Ok(())
  618. }
  619. fn request_user_attention(&self, request_type: Option<UserAttentionType>) -> Result<()> {
  620. Ok(())
  621. }
  622. fn create_window<F: Fn(RawWindow<'_>) + Send + 'static>(
  623. &mut self,
  624. pending: PendingWindow<T, Self::Runtime>,
  625. _after_window_creation: Option<F>,
  626. ) -> Result<DetachedWindow<T, Self::Runtime>> {
  627. let id = self.context.next_window_id();
  628. let (webview_id, webviews) = if let Some(w) = &pending.webview {
  629. (Some(self.context.next_webview_id()), vec![Webview])
  630. } else {
  631. (None, Vec::new())
  632. };
  633. self.context.windows.borrow_mut().insert(
  634. id,
  635. Window {
  636. label: pending.label.clone(),
  637. webviews,
  638. },
  639. );
  640. let webview = webview_id.map(|id| DetachedWebview {
  641. label: pending.label.clone(),
  642. dispatcher: MockWebviewDispatcher {
  643. id,
  644. context: self.context.clone(),
  645. url: Arc::new(Mutex::new(pending.webview.unwrap().url)),
  646. last_evaluated_script: Default::default(),
  647. },
  648. });
  649. Ok(DetachedWindow {
  650. id,
  651. label: pending.label,
  652. dispatcher: MockWindowDispatcher {
  653. id,
  654. context: self.context.clone(),
  655. },
  656. webview,
  657. })
  658. }
  659. fn create_webview(
  660. &mut self,
  661. pending: PendingWebview<T, Self::Runtime>,
  662. ) -> Result<DetachedWebview<T, Self::Runtime>> {
  663. let id = self.context.next_webview_id();
  664. let webview = Webview;
  665. if let Some(w) = self.context.windows.borrow_mut().get_mut(&self.id) {
  666. w.webviews.push(webview);
  667. }
  668. Ok(DetachedWebview {
  669. label: pending.label,
  670. dispatcher: MockWebviewDispatcher {
  671. id,
  672. context: self.context.clone(),
  673. last_evaluated_script: Default::default(),
  674. url: Arc::new(Mutex::new(pending.url)),
  675. },
  676. })
  677. }
  678. fn set_resizable(&self, resizable: bool) -> Result<()> {
  679. Ok(())
  680. }
  681. fn set_maximizable(&self, maximizable: bool) -> Result<()> {
  682. Ok(())
  683. }
  684. fn set_minimizable(&self, minimizable: bool) -> Result<()> {
  685. Ok(())
  686. }
  687. fn set_closable(&self, closable: bool) -> Result<()> {
  688. Ok(())
  689. }
  690. fn set_title<S: Into<String>>(&self, title: S) -> Result<()> {
  691. Ok(())
  692. }
  693. fn maximize(&self) -> Result<()> {
  694. Ok(())
  695. }
  696. fn unmaximize(&self) -> Result<()> {
  697. Ok(())
  698. }
  699. fn minimize(&self) -> Result<()> {
  700. Ok(())
  701. }
  702. fn unminimize(&self) -> Result<()> {
  703. Ok(())
  704. }
  705. fn show(&self) -> Result<()> {
  706. Ok(())
  707. }
  708. fn hide(&self) -> Result<()> {
  709. Ok(())
  710. }
  711. fn close(&self) -> Result<()> {
  712. self.context.send_message(Message::CloseWindow(self.id))?;
  713. Ok(())
  714. }
  715. fn destroy(&self) -> Result<()> {
  716. self.context.send_message(Message::DestroyWindow(self.id))?;
  717. Ok(())
  718. }
  719. fn set_decorations(&self, decorations: bool) -> Result<()> {
  720. Ok(())
  721. }
  722. fn set_shadow(&self, shadow: bool) -> Result<()> {
  723. Ok(())
  724. }
  725. fn set_always_on_bottom(&self, always_on_bottom: bool) -> Result<()> {
  726. Ok(())
  727. }
  728. fn set_always_on_top(&self, always_on_top: bool) -> Result<()> {
  729. Ok(())
  730. }
  731. fn set_visible_on_all_workspaces(&self, visible_on_all_workspaces: bool) -> Result<()> {
  732. Ok(())
  733. }
  734. fn set_content_protected(&self, protected: bool) -> Result<()> {
  735. Ok(())
  736. }
  737. fn set_size(&self, size: Size) -> Result<()> {
  738. Ok(())
  739. }
  740. fn set_min_size(&self, size: Option<Size>) -> Result<()> {
  741. Ok(())
  742. }
  743. fn set_max_size(&self, size: Option<Size>) -> Result<()> {
  744. Ok(())
  745. }
  746. fn set_position(&self, position: Position) -> Result<()> {
  747. Ok(())
  748. }
  749. fn set_fullscreen(&self, fullscreen: bool) -> Result<()> {
  750. Ok(())
  751. }
  752. fn set_focus(&self) -> Result<()> {
  753. Ok(())
  754. }
  755. fn set_icon(&self, icon: Icon<'_>) -> Result<()> {
  756. Ok(())
  757. }
  758. fn set_skip_taskbar(&self, skip: bool) -> Result<()> {
  759. Ok(())
  760. }
  761. fn set_cursor_grab(&self, grab: bool) -> Result<()> {
  762. Ok(())
  763. }
  764. fn set_cursor_visible(&self, visible: bool) -> Result<()> {
  765. Ok(())
  766. }
  767. fn set_cursor_icon(&self, icon: CursorIcon) -> Result<()> {
  768. Ok(())
  769. }
  770. fn set_cursor_position<Pos: Into<Position>>(&self, position: Pos) -> Result<()> {
  771. Ok(())
  772. }
  773. fn set_ignore_cursor_events(&self, ignore: bool) -> Result<()> {
  774. Ok(())
  775. }
  776. fn start_dragging(&self) -> Result<()> {
  777. Ok(())
  778. }
  779. fn start_resize_dragging(&self, direction: tauri_runtime::ResizeDirection) -> Result<()> {
  780. Ok(())
  781. }
  782. fn set_progress_bar(&self, progress_state: ProgressBarState) -> Result<()> {
  783. Ok(())
  784. }
  785. fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> Result<()> {
  786. Ok(())
  787. }
  788. fn set_size_constraints(
  789. &self,
  790. constraints: tauri_runtime::window::WindowSizeConstraints,
  791. ) -> Result<()> {
  792. Ok(())
  793. }
  794. fn set_theme(&self, theme: Option<Theme>) -> Result<()> {
  795. Ok(())
  796. }
  797. fn set_enabled(&self, enabled: bool) -> Result<()> {
  798. Ok(())
  799. }
  800. fn is_enabled(&self) -> Result<bool> {
  801. Ok(true)
  802. }
  803. fn set_background_color(&self, color: Option<tauri_utils::config::Color>) -> Result<()> {
  804. Ok(())
  805. }
  806. }
  807. #[derive(Debug, Clone)]
  808. pub struct EventProxy {}
  809. impl<T: UserEvent> EventLoopProxy<T> for EventProxy {
  810. fn send_event(&self, event: T) -> Result<()> {
  811. Ok(())
  812. }
  813. }
  814. #[derive(Debug)]
  815. pub struct MockRuntime {
  816. is_running: Arc<AtomicBool>,
  817. pub context: RuntimeContext,
  818. run_rx: Receiver<Message>,
  819. }
  820. impl MockRuntime {
  821. fn init() -> Self {
  822. let is_running = Arc::new(AtomicBool::new(false));
  823. let (tx, rx) = sync_channel(256);
  824. let context = RuntimeContext {
  825. is_running: is_running.clone(),
  826. windows: Default::default(),
  827. shortcuts: Default::default(),
  828. run_tx: tx,
  829. next_window_id: Default::default(),
  830. next_webview_id: Default::default(),
  831. next_window_event_id: Default::default(),
  832. next_webview_event_id: Default::default(),
  833. };
  834. Self {
  835. is_running,
  836. context,
  837. run_rx: rx,
  838. }
  839. }
  840. }
  841. impl<T: UserEvent> Runtime<T> for MockRuntime {
  842. type WindowDispatcher = MockWindowDispatcher;
  843. type WebviewDispatcher = MockWebviewDispatcher;
  844. type Handle = MockRuntimeHandle;
  845. type EventLoopProxy = EventProxy;
  846. fn new(_args: RuntimeInitArgs) -> Result<Self> {
  847. Ok(Self::init())
  848. }
  849. #[cfg(any(windows, target_os = "linux"))]
  850. fn new_any_thread(_args: RuntimeInitArgs) -> Result<Self> {
  851. Ok(Self::init())
  852. }
  853. fn create_proxy(&self) -> EventProxy {
  854. EventProxy {}
  855. }
  856. fn handle(&self) -> Self::Handle {
  857. MockRuntimeHandle {
  858. context: self.context.clone(),
  859. }
  860. }
  861. fn create_window<F: Fn(RawWindow<'_>) + Send + 'static>(
  862. &self,
  863. pending: PendingWindow<T, Self>,
  864. _after_window_creation: Option<F>,
  865. ) -> Result<DetachedWindow<T, Self>> {
  866. let id = self.context.next_window_id();
  867. let (webview_id, webviews) = if let Some(w) = &pending.webview {
  868. (Some(self.context.next_webview_id()), vec![Webview])
  869. } else {
  870. (None, Vec::new())
  871. };
  872. self.context.windows.borrow_mut().insert(
  873. id,
  874. Window {
  875. label: pending.label.clone(),
  876. webviews,
  877. },
  878. );
  879. let webview = webview_id.map(|id| DetachedWebview {
  880. label: pending.label.clone(),
  881. dispatcher: MockWebviewDispatcher {
  882. id,
  883. context: self.context.clone(),
  884. url: Arc::new(Mutex::new(pending.webview.unwrap().url)),
  885. last_evaluated_script: Default::default(),
  886. },
  887. });
  888. Ok(DetachedWindow {
  889. id,
  890. label: pending.label,
  891. dispatcher: MockWindowDispatcher {
  892. id,
  893. context: self.context.clone(),
  894. },
  895. webview,
  896. })
  897. }
  898. fn create_webview(
  899. &self,
  900. window_id: WindowId,
  901. pending: PendingWebview<T, Self>,
  902. ) -> Result<DetachedWebview<T, Self>> {
  903. let id = self.context.next_webview_id();
  904. let webview = Webview;
  905. if let Some(w) = self.context.windows.borrow_mut().get_mut(&window_id) {
  906. w.webviews.push(webview);
  907. }
  908. Ok(DetachedWebview {
  909. label: pending.label,
  910. dispatcher: MockWebviewDispatcher {
  911. id,
  912. context: self.context.clone(),
  913. last_evaluated_script: Default::default(),
  914. url: Arc::new(Mutex::new(pending.url)),
  915. },
  916. })
  917. }
  918. fn primary_monitor(&self) -> Option<Monitor> {
  919. unimplemented!()
  920. }
  921. fn monitor_from_point(&self, x: f64, y: f64) -> Option<Monitor> {
  922. unimplemented!()
  923. }
  924. fn available_monitors(&self) -> Vec<Monitor> {
  925. unimplemented!()
  926. }
  927. fn set_theme(&self, theme: Option<Theme>) {
  928. unimplemented!()
  929. }
  930. #[cfg(target_os = "macos")]
  931. #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
  932. fn set_activation_policy(&mut self, activation_policy: tauri_runtime::ActivationPolicy) {}
  933. #[cfg(target_os = "macos")]
  934. #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
  935. fn show(&self) {}
  936. #[cfg(target_os = "macos")]
  937. #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
  938. fn hide(&self) {}
  939. fn set_device_event_filter(&mut self, filter: DeviceEventFilter) {}
  940. #[cfg(any(
  941. target_os = "macos",
  942. windows,
  943. target_os = "linux",
  944. target_os = "dragonfly",
  945. target_os = "freebsd",
  946. target_os = "netbsd",
  947. target_os = "openbsd"
  948. ))]
  949. fn run_iteration<F: FnMut(RunEvent<T>)>(&mut self, callback: F) {}
  950. fn run<F: FnMut(RunEvent<T>) + 'static>(self, mut callback: F) {
  951. self.is_running.store(true, Ordering::Relaxed);
  952. callback(RunEvent::Ready);
  953. loop {
  954. if let Ok(m) = self.run_rx.try_recv() {
  955. match m {
  956. Message::Task(p) => p(),
  957. Message::CloseWindow(id) => {
  958. let label = self
  959. .context
  960. .windows
  961. .borrow()
  962. .get(&id)
  963. .map(|w| w.label.clone());
  964. if let Some(label) = label {
  965. let (tx, rx) = channel();
  966. callback(RunEvent::WindowEvent {
  967. label,
  968. event: WindowEvent::CloseRequested { signal_tx: tx },
  969. });
  970. let should_prevent = matches!(rx.try_recv(), Ok(true));
  971. if !should_prevent {
  972. self.context.windows.borrow_mut().remove(&id);
  973. let is_empty = self.context.windows.borrow().is_empty();
  974. if is_empty {
  975. let (tx, rx) = channel();
  976. callback(RunEvent::ExitRequested { code: None, tx });
  977. let recv = rx.try_recv();
  978. let should_prevent = matches!(recv, Ok(ExitRequestedEventAction::Prevent));
  979. if !should_prevent {
  980. break;
  981. }
  982. }
  983. }
  984. }
  985. }
  986. Message::DestroyWindow(id) => {
  987. let removed = self.context.windows.borrow_mut().remove(&id).is_some();
  988. if removed {
  989. let is_empty = self.context.windows.borrow().is_empty();
  990. if is_empty {
  991. let (tx, rx) = channel();
  992. callback(RunEvent::ExitRequested { code: None, tx });
  993. let recv = rx.try_recv();
  994. let should_prevent = matches!(recv, Ok(ExitRequestedEventAction::Prevent));
  995. if !should_prevent {
  996. break;
  997. }
  998. }
  999. }
  1000. }
  1001. }
  1002. }
  1003. callback(RunEvent::MainEventsCleared);
  1004. std::thread::sleep(std::time::Duration::from_secs(1));
  1005. }
  1006. callback(RunEvent::Exit);
  1007. }
  1008. fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
  1009. Ok(PhysicalPosition::new(0.0, 0.0))
  1010. }
  1011. }