lib.rs 83 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911
  1. // Copyright 2019-2023 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. //! [![](https://github.com/tauri-apps/tauri/raw/dev/.github/splash.png)](https://tauri.app)
  5. //!
  6. //! The [`wry`] Tauri [`Runtime`].
  7. #![doc(
  8. html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png",
  9. html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
  10. )]
  11. use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle};
  12. use tauri_runtime::{
  13. monitor::Monitor,
  14. webview::{WebviewIpcHandler, WindowBuilder, WindowBuilderBase},
  15. window::{
  16. dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
  17. CursorIcon, DetachedWindow, FileDropEvent, PendingWindow, RawWindow, WindowEvent,
  18. },
  19. DeviceEventFilter, Dispatch, Error, EventLoopProxy, ExitRequestedEventAction, Icon, Result,
  20. RunEvent, RunIteration, Runtime, RuntimeHandle, RuntimeInitArgs, UserAttentionType, UserEvent,
  21. WindowEventId,
  22. };
  23. #[cfg(windows)]
  24. use webview2_com::FocusChangedEventHandler;
  25. #[cfg(windows)]
  26. use windows::Win32::{Foundation::HWND, System::WinRT::EventRegistrationToken};
  27. #[cfg(target_os = "macos")]
  28. use wry::application::platform::macos::EventLoopWindowTargetExtMacOS;
  29. #[cfg(target_os = "macos")]
  30. use wry::application::platform::macos::WindowBuilderExtMacOS;
  31. #[cfg(target_os = "linux")]
  32. use wry::application::platform::unix::{WindowBuilderExtUnix, WindowExtUnix};
  33. #[cfg(windows)]
  34. use wry::application::platform::windows::{WindowBuilderExtWindows, WindowExtWindows};
  35. #[cfg(windows)]
  36. use wry::webview::WebViewBuilderExtWindows;
  37. #[cfg(target_os = "macos")]
  38. use tauri_utils::TitleBarStyle;
  39. use tauri_utils::{
  40. config::WindowConfig, debug_eprintln, ProgressBarState, ProgressBarStatus, Theme,
  41. };
  42. use wry::{
  43. application::{
  44. dpi::{
  45. LogicalPosition as WryLogicalPosition, LogicalSize as WryLogicalSize,
  46. PhysicalPosition as WryPhysicalPosition, PhysicalSize as WryPhysicalSize,
  47. Position as WryPosition, Size as WrySize,
  48. },
  49. event::{Event, StartCause, WindowEvent as WryWindowEvent},
  50. event_loop::{
  51. ControlFlow, DeviceEventFilter as WryDeviceEventFilter, EventLoop, EventLoopBuilder,
  52. EventLoopProxy as WryEventLoopProxy, EventLoopWindowTarget,
  53. },
  54. monitor::MonitorHandle,
  55. window::{
  56. CursorIcon as WryCursorIcon, Fullscreen, Icon as WryWindowIcon,
  57. ProgressBarState as WryProgressBarState, ProgressState as WryProgressState,
  58. Theme as WryTheme, UserAttentionType as WryUserAttentionType,
  59. },
  60. },
  61. webview::{FileDropEvent as WryFileDropEvent, Url, WebContext, WebView, WebViewBuilder},
  62. };
  63. pub use wry;
  64. pub use wry::application::window::{Window, WindowBuilder as WryWindowBuilder, WindowId};
  65. pub use wry::webview::webview_version;
  66. #[cfg(windows)]
  67. use wry::webview::WebviewExtWindows;
  68. #[cfg(target_os = "android")]
  69. use wry::webview::{
  70. prelude::{dispatch, find_class},
  71. WebViewBuilderExtAndroid, WebviewExtAndroid,
  72. };
  73. #[cfg(target_os = "macos")]
  74. use tauri_runtime::ActivationPolicy;
  75. #[cfg(target_os = "macos")]
  76. pub use wry::application::platform::macos::{
  77. ActivationPolicy as WryActivationPolicy, EventLoopExtMacOS, WindowExtMacOS,
  78. };
  79. use std::{
  80. cell::RefCell,
  81. collections::{
  82. hash_map::Entry::{Occupied, Vacant},
  83. HashMap,
  84. },
  85. fmt,
  86. ops::Deref,
  87. path::PathBuf,
  88. rc::Rc,
  89. sync::{
  90. atomic::{AtomicU32, Ordering},
  91. mpsc::{channel, Sender},
  92. Arc, Mutex, Weak,
  93. },
  94. thread::{current as current_thread, ThreadId},
  95. };
  96. pub type WebviewId = u32;
  97. type IpcHandler = dyn Fn(&Window, String) + 'static;
  98. type FileDropHandler = dyn Fn(&Window, WryFileDropEvent) -> bool + 'static;
  99. mod webview;
  100. pub use webview::Webview;
  101. pub type WebContextStore = Arc<Mutex<HashMap<Option<PathBuf>, WebContext>>>;
  102. // window
  103. pub type WindowEventHandler = Box<dyn Fn(&WindowEvent) + Send>;
  104. pub type WindowEventListeners = Arc<Mutex<HashMap<WindowEventId, WindowEventHandler>>>;
  105. #[derive(Debug, Clone, Default)]
  106. pub struct WebviewIdStore(Arc<Mutex<HashMap<WindowId, WebviewId>>>);
  107. impl WebviewIdStore {
  108. pub fn insert(&self, w: WindowId, id: WebviewId) {
  109. self.0.lock().unwrap().insert(w, id);
  110. }
  111. fn get(&self, w: &WindowId) -> Option<WebviewId> {
  112. self.0.lock().unwrap().get(w).copied()
  113. }
  114. }
  115. #[macro_export]
  116. macro_rules! getter {
  117. ($self: ident, $rx: expr, $message: expr) => {{
  118. $crate::send_user_message(&$self.context, $message)?;
  119. $rx
  120. .recv()
  121. .map_err(|_| $crate::Error::FailedToReceiveMessage)
  122. }};
  123. }
  124. macro_rules! window_getter {
  125. ($self: ident, $message: expr) => {{
  126. let (tx, rx) = channel();
  127. getter!($self, rx, Message::Window($self.window_id, $message(tx)))
  128. }};
  129. }
  130. pub(crate) fn send_user_message<T: UserEvent>(
  131. context: &Context<T>,
  132. message: Message<T>,
  133. ) -> Result<()> {
  134. if current_thread().id() == context.main_thread_id {
  135. handle_user_message(
  136. &context.main_thread.window_target,
  137. message,
  138. UserMessageContext {
  139. webview_id_map: context.webview_id_map.clone(),
  140. windows: context.main_thread.windows.clone(),
  141. },
  142. &context.main_thread.web_context,
  143. );
  144. Ok(())
  145. } else {
  146. context
  147. .proxy
  148. .send_event(message)
  149. .map_err(|_| Error::FailedToSendMessage)
  150. }
  151. }
  152. #[derive(Clone)]
  153. pub struct Context<T: UserEvent> {
  154. pub webview_id_map: WebviewIdStore,
  155. main_thread_id: ThreadId,
  156. pub proxy: WryEventLoopProxy<Message<T>>,
  157. main_thread: DispatcherMainThreadContext<T>,
  158. plugins: Arc<Mutex<Vec<Box<dyn Plugin<T> + Send>>>>,
  159. next_window_id: Arc<AtomicU32>,
  160. next_window_event_id: Arc<AtomicU32>,
  161. next_webcontext_id: Arc<AtomicU32>,
  162. }
  163. impl<T: UserEvent> Context<T> {
  164. pub fn run_threaded<R, F>(&self, f: F) -> R
  165. where
  166. F: FnOnce(Option<&DispatcherMainThreadContext<T>>) -> R,
  167. {
  168. f(if current_thread().id() == self.main_thread_id {
  169. Some(&self.main_thread)
  170. } else {
  171. None
  172. })
  173. }
  174. fn next_window_id(&self) -> WebviewId {
  175. self.next_window_id.fetch_add(1, Ordering::Relaxed)
  176. }
  177. fn next_window_event_id(&self) -> WebviewId {
  178. self.next_window_event_id.fetch_add(1, Ordering::Relaxed)
  179. }
  180. fn next_webcontext_id(&self) -> WebviewId {
  181. self.next_webcontext_id.fetch_add(1, Ordering::Relaxed)
  182. }
  183. }
  184. impl<T: UserEvent> Context<T> {
  185. fn create_webview<F: Fn(RawWindow) + Send + 'static>(
  186. &self,
  187. pending: PendingWindow<T, Wry<T>>,
  188. before_webview_creation: Option<F>,
  189. ) -> Result<DetachedWindow<T, Wry<T>>> {
  190. let label = pending.label.clone();
  191. let context = self.clone();
  192. let window_id = self.next_window_id();
  193. send_user_message(
  194. self,
  195. Message::CreateWebview(
  196. window_id,
  197. Box::new(move |event_loop, web_context| {
  198. create_webview(
  199. window_id,
  200. event_loop,
  201. web_context,
  202. context,
  203. pending,
  204. before_webview_creation,
  205. )
  206. }),
  207. ),
  208. )?;
  209. let dispatcher = WryDispatcher {
  210. window_id,
  211. context: self.clone(),
  212. };
  213. Ok(DetachedWindow { label, dispatcher })
  214. }
  215. }
  216. #[derive(Clone)]
  217. pub struct DispatcherMainThreadContext<T: UserEvent> {
  218. pub window_target: EventLoopWindowTarget<Message<T>>,
  219. pub web_context: WebContextStore,
  220. pub windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>,
  221. }
  222. impl<T: UserEvent> std::fmt::Debug for DispatcherMainThreadContext<T> {
  223. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  224. f.debug_struct("DispatcherMainThreadContext")
  225. .field("window_target", &self.window_target)
  226. .field("web_context", &self.web_context)
  227. .field("windows", &self.windows)
  228. .finish()
  229. }
  230. }
  231. // SAFETY: we ensure this type is only used on the main thread.
  232. #[allow(clippy::non_send_fields_in_send_ty)]
  233. unsafe impl<T: UserEvent> Send for DispatcherMainThreadContext<T> {}
  234. // SAFETY: we ensure this type is only used on the main thread.
  235. #[allow(clippy::non_send_fields_in_send_ty)]
  236. unsafe impl<T: UserEvent> Sync for DispatcherMainThreadContext<T> {}
  237. impl<T: UserEvent> fmt::Debug for Context<T> {
  238. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  239. f.debug_struct("Context")
  240. .field("main_thread_id", &self.main_thread_id)
  241. .field("proxy", &self.proxy)
  242. .field("main_thread", &self.main_thread)
  243. .finish()
  244. }
  245. }
  246. pub struct DeviceEventFilterWrapper(pub WryDeviceEventFilter);
  247. impl From<DeviceEventFilter> for DeviceEventFilterWrapper {
  248. fn from(item: DeviceEventFilter) -> Self {
  249. match item {
  250. DeviceEventFilter::Always => Self(WryDeviceEventFilter::Always),
  251. DeviceEventFilter::Never => Self(WryDeviceEventFilter::Never),
  252. DeviceEventFilter::Unfocused => Self(WryDeviceEventFilter::Unfocused),
  253. }
  254. }
  255. }
  256. /// Wrapper around a [`wry::application::window::Icon`] that can be created from an [`Icon`].
  257. pub struct WryIcon(pub WryWindowIcon);
  258. fn icon_err<E: std::error::Error + Send + Sync + 'static>(e: E) -> Error {
  259. Error::InvalidIcon(Box::new(e))
  260. }
  261. impl TryFrom<Icon> for WryIcon {
  262. type Error = Error;
  263. fn try_from(icon: Icon) -> std::result::Result<Self, Self::Error> {
  264. WryWindowIcon::from_rgba(icon.rgba, icon.width, icon.height)
  265. .map(Self)
  266. .map_err(icon_err)
  267. }
  268. }
  269. pub struct WindowEventWrapper(pub Option<WindowEvent>);
  270. impl WindowEventWrapper {
  271. fn parse(webview: &Option<WindowHandle>, event: &WryWindowEvent<'_>) -> Self {
  272. match event {
  273. // resized event from tao doesn't include a reliable size on macOS
  274. // because wry replaces the NSView
  275. WryWindowEvent::Resized(_) => {
  276. if let Some(webview) = webview {
  277. Self(Some(WindowEvent::Resized(
  278. PhysicalSizeWrapper(webview.inner_size()).into(),
  279. )))
  280. } else {
  281. Self(None)
  282. }
  283. }
  284. e => e.into(),
  285. }
  286. }
  287. }
  288. pub fn map_theme(theme: &WryTheme) -> Theme {
  289. match theme {
  290. WryTheme::Light => Theme::Light,
  291. WryTheme::Dark => Theme::Dark,
  292. _ => Theme::Light,
  293. }
  294. }
  295. impl<'a> From<&WryWindowEvent<'a>> for WindowEventWrapper {
  296. fn from(event: &WryWindowEvent<'a>) -> Self {
  297. let event = match event {
  298. WryWindowEvent::Resized(size) => WindowEvent::Resized(PhysicalSizeWrapper(*size).into()),
  299. WryWindowEvent::Moved(position) => {
  300. WindowEvent::Moved(PhysicalPositionWrapper(*position).into())
  301. }
  302. WryWindowEvent::Destroyed => WindowEvent::Destroyed,
  303. WryWindowEvent::ScaleFactorChanged {
  304. scale_factor,
  305. new_inner_size,
  306. } => WindowEvent::ScaleFactorChanged {
  307. scale_factor: *scale_factor,
  308. new_inner_size: PhysicalSizeWrapper(**new_inner_size).into(),
  309. },
  310. #[cfg(any(target_os = "linux", target_os = "macos"))]
  311. WryWindowEvent::Focused(focused) => WindowEvent::Focused(*focused),
  312. WryWindowEvent::ThemeChanged(theme) => WindowEvent::ThemeChanged(map_theme(theme)),
  313. _ => return Self(None),
  314. };
  315. Self(Some(event))
  316. }
  317. }
  318. impl From<&WebviewEvent> for WindowEventWrapper {
  319. fn from(event: &WebviewEvent) -> Self {
  320. let event = match event {
  321. WebviewEvent::Focused(focused) => WindowEvent::Focused(*focused),
  322. };
  323. Self(Some(event))
  324. }
  325. }
  326. pub struct MonitorHandleWrapper(pub MonitorHandle);
  327. impl From<MonitorHandleWrapper> for Monitor {
  328. fn from(monitor: MonitorHandleWrapper) -> Monitor {
  329. Self {
  330. name: monitor.0.name(),
  331. position: PhysicalPositionWrapper(monitor.0.position()).into(),
  332. size: PhysicalSizeWrapper(monitor.0.size()).into(),
  333. scale_factor: monitor.0.scale_factor(),
  334. }
  335. }
  336. }
  337. pub struct PhysicalPositionWrapper<T>(pub WryPhysicalPosition<T>);
  338. impl<T> From<PhysicalPositionWrapper<T>> for PhysicalPosition<T> {
  339. fn from(position: PhysicalPositionWrapper<T>) -> Self {
  340. Self {
  341. x: position.0.x,
  342. y: position.0.y,
  343. }
  344. }
  345. }
  346. impl<T> From<PhysicalPosition<T>> for PhysicalPositionWrapper<T> {
  347. fn from(position: PhysicalPosition<T>) -> Self {
  348. Self(WryPhysicalPosition {
  349. x: position.x,
  350. y: position.y,
  351. })
  352. }
  353. }
  354. struct LogicalPositionWrapper<T>(WryLogicalPosition<T>);
  355. impl<T> From<LogicalPosition<T>> for LogicalPositionWrapper<T> {
  356. fn from(position: LogicalPosition<T>) -> Self {
  357. Self(WryLogicalPosition {
  358. x: position.x,
  359. y: position.y,
  360. })
  361. }
  362. }
  363. pub struct PhysicalSizeWrapper<T>(pub WryPhysicalSize<T>);
  364. impl<T> From<PhysicalSizeWrapper<T>> for PhysicalSize<T> {
  365. fn from(size: PhysicalSizeWrapper<T>) -> Self {
  366. Self {
  367. width: size.0.width,
  368. height: size.0.height,
  369. }
  370. }
  371. }
  372. impl<T> From<PhysicalSize<T>> for PhysicalSizeWrapper<T> {
  373. fn from(size: PhysicalSize<T>) -> Self {
  374. Self(WryPhysicalSize {
  375. width: size.width,
  376. height: size.height,
  377. })
  378. }
  379. }
  380. struct LogicalSizeWrapper<T>(WryLogicalSize<T>);
  381. impl<T> From<LogicalSize<T>> for LogicalSizeWrapper<T> {
  382. fn from(size: LogicalSize<T>) -> Self {
  383. Self(WryLogicalSize {
  384. width: size.width,
  385. height: size.height,
  386. })
  387. }
  388. }
  389. pub struct SizeWrapper(pub WrySize);
  390. impl From<Size> for SizeWrapper {
  391. fn from(size: Size) -> Self {
  392. match size {
  393. Size::Logical(s) => Self(WrySize::Logical(LogicalSizeWrapper::from(s).0)),
  394. Size::Physical(s) => Self(WrySize::Physical(PhysicalSizeWrapper::from(s).0)),
  395. }
  396. }
  397. }
  398. pub struct PositionWrapper(pub WryPosition);
  399. impl From<Position> for PositionWrapper {
  400. fn from(position: Position) -> Self {
  401. match position {
  402. Position::Logical(s) => Self(WryPosition::Logical(LogicalPositionWrapper::from(s).0)),
  403. Position::Physical(s) => Self(WryPosition::Physical(PhysicalPositionWrapper::from(s).0)),
  404. }
  405. }
  406. }
  407. #[derive(Debug, Clone)]
  408. pub struct UserAttentionTypeWrapper(pub WryUserAttentionType);
  409. impl From<UserAttentionType> for UserAttentionTypeWrapper {
  410. fn from(request_type: UserAttentionType) -> Self {
  411. let o = match request_type {
  412. UserAttentionType::Critical => WryUserAttentionType::Critical,
  413. UserAttentionType::Informational => WryUserAttentionType::Informational,
  414. };
  415. Self(o)
  416. }
  417. }
  418. #[derive(Debug)]
  419. pub struct CursorIconWrapper(pub WryCursorIcon);
  420. impl From<CursorIcon> for CursorIconWrapper {
  421. fn from(icon: CursorIcon) -> Self {
  422. use CursorIcon::*;
  423. let i = match icon {
  424. Default => WryCursorIcon::Default,
  425. Crosshair => WryCursorIcon::Crosshair,
  426. Hand => WryCursorIcon::Hand,
  427. Arrow => WryCursorIcon::Arrow,
  428. Move => WryCursorIcon::Move,
  429. Text => WryCursorIcon::Text,
  430. Wait => WryCursorIcon::Wait,
  431. Help => WryCursorIcon::Help,
  432. Progress => WryCursorIcon::Progress,
  433. NotAllowed => WryCursorIcon::NotAllowed,
  434. ContextMenu => WryCursorIcon::ContextMenu,
  435. Cell => WryCursorIcon::Cell,
  436. VerticalText => WryCursorIcon::VerticalText,
  437. Alias => WryCursorIcon::Alias,
  438. Copy => WryCursorIcon::Copy,
  439. NoDrop => WryCursorIcon::NoDrop,
  440. Grab => WryCursorIcon::Grab,
  441. Grabbing => WryCursorIcon::Grabbing,
  442. AllScroll => WryCursorIcon::AllScroll,
  443. ZoomIn => WryCursorIcon::ZoomIn,
  444. ZoomOut => WryCursorIcon::ZoomOut,
  445. EResize => WryCursorIcon::EResize,
  446. NResize => WryCursorIcon::NResize,
  447. NeResize => WryCursorIcon::NeResize,
  448. NwResize => WryCursorIcon::NwResize,
  449. SResize => WryCursorIcon::SResize,
  450. SeResize => WryCursorIcon::SeResize,
  451. SwResize => WryCursorIcon::SwResize,
  452. WResize => WryCursorIcon::WResize,
  453. EwResize => WryCursorIcon::EwResize,
  454. NsResize => WryCursorIcon::NsResize,
  455. NeswResize => WryCursorIcon::NeswResize,
  456. NwseResize => WryCursorIcon::NwseResize,
  457. ColResize => WryCursorIcon::ColResize,
  458. RowResize => WryCursorIcon::RowResize,
  459. _ => WryCursorIcon::Default,
  460. };
  461. Self(i)
  462. }
  463. }
  464. pub struct ProgressStateWrapper(pub WryProgressState);
  465. impl From<ProgressBarStatus> for ProgressStateWrapper {
  466. fn from(status: ProgressBarStatus) -> Self {
  467. let state = match status {
  468. ProgressBarStatus::None => WryProgressState::None,
  469. ProgressBarStatus::Normal => WryProgressState::Normal,
  470. ProgressBarStatus::Indeterminate => WryProgressState::Indeterminate,
  471. ProgressBarStatus::Paused => WryProgressState::Paused,
  472. ProgressBarStatus::Error => WryProgressState::Error,
  473. };
  474. Self(state)
  475. }
  476. }
  477. pub struct ProgressBarStateWrapper(pub WryProgressBarState);
  478. impl From<ProgressBarState> for ProgressBarStateWrapper {
  479. fn from(progress_state: ProgressBarState) -> Self {
  480. Self(WryProgressBarState {
  481. progress: progress_state.progress,
  482. state: progress_state
  483. .status
  484. .map(|state| ProgressStateWrapper::from(state).0),
  485. unity_uri: progress_state.unity_uri,
  486. })
  487. }
  488. }
  489. #[derive(Clone, Default)]
  490. pub struct WindowBuilderWrapper {
  491. inner: WryWindowBuilder,
  492. center: bool,
  493. #[cfg(target_os = "macos")]
  494. tabbing_identifier: Option<String>,
  495. }
  496. impl std::fmt::Debug for WindowBuilderWrapper {
  497. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  498. let mut s = f.debug_struct("WindowBuilderWrapper");
  499. s.field("inner", &self.inner).field("center", &self.center);
  500. #[cfg(target_os = "macos")]
  501. {
  502. s.field("tabbing_identifier", &self.tabbing_identifier);
  503. }
  504. s.finish()
  505. }
  506. }
  507. // SAFETY: this type is `Send` since `menu_items` are read only here
  508. #[allow(clippy::non_send_fields_in_send_ty)]
  509. unsafe impl Send for WindowBuilderWrapper {}
  510. impl WindowBuilderBase for WindowBuilderWrapper {}
  511. impl WindowBuilder for WindowBuilderWrapper {
  512. fn new() -> Self {
  513. Self::default().focused(true)
  514. }
  515. fn with_config(config: WindowConfig) -> Self {
  516. let mut window = WindowBuilderWrapper::new();
  517. #[cfg(target_os = "macos")]
  518. {
  519. window = window
  520. .hidden_title(config.hidden_title)
  521. .title_bar_style(config.title_bar_style);
  522. if let Some(identifier) = &config.tabbing_identifier {
  523. window = window.tabbing_identifier(identifier);
  524. }
  525. }
  526. #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
  527. {
  528. window = window.transparent(config.transparent);
  529. }
  530. #[cfg(all(
  531. target_os = "macos",
  532. not(feature = "macos-private-api"),
  533. debug_assertions
  534. ))]
  535. if config.transparent {
  536. eprintln!(
  537. "The window is set to be transparent but the `macos-private-api` is not enabled.
  538. This can be enabled via the `tauri.macOSPrivateApi` configuration property <https://tauri.app/docs/api/config#tauri.macOSPrivateApi>
  539. ");
  540. }
  541. #[cfg(target_os = "linux")]
  542. {
  543. // Mouse event is disabled on Linux since sudden event bursts could block event loop.
  544. window.inner = window.inner.with_cursor_moved_event(false);
  545. }
  546. #[cfg(desktop)]
  547. {
  548. window = window
  549. .title(config.title.to_string())
  550. .inner_size(config.width, config.height)
  551. .visible(config.visible)
  552. .resizable(config.resizable)
  553. .fullscreen(config.fullscreen)
  554. .decorations(config.decorations)
  555. .maximized(config.maximized)
  556. .always_on_bottom(config.always_on_bottom)
  557. .always_on_top(config.always_on_top)
  558. .visible_on_all_workspaces(config.visible_on_all_workspaces)
  559. .content_protected(config.content_protected)
  560. .skip_taskbar(config.skip_taskbar)
  561. .theme(config.theme)
  562. .shadow(config.shadow);
  563. if let (Some(min_width), Some(min_height)) = (config.min_width, config.min_height) {
  564. window = window.min_inner_size(min_width, min_height);
  565. }
  566. if let (Some(max_width), Some(max_height)) = (config.max_width, config.max_height) {
  567. window = window.max_inner_size(max_width, max_height);
  568. }
  569. if let (Some(x), Some(y)) = (config.x, config.y) {
  570. window = window.position(x, y);
  571. }
  572. if config.center {
  573. window = window.center();
  574. }
  575. }
  576. window
  577. }
  578. fn center(mut self) -> Self {
  579. self.center = true;
  580. self
  581. }
  582. fn position(mut self, x: f64, y: f64) -> Self {
  583. self.inner = self.inner.with_position(WryLogicalPosition::new(x, y));
  584. self
  585. }
  586. fn inner_size(mut self, width: f64, height: f64) -> Self {
  587. self.inner = self
  588. .inner
  589. .with_inner_size(WryLogicalSize::new(width, height));
  590. self
  591. }
  592. fn min_inner_size(mut self, min_width: f64, min_height: f64) -> Self {
  593. self.inner = self
  594. .inner
  595. .with_min_inner_size(WryLogicalSize::new(min_width, min_height));
  596. self
  597. }
  598. fn max_inner_size(mut self, max_width: f64, max_height: f64) -> Self {
  599. self.inner = self
  600. .inner
  601. .with_max_inner_size(WryLogicalSize::new(max_width, max_height));
  602. self
  603. }
  604. fn resizable(mut self, resizable: bool) -> Self {
  605. self.inner = self.inner.with_resizable(resizable);
  606. self
  607. }
  608. fn maximizable(mut self, maximizable: bool) -> Self {
  609. self.inner = self.inner.with_maximizable(maximizable);
  610. self
  611. }
  612. fn minimizable(mut self, minimizable: bool) -> Self {
  613. self.inner = self.inner.with_minimizable(minimizable);
  614. self
  615. }
  616. fn closable(mut self, closable: bool) -> Self {
  617. self.inner = self.inner.with_closable(closable);
  618. self
  619. }
  620. fn title<S: Into<String>>(mut self, title: S) -> Self {
  621. self.inner = self.inner.with_title(title.into());
  622. self
  623. }
  624. fn fullscreen(mut self, fullscreen: bool) -> Self {
  625. self.inner = if fullscreen {
  626. self
  627. .inner
  628. .with_fullscreen(Some(Fullscreen::Borderless(None)))
  629. } else {
  630. self.inner.with_fullscreen(None)
  631. };
  632. self
  633. }
  634. fn focused(mut self, focused: bool) -> Self {
  635. self.inner = self.inner.with_focused(focused);
  636. self
  637. }
  638. fn maximized(mut self, maximized: bool) -> Self {
  639. self.inner = self.inner.with_maximized(maximized);
  640. self
  641. }
  642. fn visible(mut self, visible: bool) -> Self {
  643. self.inner = self.inner.with_visible(visible);
  644. self
  645. }
  646. #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
  647. fn transparent(mut self, transparent: bool) -> Self {
  648. self.inner = self.inner.with_transparent(transparent);
  649. self
  650. }
  651. fn decorations(mut self, decorations: bool) -> Self {
  652. self.inner = self.inner.with_decorations(decorations);
  653. self
  654. }
  655. fn always_on_bottom(mut self, always_on_bottom: bool) -> Self {
  656. self.inner = self.inner.with_always_on_bottom(always_on_bottom);
  657. self
  658. }
  659. fn always_on_top(mut self, always_on_top: bool) -> Self {
  660. self.inner = self.inner.with_always_on_top(always_on_top);
  661. self
  662. }
  663. fn visible_on_all_workspaces(mut self, visible_on_all_workspaces: bool) -> Self {
  664. self.inner = self
  665. .inner
  666. .with_visible_on_all_workspaces(visible_on_all_workspaces);
  667. self
  668. }
  669. fn content_protected(mut self, protected: bool) -> Self {
  670. self.inner = self.inner.with_content_protection(protected);
  671. self
  672. }
  673. fn shadow(#[allow(unused_mut)] mut self, _enable: bool) -> Self {
  674. #[cfg(windows)]
  675. {
  676. self.inner = self.inner.with_undecorated_shadow(_enable);
  677. }
  678. #[cfg(target_os = "macos")]
  679. {
  680. self.inner = self.inner.with_has_shadow(_enable);
  681. }
  682. self
  683. }
  684. #[cfg(windows)]
  685. fn parent_window(mut self, parent: HWND) -> Self {
  686. self.inner = self.inner.with_parent_window(parent.0);
  687. self
  688. }
  689. #[cfg(target_os = "macos")]
  690. fn parent_window(mut self, parent: *mut std::ffi::c_void) -> Self {
  691. self.inner = self.inner.with_parent_window(parent);
  692. self
  693. }
  694. #[cfg(windows)]
  695. fn owner_window(mut self, owner: HWND) -> Self {
  696. self.inner = self.inner.with_owner_window(owner.0);
  697. self
  698. }
  699. #[cfg(target_os = "macos")]
  700. fn title_bar_style(mut self, style: TitleBarStyle) -> Self {
  701. match style {
  702. TitleBarStyle::Visible => {
  703. self.inner = self.inner.with_titlebar_transparent(false);
  704. // Fixes rendering issue when resizing window with devtools open (https://github.com/tauri-apps/tauri/issues/3914)
  705. self.inner = self.inner.with_fullsize_content_view(true);
  706. }
  707. TitleBarStyle::Transparent => {
  708. self.inner = self.inner.with_titlebar_transparent(true);
  709. self.inner = self.inner.with_fullsize_content_view(false);
  710. }
  711. TitleBarStyle::Overlay => {
  712. self.inner = self.inner.with_titlebar_transparent(true);
  713. self.inner = self.inner.with_fullsize_content_view(true);
  714. }
  715. }
  716. self
  717. }
  718. #[cfg(target_os = "macos")]
  719. fn hidden_title(mut self, hidden: bool) -> Self {
  720. self.inner = self.inner.with_title_hidden(hidden);
  721. self
  722. }
  723. #[cfg(target_os = "macos")]
  724. fn tabbing_identifier(mut self, identifier: &str) -> Self {
  725. self.inner = self.inner.with_tabbing_identifier(identifier);
  726. self.tabbing_identifier.replace(identifier.into());
  727. self
  728. }
  729. fn icon(mut self, icon: Icon) -> Result<Self> {
  730. self.inner = self
  731. .inner
  732. .with_window_icon(Some(WryIcon::try_from(icon)?.0));
  733. Ok(self)
  734. }
  735. #[cfg(any(windows, target_os = "linux"))]
  736. fn skip_taskbar(mut self, skip: bool) -> Self {
  737. self.inner = self.inner.with_skip_taskbar(skip);
  738. self
  739. }
  740. #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))]
  741. fn skip_taskbar(self, _skip: bool) -> Self {
  742. self
  743. }
  744. #[allow(unused_variables, unused_mut)]
  745. fn theme(mut self, theme: Option<Theme>) -> Self {
  746. self.inner = self.inner.with_theme(if let Some(t) = theme {
  747. match t {
  748. Theme::Dark => Some(WryTheme::Dark),
  749. _ => Some(WryTheme::Light),
  750. }
  751. } else {
  752. None
  753. });
  754. self
  755. }
  756. fn has_icon(&self) -> bool {
  757. self.inner.window.window_icon.is_some()
  758. }
  759. }
  760. pub struct FileDropEventWrapper(WryFileDropEvent);
  761. // on Linux, the paths are percent-encoded
  762. #[cfg(any(
  763. target_os = "linux",
  764. target_os = "dragonfly",
  765. target_os = "freebsd",
  766. target_os = "netbsd",
  767. target_os = "openbsd"
  768. ))]
  769. fn decode_path(path: PathBuf) -> PathBuf {
  770. percent_encoding::percent_decode(path.display().to_string().as_bytes())
  771. .decode_utf8_lossy()
  772. .into_owned()
  773. .into()
  774. }
  775. // on Windows and macOS, we do not need to decode the path
  776. #[cfg(not(any(
  777. target_os = "linux",
  778. target_os = "dragonfly",
  779. target_os = "freebsd",
  780. target_os = "netbsd",
  781. target_os = "openbsd"
  782. )))]
  783. fn decode_path(path: PathBuf) -> PathBuf {
  784. path
  785. }
  786. impl From<FileDropEventWrapper> for FileDropEvent {
  787. fn from(event: FileDropEventWrapper) -> Self {
  788. match event.0 {
  789. WryFileDropEvent::Hovered { paths, position } => FileDropEvent::Hovered {
  790. paths: paths.into_iter().map(decode_path).collect(),
  791. position: PhysicalPositionWrapper(position).into(),
  792. },
  793. WryFileDropEvent::Dropped { paths, position } => FileDropEvent::Dropped {
  794. paths: paths.into_iter().map(decode_path).collect(),
  795. position: PhysicalPositionWrapper(position).into(),
  796. },
  797. // default to cancelled
  798. // FIXME(maybe): Add `FileDropEvent::Unknown` event?
  799. _ => FileDropEvent::Cancelled,
  800. }
  801. }
  802. }
  803. #[cfg(any(
  804. target_os = "linux",
  805. target_os = "dragonfly",
  806. target_os = "freebsd",
  807. target_os = "netbsd",
  808. target_os = "openbsd"
  809. ))]
  810. pub struct GtkWindow(pub gtk::ApplicationWindow);
  811. #[cfg(any(
  812. target_os = "linux",
  813. target_os = "dragonfly",
  814. target_os = "freebsd",
  815. target_os = "netbsd",
  816. target_os = "openbsd"
  817. ))]
  818. #[allow(clippy::non_send_fields_in_send_ty)]
  819. unsafe impl Send for GtkWindow {}
  820. #[cfg(any(
  821. target_os = "linux",
  822. target_os = "dragonfly",
  823. target_os = "freebsd",
  824. target_os = "netbsd",
  825. target_os = "openbsd"
  826. ))]
  827. pub struct GtkBox(pub gtk::Box);
  828. #[cfg(any(
  829. target_os = "linux",
  830. target_os = "dragonfly",
  831. target_os = "freebsd",
  832. target_os = "netbsd",
  833. target_os = "openbsd"
  834. ))]
  835. #[allow(clippy::non_send_fields_in_send_ty)]
  836. unsafe impl Send for GtkBox {}
  837. pub struct RawWindowHandle(pub raw_window_handle::RawWindowHandle);
  838. unsafe impl Send for RawWindowHandle {}
  839. #[cfg(target_os = "macos")]
  840. #[derive(Debug, Clone)]
  841. pub enum ApplicationMessage {
  842. Show,
  843. Hide,
  844. }
  845. pub enum WindowMessage {
  846. WithWebview(Box<dyn FnOnce(Webview) + Send>),
  847. AddEventListener(WindowEventId, Box<dyn Fn(&WindowEvent) + Send>),
  848. // Devtools
  849. #[cfg(any(debug_assertions, feature = "devtools"))]
  850. OpenDevTools,
  851. #[cfg(any(debug_assertions, feature = "devtools"))]
  852. CloseDevTools,
  853. #[cfg(any(debug_assertions, feature = "devtools"))]
  854. IsDevToolsOpen(Sender<bool>),
  855. // Getters
  856. Url(Sender<Url>),
  857. ScaleFactor(Sender<f64>),
  858. InnerPosition(Sender<Result<PhysicalPosition<i32>>>),
  859. OuterPosition(Sender<Result<PhysicalPosition<i32>>>),
  860. InnerSize(Sender<PhysicalSize<u32>>),
  861. OuterSize(Sender<PhysicalSize<u32>>),
  862. IsFullscreen(Sender<bool>),
  863. IsMinimized(Sender<bool>),
  864. IsMaximized(Sender<bool>),
  865. IsFocused(Sender<bool>),
  866. IsDecorated(Sender<bool>),
  867. IsResizable(Sender<bool>),
  868. IsMaximizable(Sender<bool>),
  869. IsMinimizable(Sender<bool>),
  870. IsClosable(Sender<bool>),
  871. IsVisible(Sender<bool>),
  872. Title(Sender<String>),
  873. CurrentMonitor(Sender<Option<MonitorHandle>>),
  874. PrimaryMonitor(Sender<Option<MonitorHandle>>),
  875. AvailableMonitors(Sender<Vec<MonitorHandle>>),
  876. #[cfg(any(
  877. target_os = "linux",
  878. target_os = "dragonfly",
  879. target_os = "freebsd",
  880. target_os = "netbsd",
  881. target_os = "openbsd"
  882. ))]
  883. GtkWindow(Sender<GtkWindow>),
  884. #[cfg(any(
  885. target_os = "linux",
  886. target_os = "dragonfly",
  887. target_os = "freebsd",
  888. target_os = "netbsd",
  889. target_os = "openbsd"
  890. ))]
  891. GtkBox(Sender<GtkBox>),
  892. RawWindowHandle(Sender<RawWindowHandle>),
  893. Theme(Sender<Theme>),
  894. // Setters
  895. Center,
  896. RequestUserAttention(Option<UserAttentionTypeWrapper>),
  897. SetResizable(bool),
  898. SetMaximizable(bool),
  899. SetMinimizable(bool),
  900. SetClosable(bool),
  901. SetTitle(String),
  902. Navigate(Url),
  903. Maximize,
  904. Unmaximize,
  905. Minimize,
  906. Unminimize,
  907. Show,
  908. Hide,
  909. Close,
  910. SetDecorations(bool),
  911. SetShadow(bool),
  912. SetAlwaysOnBottom(bool),
  913. SetAlwaysOnTop(bool),
  914. SetVisibleOnAllWorkspaces(bool),
  915. SetContentProtected(bool),
  916. SetSize(Size),
  917. SetMinSize(Option<Size>),
  918. SetMaxSize(Option<Size>),
  919. SetPosition(Position),
  920. SetFullscreen(bool),
  921. SetFocus,
  922. SetIcon(WryWindowIcon),
  923. SetSkipTaskbar(bool),
  924. SetCursorGrab(bool),
  925. SetCursorVisible(bool),
  926. SetCursorIcon(CursorIcon),
  927. SetCursorPosition(Position),
  928. SetIgnoreCursorEvents(bool),
  929. SetProgressBar(ProgressBarState),
  930. DragWindow,
  931. RequestRedraw,
  932. }
  933. #[derive(Debug, Clone)]
  934. pub enum WebviewMessage {
  935. EvaluateScript(String),
  936. #[allow(dead_code)]
  937. WebviewEvent(WebviewEvent),
  938. Print,
  939. }
  940. #[allow(dead_code)]
  941. #[derive(Debug, Clone)]
  942. pub enum WebviewEvent {
  943. Focused(bool),
  944. }
  945. pub type CreateWebviewClosure<T> = Box<
  946. dyn FnOnce(&EventLoopWindowTarget<Message<T>>, &WebContextStore) -> Result<WindowWrapper> + Send,
  947. >;
  948. pub enum Message<T: 'static> {
  949. Task(Box<dyn FnOnce() + Send>),
  950. #[cfg(target_os = "macos")]
  951. Application(ApplicationMessage),
  952. Window(WebviewId, WindowMessage),
  953. Webview(WebviewId, WebviewMessage),
  954. CreateWebview(WebviewId, CreateWebviewClosure<T>),
  955. CreateWindow(
  956. WebviewId,
  957. Box<dyn FnOnce() -> (String, WryWindowBuilder) + Send>,
  958. Sender<Result<Weak<Window>>>,
  959. ),
  960. UserEvent(T),
  961. }
  962. impl<T: UserEvent> Clone for Message<T> {
  963. fn clone(&self) -> Self {
  964. match self {
  965. Self::Webview(i, m) => Self::Webview(*i, m.clone()),
  966. Self::UserEvent(t) => Self::UserEvent(t.clone()),
  967. _ => unimplemented!(),
  968. }
  969. }
  970. }
  971. /// The Tauri [`Dispatch`] for [`Wry`].
  972. #[derive(Debug, Clone)]
  973. pub struct WryDispatcher<T: UserEvent> {
  974. window_id: WebviewId,
  975. context: Context<T>,
  976. }
  977. // SAFETY: this is safe since the `Context` usage is guarded on `send_user_message`.
  978. #[allow(clippy::non_send_fields_in_send_ty)]
  979. unsafe impl<T: UserEvent> Sync for WryDispatcher<T> {}
  980. impl<T: UserEvent> Dispatch<T> for WryDispatcher<T> {
  981. type Runtime = Wry<T>;
  982. type WindowBuilder = WindowBuilderWrapper;
  983. fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
  984. send_user_message(&self.context, Message::Task(Box::new(f)))
  985. }
  986. fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) -> WindowEventId {
  987. let id = self.context.next_window_event_id();
  988. let _ = self.context.proxy.send_event(Message::Window(
  989. self.window_id,
  990. WindowMessage::AddEventListener(id, Box::new(f)),
  991. ));
  992. id
  993. }
  994. fn with_webview<F: FnOnce(Box<dyn std::any::Any>) + Send + 'static>(&self, f: F) -> Result<()> {
  995. send_user_message(
  996. &self.context,
  997. Message::Window(
  998. self.window_id,
  999. WindowMessage::WithWebview(Box::new(move |webview| f(Box::new(webview)))),
  1000. ),
  1001. )
  1002. }
  1003. #[cfg(any(debug_assertions, feature = "devtools"))]
  1004. fn open_devtools(&self) {
  1005. let _ = send_user_message(
  1006. &self.context,
  1007. Message::Window(self.window_id, WindowMessage::OpenDevTools),
  1008. );
  1009. }
  1010. #[cfg(any(debug_assertions, feature = "devtools"))]
  1011. fn close_devtools(&self) {
  1012. let _ = send_user_message(
  1013. &self.context,
  1014. Message::Window(self.window_id, WindowMessage::CloseDevTools),
  1015. );
  1016. }
  1017. /// Gets the devtools window's current open state.
  1018. #[cfg(any(debug_assertions, feature = "devtools"))]
  1019. fn is_devtools_open(&self) -> Result<bool> {
  1020. window_getter!(self, WindowMessage::IsDevToolsOpen)
  1021. }
  1022. // Getters
  1023. fn url(&self) -> Result<Url> {
  1024. window_getter!(self, WindowMessage::Url)
  1025. }
  1026. fn scale_factor(&self) -> Result<f64> {
  1027. window_getter!(self, WindowMessage::ScaleFactor)
  1028. }
  1029. fn inner_position(&self) -> Result<PhysicalPosition<i32>> {
  1030. window_getter!(self, WindowMessage::InnerPosition)?
  1031. }
  1032. fn outer_position(&self) -> Result<PhysicalPosition<i32>> {
  1033. window_getter!(self, WindowMessage::OuterPosition)?
  1034. }
  1035. fn inner_size(&self) -> Result<PhysicalSize<u32>> {
  1036. window_getter!(self, WindowMessage::InnerSize)
  1037. }
  1038. fn outer_size(&self) -> Result<PhysicalSize<u32>> {
  1039. window_getter!(self, WindowMessage::OuterSize)
  1040. }
  1041. fn is_fullscreen(&self) -> Result<bool> {
  1042. window_getter!(self, WindowMessage::IsFullscreen)
  1043. }
  1044. fn is_minimized(&self) -> Result<bool> {
  1045. window_getter!(self, WindowMessage::IsMinimized)
  1046. }
  1047. fn is_maximized(&self) -> Result<bool> {
  1048. window_getter!(self, WindowMessage::IsMaximized)
  1049. }
  1050. fn is_focused(&self) -> Result<bool> {
  1051. window_getter!(self, WindowMessage::IsFocused)
  1052. }
  1053. /// Gets the window’s current decoration state.
  1054. fn is_decorated(&self) -> Result<bool> {
  1055. window_getter!(self, WindowMessage::IsDecorated)
  1056. }
  1057. /// Gets the window’s current resizable state.
  1058. fn is_resizable(&self) -> Result<bool> {
  1059. window_getter!(self, WindowMessage::IsResizable)
  1060. }
  1061. /// Gets the current native window's maximize button state
  1062. fn is_maximizable(&self) -> Result<bool> {
  1063. window_getter!(self, WindowMessage::IsMaximizable)
  1064. }
  1065. /// Gets the current native window's minimize button state
  1066. fn is_minimizable(&self) -> Result<bool> {
  1067. window_getter!(self, WindowMessage::IsMinimizable)
  1068. }
  1069. /// Gets the current native window's close button state
  1070. fn is_closable(&self) -> Result<bool> {
  1071. window_getter!(self, WindowMessage::IsClosable)
  1072. }
  1073. fn is_visible(&self) -> Result<bool> {
  1074. window_getter!(self, WindowMessage::IsVisible)
  1075. }
  1076. fn title(&self) -> Result<String> {
  1077. window_getter!(self, WindowMessage::Title)
  1078. }
  1079. fn current_monitor(&self) -> Result<Option<Monitor>> {
  1080. Ok(window_getter!(self, WindowMessage::CurrentMonitor)?.map(|m| MonitorHandleWrapper(m).into()))
  1081. }
  1082. fn primary_monitor(&self) -> Result<Option<Monitor>> {
  1083. Ok(window_getter!(self, WindowMessage::PrimaryMonitor)?.map(|m| MonitorHandleWrapper(m).into()))
  1084. }
  1085. fn available_monitors(&self) -> Result<Vec<Monitor>> {
  1086. Ok(
  1087. window_getter!(self, WindowMessage::AvailableMonitors)?
  1088. .into_iter()
  1089. .map(|m| MonitorHandleWrapper(m).into())
  1090. .collect(),
  1091. )
  1092. }
  1093. fn theme(&self) -> Result<Theme> {
  1094. window_getter!(self, WindowMessage::Theme)
  1095. }
  1096. #[cfg(any(
  1097. target_os = "linux",
  1098. target_os = "dragonfly",
  1099. target_os = "freebsd",
  1100. target_os = "netbsd",
  1101. target_os = "openbsd"
  1102. ))]
  1103. fn gtk_window(&self) -> Result<gtk::ApplicationWindow> {
  1104. window_getter!(self, WindowMessage::GtkWindow).map(|w| w.0)
  1105. }
  1106. #[cfg(any(
  1107. target_os = "linux",
  1108. target_os = "dragonfly",
  1109. target_os = "freebsd",
  1110. target_os = "netbsd",
  1111. target_os = "openbsd"
  1112. ))]
  1113. fn default_vbox(&self) -> Result<gtk::Box> {
  1114. window_getter!(self, WindowMessage::GtkBox).map(|w| w.0)
  1115. }
  1116. fn raw_window_handle(&self) -> Result<raw_window_handle::RawWindowHandle> {
  1117. window_getter!(self, WindowMessage::RawWindowHandle).map(|w| w.0)
  1118. }
  1119. // Setters
  1120. fn center(&self) -> Result<()> {
  1121. send_user_message(
  1122. &self.context,
  1123. Message::Window(self.window_id, WindowMessage::Center),
  1124. )
  1125. }
  1126. fn print(&self) -> Result<()> {
  1127. send_user_message(
  1128. &self.context,
  1129. Message::Webview(self.window_id, WebviewMessage::Print),
  1130. )
  1131. }
  1132. fn request_user_attention(&self, request_type: Option<UserAttentionType>) -> Result<()> {
  1133. send_user_message(
  1134. &self.context,
  1135. Message::Window(
  1136. self.window_id,
  1137. WindowMessage::RequestUserAttention(request_type.map(Into::into)),
  1138. ),
  1139. )
  1140. }
  1141. // Creates a window by dispatching a message to the event loop.
  1142. // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock.
  1143. fn create_window<F: Fn(RawWindow) + Send + 'static>(
  1144. &mut self,
  1145. pending: PendingWindow<T, Self::Runtime>,
  1146. before_webview_creation: Option<F>,
  1147. ) -> Result<DetachedWindow<T, Self::Runtime>> {
  1148. self
  1149. .context
  1150. .create_webview(pending, before_webview_creation)
  1151. }
  1152. fn set_resizable(&self, resizable: bool) -> Result<()> {
  1153. send_user_message(
  1154. &self.context,
  1155. Message::Window(self.window_id, WindowMessage::SetResizable(resizable)),
  1156. )
  1157. }
  1158. fn set_maximizable(&self, maximizable: bool) -> Result<()> {
  1159. send_user_message(
  1160. &self.context,
  1161. Message::Window(self.window_id, WindowMessage::SetMaximizable(maximizable)),
  1162. )
  1163. }
  1164. fn set_minimizable(&self, minimizable: bool) -> Result<()> {
  1165. send_user_message(
  1166. &self.context,
  1167. Message::Window(self.window_id, WindowMessage::SetMinimizable(minimizable)),
  1168. )
  1169. }
  1170. fn set_closable(&self, closable: bool) -> Result<()> {
  1171. send_user_message(
  1172. &self.context,
  1173. Message::Window(self.window_id, WindowMessage::SetClosable(closable)),
  1174. )
  1175. }
  1176. fn set_title<S: Into<String>>(&self, title: S) -> Result<()> {
  1177. send_user_message(
  1178. &self.context,
  1179. Message::Window(self.window_id, WindowMessage::SetTitle(title.into())),
  1180. )
  1181. }
  1182. fn navigate(&self, url: Url) -> Result<()> {
  1183. send_user_message(
  1184. &self.context,
  1185. Message::Window(self.window_id, WindowMessage::Navigate(url)),
  1186. )
  1187. }
  1188. fn maximize(&self) -> Result<()> {
  1189. send_user_message(
  1190. &self.context,
  1191. Message::Window(self.window_id, WindowMessage::Maximize),
  1192. )
  1193. }
  1194. fn unmaximize(&self) -> Result<()> {
  1195. send_user_message(
  1196. &self.context,
  1197. Message::Window(self.window_id, WindowMessage::Unmaximize),
  1198. )
  1199. }
  1200. fn minimize(&self) -> Result<()> {
  1201. send_user_message(
  1202. &self.context,
  1203. Message::Window(self.window_id, WindowMessage::Minimize),
  1204. )
  1205. }
  1206. fn unminimize(&self) -> Result<()> {
  1207. send_user_message(
  1208. &self.context,
  1209. Message::Window(self.window_id, WindowMessage::Unminimize),
  1210. )
  1211. }
  1212. fn show(&self) -> Result<()> {
  1213. send_user_message(
  1214. &self.context,
  1215. Message::Window(self.window_id, WindowMessage::Show),
  1216. )
  1217. }
  1218. fn hide(&self) -> Result<()> {
  1219. send_user_message(
  1220. &self.context,
  1221. Message::Window(self.window_id, WindowMessage::Hide),
  1222. )
  1223. }
  1224. fn close(&self) -> Result<()> {
  1225. // NOTE: close cannot use the `send_user_message` function because it accesses the event loop callback
  1226. self
  1227. .context
  1228. .proxy
  1229. .send_event(Message::Window(self.window_id, WindowMessage::Close))
  1230. .map_err(|_| Error::FailedToSendMessage)
  1231. }
  1232. fn set_decorations(&self, decorations: bool) -> Result<()> {
  1233. send_user_message(
  1234. &self.context,
  1235. Message::Window(self.window_id, WindowMessage::SetDecorations(decorations)),
  1236. )
  1237. }
  1238. fn set_shadow(&self, enable: bool) -> Result<()> {
  1239. send_user_message(
  1240. &self.context,
  1241. Message::Window(self.window_id, WindowMessage::SetShadow(enable)),
  1242. )
  1243. }
  1244. fn set_always_on_bottom(&self, always_on_bottom: bool) -> Result<()> {
  1245. send_user_message(
  1246. &self.context,
  1247. Message::Window(
  1248. self.window_id,
  1249. WindowMessage::SetAlwaysOnBottom(always_on_bottom),
  1250. ),
  1251. )
  1252. }
  1253. fn set_always_on_top(&self, always_on_top: bool) -> Result<()> {
  1254. send_user_message(
  1255. &self.context,
  1256. Message::Window(self.window_id, WindowMessage::SetAlwaysOnTop(always_on_top)),
  1257. )
  1258. }
  1259. fn set_visible_on_all_workspaces(&self, visible_on_all_workspaces: bool) -> Result<()> {
  1260. send_user_message(
  1261. &self.context,
  1262. Message::Window(
  1263. self.window_id,
  1264. WindowMessage::SetVisibleOnAllWorkspaces(visible_on_all_workspaces),
  1265. ),
  1266. )
  1267. }
  1268. fn set_content_protected(&self, protected: bool) -> Result<()> {
  1269. send_user_message(
  1270. &self.context,
  1271. Message::Window(
  1272. self.window_id,
  1273. WindowMessage::SetContentProtected(protected),
  1274. ),
  1275. )
  1276. }
  1277. fn set_size(&self, size: Size) -> Result<()> {
  1278. send_user_message(
  1279. &self.context,
  1280. Message::Window(self.window_id, WindowMessage::SetSize(size)),
  1281. )
  1282. }
  1283. fn set_min_size(&self, size: Option<Size>) -> Result<()> {
  1284. send_user_message(
  1285. &self.context,
  1286. Message::Window(self.window_id, WindowMessage::SetMinSize(size)),
  1287. )
  1288. }
  1289. fn set_max_size(&self, size: Option<Size>) -> Result<()> {
  1290. send_user_message(
  1291. &self.context,
  1292. Message::Window(self.window_id, WindowMessage::SetMaxSize(size)),
  1293. )
  1294. }
  1295. fn set_position(&self, position: Position) -> Result<()> {
  1296. send_user_message(
  1297. &self.context,
  1298. Message::Window(self.window_id, WindowMessage::SetPosition(position)),
  1299. )
  1300. }
  1301. fn set_fullscreen(&self, fullscreen: bool) -> Result<()> {
  1302. send_user_message(
  1303. &self.context,
  1304. Message::Window(self.window_id, WindowMessage::SetFullscreen(fullscreen)),
  1305. )
  1306. }
  1307. fn set_focus(&self) -> Result<()> {
  1308. send_user_message(
  1309. &self.context,
  1310. Message::Window(self.window_id, WindowMessage::SetFocus),
  1311. )
  1312. }
  1313. fn set_icon(&self, icon: Icon) -> Result<()> {
  1314. send_user_message(
  1315. &self.context,
  1316. Message::Window(
  1317. self.window_id,
  1318. WindowMessage::SetIcon(WryIcon::try_from(icon)?.0),
  1319. ),
  1320. )
  1321. }
  1322. fn set_skip_taskbar(&self, skip: bool) -> Result<()> {
  1323. send_user_message(
  1324. &self.context,
  1325. Message::Window(self.window_id, WindowMessage::SetSkipTaskbar(skip)),
  1326. )
  1327. }
  1328. fn set_cursor_grab(&self, grab: bool) -> crate::Result<()> {
  1329. send_user_message(
  1330. &self.context,
  1331. Message::Window(self.window_id, WindowMessage::SetCursorGrab(grab)),
  1332. )
  1333. }
  1334. fn set_cursor_visible(&self, visible: bool) -> crate::Result<()> {
  1335. send_user_message(
  1336. &self.context,
  1337. Message::Window(self.window_id, WindowMessage::SetCursorVisible(visible)),
  1338. )
  1339. }
  1340. fn set_cursor_icon(&self, icon: CursorIcon) -> crate::Result<()> {
  1341. send_user_message(
  1342. &self.context,
  1343. Message::Window(self.window_id, WindowMessage::SetCursorIcon(icon)),
  1344. )
  1345. }
  1346. fn set_cursor_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
  1347. send_user_message(
  1348. &self.context,
  1349. Message::Window(
  1350. self.window_id,
  1351. WindowMessage::SetCursorPosition(position.into()),
  1352. ),
  1353. )
  1354. }
  1355. fn set_ignore_cursor_events(&self, ignore: bool) -> crate::Result<()> {
  1356. send_user_message(
  1357. &self.context,
  1358. Message::Window(self.window_id, WindowMessage::SetIgnoreCursorEvents(ignore)),
  1359. )
  1360. }
  1361. fn start_dragging(&self) -> Result<()> {
  1362. send_user_message(
  1363. &self.context,
  1364. Message::Window(self.window_id, WindowMessage::DragWindow),
  1365. )
  1366. }
  1367. fn eval_script<S: Into<String>>(&self, script: S) -> Result<()> {
  1368. send_user_message(
  1369. &self.context,
  1370. Message::Webview(
  1371. self.window_id,
  1372. WebviewMessage::EvaluateScript(script.into()),
  1373. ),
  1374. )
  1375. }
  1376. fn set_progress_bar(&self, progress_state: ProgressBarState) -> Result<()> {
  1377. send_user_message(
  1378. &self.context,
  1379. Message::Window(
  1380. self.window_id,
  1381. WindowMessage::SetProgressBar(progress_state),
  1382. ),
  1383. )
  1384. }
  1385. }
  1386. #[derive(Clone)]
  1387. enum WindowHandle {
  1388. Webview {
  1389. inner: Rc<WebView>,
  1390. context_store: WebContextStore,
  1391. // the key of the WebContext if it's not shared
  1392. context_key: Option<PathBuf>,
  1393. },
  1394. Window(Arc<Window>),
  1395. }
  1396. impl Drop for WindowHandle {
  1397. fn drop(&mut self) {
  1398. if let Self::Webview {
  1399. inner,
  1400. context_store,
  1401. context_key,
  1402. } = self
  1403. {
  1404. if Rc::get_mut(inner).is_some() {
  1405. context_store.lock().unwrap().remove(context_key);
  1406. }
  1407. }
  1408. }
  1409. }
  1410. impl fmt::Debug for WindowHandle {
  1411. fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
  1412. Ok(())
  1413. }
  1414. }
  1415. impl Deref for WindowHandle {
  1416. type Target = Window;
  1417. #[inline(always)]
  1418. fn deref(&self) -> &Window {
  1419. match self {
  1420. Self::Webview { inner, .. } => inner.window(),
  1421. Self::Window(w) => w,
  1422. }
  1423. }
  1424. }
  1425. impl WindowHandle {
  1426. fn inner_size(&self) -> WryPhysicalSize<u32> {
  1427. match self {
  1428. WindowHandle::Window(w) => w.inner_size(),
  1429. WindowHandle::Webview { inner, .. } => inner.inner_size(),
  1430. }
  1431. }
  1432. }
  1433. pub struct WindowWrapper {
  1434. label: String,
  1435. inner: Option<WindowHandle>,
  1436. window_event_listeners: WindowEventListeners,
  1437. }
  1438. impl fmt::Debug for WindowWrapper {
  1439. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  1440. f.debug_struct("WindowWrapper")
  1441. .field("label", &self.label)
  1442. .field("inner", &self.inner)
  1443. .finish()
  1444. }
  1445. }
  1446. #[derive(Debug, Clone)]
  1447. pub struct EventProxy<T: UserEvent>(WryEventLoopProxy<Message<T>>);
  1448. #[cfg(target_os = "ios")]
  1449. #[allow(clippy::non_send_fields_in_send_ty)]
  1450. unsafe impl<T: UserEvent> Sync for EventProxy<T> {}
  1451. impl<T: UserEvent> EventLoopProxy<T> for EventProxy<T> {
  1452. fn send_event(&self, event: T) -> Result<()> {
  1453. self
  1454. .0
  1455. .send_event(Message::UserEvent(event))
  1456. .map_err(|_| Error::EventLoopClosed)
  1457. }
  1458. }
  1459. pub trait PluginBuilder<T: UserEvent> {
  1460. type Plugin: Plugin<T>;
  1461. fn build(self, context: Context<T>) -> Self::Plugin;
  1462. }
  1463. pub trait Plugin<T: UserEvent> {
  1464. fn on_event(
  1465. &mut self,
  1466. event: &Event<Message<T>>,
  1467. event_loop: &EventLoopWindowTarget<Message<T>>,
  1468. proxy: &WryEventLoopProxy<Message<T>>,
  1469. control_flow: &mut ControlFlow,
  1470. context: EventLoopIterationContext<'_, T>,
  1471. web_context: &WebContextStore,
  1472. ) -> bool;
  1473. }
  1474. /// A Tauri [`Runtime`] wrapper around wry.
  1475. pub struct Wry<T: UserEvent> {
  1476. context: Context<T>,
  1477. event_loop: EventLoop<Message<T>>,
  1478. }
  1479. impl<T: UserEvent> fmt::Debug for Wry<T> {
  1480. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  1481. f.debug_struct("Wry")
  1482. .field("main_thread_id", &self.context.main_thread_id)
  1483. .field("event_loop", &self.event_loop)
  1484. .field("windows", &self.context.main_thread.windows)
  1485. .field("web_context", &self.context.main_thread.web_context)
  1486. .finish()
  1487. }
  1488. }
  1489. /// A handle to the Wry runtime.
  1490. #[derive(Debug, Clone)]
  1491. pub struct WryHandle<T: UserEvent> {
  1492. context: Context<T>,
  1493. }
  1494. // SAFETY: this is safe since the `Context` usage is guarded on `send_user_message`.
  1495. #[allow(clippy::non_send_fields_in_send_ty)]
  1496. unsafe impl<T: UserEvent> Sync for WryHandle<T> {}
  1497. impl<T: UserEvent> WryHandle<T> {
  1498. /// Creates a new tao window using a callback, and returns its window id.
  1499. pub fn create_tao_window<F: FnOnce() -> (String, WryWindowBuilder) + Send + 'static>(
  1500. &self,
  1501. f: F,
  1502. ) -> Result<Weak<Window>> {
  1503. let id = self.context.next_window_id();
  1504. let (tx, rx) = channel();
  1505. send_user_message(&self.context, Message::CreateWindow(id, Box::new(f), tx))?;
  1506. rx.recv().unwrap()
  1507. }
  1508. /// Gets the [`WebviewId'] associated with the given [`WindowId`].
  1509. pub fn window_id(&self, window_id: WindowId) -> WebviewId {
  1510. *self
  1511. .context
  1512. .webview_id_map
  1513. .0
  1514. .lock()
  1515. .unwrap()
  1516. .get(&window_id)
  1517. .unwrap()
  1518. }
  1519. /// Send a message to the event loop.
  1520. pub fn send_event(&self, message: Message<T>) -> Result<()> {
  1521. self
  1522. .context
  1523. .proxy
  1524. .send_event(message)
  1525. .map_err(|_| Error::FailedToSendMessage)?;
  1526. Ok(())
  1527. }
  1528. pub fn plugin<P: PluginBuilder<T> + 'static>(&mut self, plugin: P)
  1529. where
  1530. <P as PluginBuilder<T>>::Plugin: Send,
  1531. {
  1532. self
  1533. .context
  1534. .plugins
  1535. .lock()
  1536. .unwrap()
  1537. .push(Box::new(plugin.build(self.context.clone())));
  1538. }
  1539. }
  1540. impl<T: UserEvent> RuntimeHandle<T> for WryHandle<T> {
  1541. type Runtime = Wry<T>;
  1542. fn create_proxy(&self) -> EventProxy<T> {
  1543. EventProxy(self.context.proxy.clone())
  1544. }
  1545. // Creates a window by dispatching a message to the event loop.
  1546. // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock.
  1547. fn create_window<F: Fn(RawWindow) + Send + 'static>(
  1548. &self,
  1549. pending: PendingWindow<T, Self::Runtime>,
  1550. before_webview_creation: Option<F>,
  1551. ) -> Result<DetachedWindow<T, Self::Runtime>> {
  1552. self
  1553. .context
  1554. .create_webview(pending, before_webview_creation)
  1555. }
  1556. fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
  1557. send_user_message(&self.context, Message::Task(Box::new(f)))
  1558. }
  1559. fn raw_display_handle(&self) -> RawDisplayHandle {
  1560. self.context.main_thread.window_target.raw_display_handle()
  1561. }
  1562. fn primary_monitor(&self) -> Option<Monitor> {
  1563. self
  1564. .context
  1565. .main_thread
  1566. .window_target
  1567. .primary_monitor()
  1568. .map(|m| MonitorHandleWrapper(m).into())
  1569. }
  1570. fn available_monitors(&self) -> Vec<Monitor> {
  1571. self
  1572. .context
  1573. .main_thread
  1574. .window_target
  1575. .available_monitors()
  1576. .map(|m| MonitorHandleWrapper(m).into())
  1577. .collect()
  1578. }
  1579. #[cfg(target_os = "macos")]
  1580. fn show(&self) -> tauri_runtime::Result<()> {
  1581. send_user_message(
  1582. &self.context,
  1583. Message::Application(ApplicationMessage::Show),
  1584. )
  1585. }
  1586. #[cfg(target_os = "macos")]
  1587. fn hide(&self) -> tauri_runtime::Result<()> {
  1588. send_user_message(
  1589. &self.context,
  1590. Message::Application(ApplicationMessage::Hide),
  1591. )
  1592. }
  1593. #[cfg(target_os = "android")]
  1594. fn find_class<'a>(
  1595. &self,
  1596. env: &mut jni::JNIEnv<'a>,
  1597. activity: &jni::objects::JObject<'_>,
  1598. name: impl Into<String>,
  1599. ) -> std::result::Result<jni::objects::JClass<'a>, jni::errors::Error> {
  1600. find_class(env, activity, name.into())
  1601. }
  1602. #[cfg(target_os = "android")]
  1603. fn run_on_android_context<F>(&self, f: F)
  1604. where
  1605. F: FnOnce(&mut jni::JNIEnv, &jni::objects::JObject, &jni::objects::JObject) + Send + 'static,
  1606. {
  1607. dispatch(f)
  1608. }
  1609. }
  1610. impl<T: UserEvent> Wry<T> {
  1611. fn init_with_builder(
  1612. mut event_loop_builder: EventLoopBuilder<Message<T>>,
  1613. #[allow(unused_variables)] args: RuntimeInitArgs,
  1614. ) -> Result<Self> {
  1615. #[cfg(windows)]
  1616. if let Some(hook) = args.msg_hook {
  1617. use wry::application::platform::windows::EventLoopBuilderExtWindows;
  1618. event_loop_builder.with_msg_hook(hook);
  1619. }
  1620. Self::init(event_loop_builder.build())
  1621. }
  1622. fn init(event_loop: EventLoop<Message<T>>) -> Result<Self> {
  1623. let main_thread_id = current_thread().id();
  1624. let web_context = WebContextStore::default();
  1625. let windows = Rc::new(RefCell::new(HashMap::default()));
  1626. let webview_id_map = WebviewIdStore::default();
  1627. let context = Context {
  1628. webview_id_map,
  1629. main_thread_id,
  1630. proxy: event_loop.create_proxy(),
  1631. main_thread: DispatcherMainThreadContext {
  1632. window_target: event_loop.deref().clone(),
  1633. web_context,
  1634. windows,
  1635. },
  1636. plugins: Default::default(),
  1637. next_window_id: Default::default(),
  1638. next_window_event_id: Default::default(),
  1639. next_webcontext_id: Default::default(),
  1640. };
  1641. Ok(Self {
  1642. context,
  1643. event_loop,
  1644. })
  1645. }
  1646. }
  1647. impl<T: UserEvent> Runtime<T> for Wry<T> {
  1648. type Dispatcher = WryDispatcher<T>;
  1649. type Handle = WryHandle<T>;
  1650. type EventLoopProxy = EventProxy<T>;
  1651. fn new(args: RuntimeInitArgs) -> Result<Self> {
  1652. Self::init_with_builder(EventLoopBuilder::<Message<T>>::with_user_event(), args)
  1653. }
  1654. #[cfg(any(
  1655. target_os = "linux",
  1656. target_os = "dragonfly",
  1657. target_os = "freebsd",
  1658. target_os = "netbsd",
  1659. target_os = "openbsd"
  1660. ))]
  1661. fn new_any_thread(args: RuntimeInitArgs) -> Result<Self> {
  1662. use wry::application::platform::unix::EventLoopBuilderExtUnix;
  1663. let mut event_loop_builder = EventLoopBuilder::<Message<T>>::with_user_event();
  1664. event_loop_builder.with_any_thread(true);
  1665. Self::init_with_builder(event_loop_builder, args)
  1666. }
  1667. #[cfg(windows)]
  1668. fn new_any_thread(args: RuntimeInitArgs) -> Result<Self> {
  1669. use wry::application::platform::windows::EventLoopBuilderExtWindows;
  1670. let mut event_loop_builder = EventLoopBuilder::<Message<T>>::with_user_event();
  1671. event_loop_builder.with_any_thread(true);
  1672. Self::init_with_builder(event_loop_builder, args)
  1673. }
  1674. fn create_proxy(&self) -> EventProxy<T> {
  1675. EventProxy(self.event_loop.create_proxy())
  1676. }
  1677. fn handle(&self) -> Self::Handle {
  1678. WryHandle {
  1679. context: self.context.clone(),
  1680. }
  1681. }
  1682. fn create_window<F: Fn(RawWindow) + Send + 'static>(
  1683. &self,
  1684. pending: PendingWindow<T, Self>,
  1685. before_webview_creation: Option<F>,
  1686. ) -> Result<DetachedWindow<T, Self>> {
  1687. let label = pending.label.clone();
  1688. let window_id = self.context.next_window_id();
  1689. let webview = create_webview(
  1690. window_id,
  1691. &self.event_loop,
  1692. &self.context.main_thread.web_context,
  1693. self.context.clone(),
  1694. pending,
  1695. before_webview_creation,
  1696. )?;
  1697. let dispatcher = WryDispatcher {
  1698. window_id,
  1699. context: self.context.clone(),
  1700. };
  1701. self
  1702. .context
  1703. .main_thread
  1704. .windows
  1705. .borrow_mut()
  1706. .insert(window_id, webview);
  1707. Ok(DetachedWindow { label, dispatcher })
  1708. }
  1709. fn primary_monitor(&self) -> Option<Monitor> {
  1710. self
  1711. .context
  1712. .main_thread
  1713. .window_target
  1714. .primary_monitor()
  1715. .map(|m| MonitorHandleWrapper(m).into())
  1716. }
  1717. fn available_monitors(&self) -> Vec<Monitor> {
  1718. self
  1719. .context
  1720. .main_thread
  1721. .window_target
  1722. .available_monitors()
  1723. .map(|m| MonitorHandleWrapper(m).into())
  1724. .collect()
  1725. }
  1726. #[cfg(target_os = "macos")]
  1727. fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
  1728. self
  1729. .event_loop
  1730. .set_activation_policy(match activation_policy {
  1731. ActivationPolicy::Regular => WryActivationPolicy::Regular,
  1732. ActivationPolicy::Accessory => WryActivationPolicy::Accessory,
  1733. ActivationPolicy::Prohibited => WryActivationPolicy::Prohibited,
  1734. _ => unimplemented!(),
  1735. });
  1736. }
  1737. #[cfg(target_os = "macos")]
  1738. fn show(&self) {
  1739. self.event_loop.show_application();
  1740. }
  1741. #[cfg(target_os = "macos")]
  1742. fn hide(&self) {
  1743. self.event_loop.hide_application();
  1744. }
  1745. fn set_device_event_filter(&mut self, filter: DeviceEventFilter) {
  1746. self
  1747. .event_loop
  1748. .set_device_event_filter(DeviceEventFilterWrapper::from(filter).0);
  1749. }
  1750. #[cfg(desktop)]
  1751. fn run_iteration<F: FnMut(RunEvent<T>) + 'static>(&mut self, mut callback: F) -> RunIteration {
  1752. use wry::application::platform::run_return::EventLoopExtRunReturn;
  1753. let windows = self.context.main_thread.windows.clone();
  1754. let webview_id_map = self.context.webview_id_map.clone();
  1755. let web_context = &self.context.main_thread.web_context;
  1756. let plugins = self.context.plugins.clone();
  1757. let mut iteration = RunIteration::default();
  1758. let proxy = self.event_loop.create_proxy();
  1759. self
  1760. .event_loop
  1761. .run_return(|event, event_loop, control_flow| {
  1762. *control_flow = ControlFlow::Wait;
  1763. if let Event::MainEventsCleared = &event {
  1764. *control_flow = ControlFlow::Exit;
  1765. }
  1766. for p in plugins.lock().unwrap().iter_mut() {
  1767. let prevent_default = p.on_event(
  1768. &event,
  1769. event_loop,
  1770. &proxy,
  1771. control_flow,
  1772. EventLoopIterationContext {
  1773. callback: &mut callback,
  1774. webview_id_map: webview_id_map.clone(),
  1775. windows: windows.clone(),
  1776. },
  1777. web_context,
  1778. );
  1779. if prevent_default {
  1780. return;
  1781. }
  1782. }
  1783. iteration = handle_event_loop(
  1784. event,
  1785. event_loop,
  1786. control_flow,
  1787. EventLoopIterationContext {
  1788. callback: &mut callback,
  1789. windows: windows.clone(),
  1790. webview_id_map: webview_id_map.clone(),
  1791. },
  1792. web_context,
  1793. );
  1794. });
  1795. iteration
  1796. }
  1797. fn run<F: FnMut(RunEvent<T>) + 'static>(self, mut callback: F) {
  1798. let windows = self.context.main_thread.windows.clone();
  1799. let webview_id_map = self.context.webview_id_map.clone();
  1800. let web_context = self.context.main_thread.web_context;
  1801. let plugins = self.context.plugins.clone();
  1802. let proxy = self.event_loop.create_proxy();
  1803. self.event_loop.run(move |event, event_loop, control_flow| {
  1804. for p in plugins.lock().unwrap().iter_mut() {
  1805. let prevent_default = p.on_event(
  1806. &event,
  1807. event_loop,
  1808. &proxy,
  1809. control_flow,
  1810. EventLoopIterationContext {
  1811. callback: &mut callback,
  1812. webview_id_map: webview_id_map.clone(),
  1813. windows: windows.clone(),
  1814. },
  1815. &web_context,
  1816. );
  1817. if prevent_default {
  1818. return;
  1819. }
  1820. }
  1821. handle_event_loop(
  1822. event,
  1823. event_loop,
  1824. control_flow,
  1825. EventLoopIterationContext {
  1826. callback: &mut callback,
  1827. webview_id_map: webview_id_map.clone(),
  1828. windows: windows.clone(),
  1829. },
  1830. &web_context,
  1831. );
  1832. })
  1833. }
  1834. }
  1835. pub struct EventLoopIterationContext<'a, T: UserEvent> {
  1836. pub callback: &'a mut (dyn FnMut(RunEvent<T>) + 'static),
  1837. pub webview_id_map: WebviewIdStore,
  1838. pub windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>,
  1839. }
  1840. struct UserMessageContext {
  1841. windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>,
  1842. webview_id_map: WebviewIdStore,
  1843. }
  1844. fn handle_user_message<T: UserEvent>(
  1845. event_loop: &EventLoopWindowTarget<Message<T>>,
  1846. message: Message<T>,
  1847. context: UserMessageContext,
  1848. web_context: &WebContextStore,
  1849. ) -> RunIteration {
  1850. let UserMessageContext {
  1851. webview_id_map,
  1852. windows,
  1853. } = context;
  1854. match message {
  1855. Message::Task(task) => task(),
  1856. #[cfg(target_os = "macos")]
  1857. Message::Application(application_message) => match application_message {
  1858. ApplicationMessage::Show => {
  1859. event_loop.show_application();
  1860. }
  1861. ApplicationMessage::Hide => {
  1862. event_loop.hide_application();
  1863. }
  1864. },
  1865. Message::Window(id, window_message) => {
  1866. let w = windows
  1867. .borrow()
  1868. .get(&id)
  1869. .map(|w| (w.inner.clone(), w.window_event_listeners.clone()));
  1870. if let Some((Some(window), window_event_listeners)) = w {
  1871. match window_message {
  1872. WindowMessage::WithWebview(f) => {
  1873. if let WindowHandle::Webview { inner: w, .. } = &window {
  1874. #[cfg(any(
  1875. target_os = "linux",
  1876. target_os = "dragonfly",
  1877. target_os = "freebsd",
  1878. target_os = "netbsd",
  1879. target_os = "openbsd"
  1880. ))]
  1881. {
  1882. use wry::webview::WebviewExtUnix;
  1883. f(w.webview());
  1884. }
  1885. #[cfg(target_os = "macos")]
  1886. {
  1887. use wry::webview::WebviewExtMacOS;
  1888. f(Webview {
  1889. webview: w.webview(),
  1890. manager: w.manager(),
  1891. ns_window: w.ns_window(),
  1892. });
  1893. }
  1894. #[cfg(target_os = "ios")]
  1895. {
  1896. use wry::{application::platform::ios::WindowExtIOS, webview::WebviewExtIOS};
  1897. f(Webview {
  1898. webview: w.webview(),
  1899. manager: w.manager(),
  1900. view_controller: w.window().ui_view_controller() as cocoa::base::id,
  1901. });
  1902. }
  1903. #[cfg(windows)]
  1904. {
  1905. f(Webview {
  1906. controller: w.controller(),
  1907. });
  1908. }
  1909. #[cfg(target_os = "android")]
  1910. {
  1911. f(w.handle())
  1912. }
  1913. }
  1914. }
  1915. WindowMessage::AddEventListener(id, listener) => {
  1916. window_event_listeners.lock().unwrap().insert(id, listener);
  1917. }
  1918. #[cfg(any(debug_assertions, feature = "devtools"))]
  1919. WindowMessage::OpenDevTools => {
  1920. if let WindowHandle::Webview { inner: w, .. } = &window {
  1921. w.open_devtools();
  1922. }
  1923. }
  1924. #[cfg(any(debug_assertions, feature = "devtools"))]
  1925. WindowMessage::CloseDevTools => {
  1926. if let WindowHandle::Webview { inner: w, .. } = &window {
  1927. w.close_devtools();
  1928. }
  1929. }
  1930. #[cfg(any(debug_assertions, feature = "devtools"))]
  1931. WindowMessage::IsDevToolsOpen(tx) => {
  1932. if let WindowHandle::Webview { inner: w, .. } = &window {
  1933. tx.send(w.is_devtools_open()).unwrap();
  1934. } else {
  1935. tx.send(false).unwrap();
  1936. }
  1937. }
  1938. // Getters
  1939. WindowMessage::Url(tx) => {
  1940. if let WindowHandle::Webview { inner: w, .. } = &window {
  1941. tx.send(w.url()).unwrap();
  1942. }
  1943. }
  1944. WindowMessage::ScaleFactor(tx) => tx.send(window.scale_factor()).unwrap(),
  1945. WindowMessage::InnerPosition(tx) => tx
  1946. .send(
  1947. window
  1948. .inner_position()
  1949. .map(|p| PhysicalPositionWrapper(p).into())
  1950. .map_err(|_| Error::FailedToSendMessage),
  1951. )
  1952. .unwrap(),
  1953. WindowMessage::OuterPosition(tx) => tx
  1954. .send(
  1955. window
  1956. .outer_position()
  1957. .map(|p| PhysicalPositionWrapper(p).into())
  1958. .map_err(|_| Error::FailedToSendMessage),
  1959. )
  1960. .unwrap(),
  1961. WindowMessage::InnerSize(tx) => tx
  1962. .send(PhysicalSizeWrapper(window.inner_size()).into())
  1963. .unwrap(),
  1964. WindowMessage::OuterSize(tx) => tx
  1965. .send(PhysicalSizeWrapper(window.outer_size()).into())
  1966. .unwrap(),
  1967. WindowMessage::IsFullscreen(tx) => tx.send(window.fullscreen().is_some()).unwrap(),
  1968. WindowMessage::IsMinimized(tx) => tx.send(window.is_minimized()).unwrap(),
  1969. WindowMessage::IsMaximized(tx) => tx.send(window.is_maximized()).unwrap(),
  1970. WindowMessage::IsFocused(tx) => tx.send(window.is_focused()).unwrap(),
  1971. WindowMessage::IsDecorated(tx) => tx.send(window.is_decorated()).unwrap(),
  1972. WindowMessage::IsResizable(tx) => tx.send(window.is_resizable()).unwrap(),
  1973. WindowMessage::IsMaximizable(tx) => tx.send(window.is_maximizable()).unwrap(),
  1974. WindowMessage::IsMinimizable(tx) => tx.send(window.is_minimizable()).unwrap(),
  1975. WindowMessage::IsClosable(tx) => tx.send(window.is_closable()).unwrap(),
  1976. WindowMessage::IsVisible(tx) => tx.send(window.is_visible()).unwrap(),
  1977. WindowMessage::Title(tx) => tx.send(window.title()).unwrap(),
  1978. WindowMessage::CurrentMonitor(tx) => tx.send(window.current_monitor()).unwrap(),
  1979. WindowMessage::PrimaryMonitor(tx) => tx.send(window.primary_monitor()).unwrap(),
  1980. WindowMessage::AvailableMonitors(tx) => {
  1981. tx.send(window.available_monitors().collect()).unwrap()
  1982. }
  1983. #[cfg(any(
  1984. target_os = "linux",
  1985. target_os = "dragonfly",
  1986. target_os = "freebsd",
  1987. target_os = "netbsd",
  1988. target_os = "openbsd"
  1989. ))]
  1990. WindowMessage::GtkWindow(tx) => tx.send(GtkWindow(window.gtk_window().clone())).unwrap(),
  1991. #[cfg(any(
  1992. target_os = "linux",
  1993. target_os = "dragonfly",
  1994. target_os = "freebsd",
  1995. target_os = "netbsd",
  1996. target_os = "openbsd"
  1997. ))]
  1998. WindowMessage::GtkBox(tx) => tx
  1999. .send(GtkBox(window.default_vbox().unwrap().clone()))
  2000. .unwrap(),
  2001. WindowMessage::RawWindowHandle(tx) => tx
  2002. .send(RawWindowHandle(window.raw_window_handle()))
  2003. .unwrap(),
  2004. WindowMessage::Theme(tx) => {
  2005. tx.send(map_theme(&window.theme())).unwrap();
  2006. }
  2007. // Setters
  2008. WindowMessage::Center => {
  2009. let _ = center_window(&window, window.inner_size());
  2010. }
  2011. WindowMessage::RequestUserAttention(request_type) => {
  2012. window.request_user_attention(request_type.map(|r| r.0));
  2013. }
  2014. WindowMessage::SetResizable(resizable) => window.set_resizable(resizable),
  2015. WindowMessage::SetMaximizable(maximizable) => window.set_maximizable(maximizable),
  2016. WindowMessage::SetMinimizable(minimizable) => window.set_minimizable(minimizable),
  2017. WindowMessage::SetClosable(closable) => window.set_closable(closable),
  2018. WindowMessage::SetTitle(title) => window.set_title(&title),
  2019. WindowMessage::Navigate(url) => {
  2020. if let WindowHandle::Webview { inner: w, .. } = &window {
  2021. w.load_url(url.as_str())
  2022. }
  2023. }
  2024. WindowMessage::Maximize => window.set_maximized(true),
  2025. WindowMessage::Unmaximize => window.set_maximized(false),
  2026. WindowMessage::Minimize => window.set_minimized(true),
  2027. WindowMessage::Unminimize => window.set_minimized(false),
  2028. WindowMessage::Show => window.set_visible(true),
  2029. WindowMessage::Hide => window.set_visible(false),
  2030. WindowMessage::Close => {
  2031. panic!("cannot handle `WindowMessage::Close` on the main thread")
  2032. }
  2033. WindowMessage::SetDecorations(decorations) => window.set_decorations(decorations),
  2034. WindowMessage::SetShadow(_enable) => {
  2035. #[cfg(windows)]
  2036. window.set_undecorated_shadow(_enable);
  2037. #[cfg(target_os = "macos")]
  2038. window.set_has_shadow(_enable);
  2039. }
  2040. WindowMessage::SetAlwaysOnBottom(always_on_bottom) => {
  2041. window.set_always_on_bottom(always_on_bottom)
  2042. }
  2043. WindowMessage::SetAlwaysOnTop(always_on_top) => window.set_always_on_top(always_on_top),
  2044. WindowMessage::SetVisibleOnAllWorkspaces(visible_on_all_workspaces) => {
  2045. window.set_visible_on_all_workspaces(visible_on_all_workspaces)
  2046. }
  2047. WindowMessage::SetContentProtected(protected) => window.set_content_protection(protected),
  2048. WindowMessage::SetSize(size) => {
  2049. window.set_inner_size(SizeWrapper::from(size).0);
  2050. }
  2051. WindowMessage::SetMinSize(size) => {
  2052. window.set_min_inner_size(size.map(|s| SizeWrapper::from(s).0));
  2053. }
  2054. WindowMessage::SetMaxSize(size) => {
  2055. window.set_max_inner_size(size.map(|s| SizeWrapper::from(s).0));
  2056. }
  2057. WindowMessage::SetPosition(position) => {
  2058. window.set_outer_position(PositionWrapper::from(position).0)
  2059. }
  2060. WindowMessage::SetFullscreen(fullscreen) => {
  2061. if fullscreen {
  2062. window.set_fullscreen(Some(Fullscreen::Borderless(None)))
  2063. } else {
  2064. window.set_fullscreen(None)
  2065. }
  2066. }
  2067. WindowMessage::SetFocus => {
  2068. window.set_focus();
  2069. }
  2070. WindowMessage::SetIcon(icon) => {
  2071. window.set_window_icon(Some(icon));
  2072. }
  2073. #[allow(unused_variables)]
  2074. WindowMessage::SetSkipTaskbar(skip) => {
  2075. #[cfg(any(windows, target_os = "linux"))]
  2076. window.set_skip_taskbar(skip);
  2077. }
  2078. WindowMessage::SetCursorGrab(grab) => {
  2079. let _ = window.set_cursor_grab(grab);
  2080. }
  2081. WindowMessage::SetCursorVisible(visible) => {
  2082. window.set_cursor_visible(visible);
  2083. }
  2084. WindowMessage::SetCursorIcon(icon) => {
  2085. window.set_cursor_icon(CursorIconWrapper::from(icon).0);
  2086. }
  2087. WindowMessage::SetCursorPosition(position) => {
  2088. let _ = window.set_cursor_position(PositionWrapper::from(position).0);
  2089. }
  2090. WindowMessage::SetIgnoreCursorEvents(ignore) => {
  2091. let _ = window.set_ignore_cursor_events(ignore);
  2092. }
  2093. WindowMessage::DragWindow => {
  2094. let _ = window.drag_window();
  2095. }
  2096. WindowMessage::RequestRedraw => {
  2097. window.request_redraw();
  2098. }
  2099. WindowMessage::SetProgressBar(progress_state) => {
  2100. window.set_progress_bar(ProgressBarStateWrapper::from(progress_state).0);
  2101. }
  2102. }
  2103. }
  2104. }
  2105. Message::Webview(id, webview_message) => match webview_message {
  2106. WebviewMessage::EvaluateScript(script) => {
  2107. if let Some(WindowHandle::Webview { inner: webview, .. }) =
  2108. windows.borrow().get(&id).and_then(|w| w.inner.as_ref())
  2109. {
  2110. if let Err(e) = webview.evaluate_script(&script) {
  2111. debug_eprintln!("{}", e);
  2112. }
  2113. }
  2114. }
  2115. WebviewMessage::Print => {
  2116. if let Some(WindowHandle::Webview { inner: webview, .. }) =
  2117. windows.borrow().get(&id).and_then(|w| w.inner.as_ref())
  2118. {
  2119. let _ = webview.print();
  2120. }
  2121. }
  2122. WebviewMessage::WebviewEvent(_event) => { /* already handled */ }
  2123. },
  2124. Message::CreateWebview(window_id, handler) => match handler(event_loop, web_context) {
  2125. Ok(webview) => {
  2126. windows.borrow_mut().insert(window_id, webview);
  2127. }
  2128. Err(e) => {
  2129. debug_eprintln!("{}", e);
  2130. }
  2131. },
  2132. Message::CreateWindow(window_id, handler, sender) => {
  2133. let (label, builder) = handler();
  2134. if let Ok(window) = builder.build(event_loop) {
  2135. webview_id_map.insert(window.id(), window_id);
  2136. let w = Arc::new(window);
  2137. windows.borrow_mut().insert(
  2138. window_id,
  2139. WindowWrapper {
  2140. label,
  2141. inner: Some(WindowHandle::Window(w.clone())),
  2142. window_event_listeners: Default::default(),
  2143. },
  2144. );
  2145. sender.send(Ok(Arc::downgrade(&w))).unwrap();
  2146. } else {
  2147. sender.send(Err(Error::CreateWindow)).unwrap();
  2148. }
  2149. }
  2150. Message::UserEvent(_) => (),
  2151. }
  2152. let it = RunIteration {
  2153. window_count: windows.borrow().len(),
  2154. };
  2155. it
  2156. }
  2157. fn handle_event_loop<T: UserEvent>(
  2158. event: Event<'_, Message<T>>,
  2159. event_loop: &EventLoopWindowTarget<Message<T>>,
  2160. control_flow: &mut ControlFlow,
  2161. context: EventLoopIterationContext<'_, T>,
  2162. web_context: &WebContextStore,
  2163. ) -> RunIteration {
  2164. let EventLoopIterationContext {
  2165. callback,
  2166. webview_id_map,
  2167. windows,
  2168. } = context;
  2169. if *control_flow != ControlFlow::Exit {
  2170. *control_flow = ControlFlow::Wait;
  2171. }
  2172. match event {
  2173. Event::NewEvents(StartCause::Init) => {
  2174. callback(RunEvent::Ready);
  2175. }
  2176. Event::NewEvents(StartCause::Poll) => {
  2177. callback(RunEvent::Resumed);
  2178. }
  2179. Event::MainEventsCleared => {
  2180. callback(RunEvent::MainEventsCleared);
  2181. }
  2182. Event::LoopDestroyed => {
  2183. callback(RunEvent::Exit);
  2184. }
  2185. Event::UserEvent(Message::Webview(id, WebviewMessage::WebviewEvent(event))) => {
  2186. if let Some(event) = WindowEventWrapper::from(&event).0 {
  2187. let windows = windows.borrow();
  2188. let window = windows.get(&id);
  2189. if let Some(window) = window {
  2190. callback(RunEvent::WindowEvent {
  2191. label: window.label.clone(),
  2192. event: event.clone(),
  2193. });
  2194. let listeners = window.window_event_listeners.lock().unwrap();
  2195. let handlers = listeners.values();
  2196. for handler in handlers {
  2197. handler(&event);
  2198. }
  2199. }
  2200. }
  2201. }
  2202. Event::WindowEvent {
  2203. event, window_id, ..
  2204. } => {
  2205. if let Some(window_id) = webview_id_map.get(&window_id) {
  2206. {
  2207. let windows_ref = windows.borrow();
  2208. if let Some(window) = windows_ref.get(&window_id) {
  2209. if let Some(event) = WindowEventWrapper::parse(&window.inner, &event).0 {
  2210. let label = window.label.clone();
  2211. let window_event_listeners = window.window_event_listeners.clone();
  2212. drop(windows_ref);
  2213. callback(RunEvent::WindowEvent {
  2214. label,
  2215. event: event.clone(),
  2216. });
  2217. let listeners = window_event_listeners.lock().unwrap();
  2218. let handlers = listeners.values();
  2219. for handler in handlers {
  2220. handler(&event);
  2221. }
  2222. }
  2223. }
  2224. }
  2225. match event {
  2226. #[cfg(windows)]
  2227. WryWindowEvent::ThemeChanged(theme) => {
  2228. if let Some(window) = windows.borrow().get(&window_id) {
  2229. if let Some(WindowHandle::Webview { inner, .. }) = &window.inner {
  2230. let theme = match theme {
  2231. WryTheme::Dark => wry::webview::Theme::Dark,
  2232. WryTheme::Light => wry::webview::Theme::Light,
  2233. _ => wry::webview::Theme::Light,
  2234. };
  2235. inner.set_theme(theme);
  2236. }
  2237. }
  2238. }
  2239. WryWindowEvent::CloseRequested => {
  2240. on_close_requested(callback, window_id, windows.clone());
  2241. }
  2242. WryWindowEvent::Destroyed => {
  2243. let removed = windows.borrow_mut().remove(&window_id).is_some();
  2244. if removed {
  2245. let is_empty = windows.borrow().is_empty();
  2246. if is_empty {
  2247. let (tx, rx) = channel();
  2248. callback(RunEvent::ExitRequested { tx });
  2249. let recv = rx.try_recv();
  2250. let should_prevent = matches!(recv, Ok(ExitRequestedEventAction::Prevent));
  2251. if !should_prevent {
  2252. *control_flow = ControlFlow::Exit;
  2253. }
  2254. }
  2255. }
  2256. }
  2257. _ => {}
  2258. }
  2259. }
  2260. }
  2261. Event::UserEvent(message) => match message {
  2262. Message::Window(id, WindowMessage::Close) => {
  2263. on_window_close(id, windows.clone());
  2264. }
  2265. Message::UserEvent(t) => callback(RunEvent::UserEvent(t)),
  2266. message => {
  2267. return handle_user_message(
  2268. event_loop,
  2269. message,
  2270. UserMessageContext {
  2271. webview_id_map,
  2272. windows,
  2273. },
  2274. web_context,
  2275. );
  2276. }
  2277. },
  2278. #[cfg(any(target_os = "macos", target_os = "ios"))]
  2279. Event::Opened { urls } => {
  2280. callback(RunEvent::Opened { urls });
  2281. }
  2282. _ => (),
  2283. }
  2284. let it = RunIteration {
  2285. window_count: windows.borrow().len(),
  2286. };
  2287. it
  2288. }
  2289. fn on_close_requested<'a, T: UserEvent>(
  2290. callback: &'a mut (dyn FnMut(RunEvent<T>) + 'static),
  2291. window_id: WebviewId,
  2292. windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>,
  2293. ) {
  2294. let (tx, rx) = channel();
  2295. let windows_ref = windows.borrow();
  2296. if let Some(w) = windows_ref.get(&window_id) {
  2297. let label = w.label.clone();
  2298. let window_event_listeners = w.window_event_listeners.clone();
  2299. drop(windows_ref);
  2300. let listeners = window_event_listeners.lock().unwrap();
  2301. let handlers = listeners.values();
  2302. for handler in handlers {
  2303. handler(&WindowEvent::CloseRequested {
  2304. signal_tx: tx.clone(),
  2305. });
  2306. }
  2307. callback(RunEvent::WindowEvent {
  2308. label,
  2309. event: WindowEvent::CloseRequested { signal_tx: tx },
  2310. });
  2311. if let Ok(true) = rx.try_recv() {
  2312. } else {
  2313. on_window_close(window_id, windows);
  2314. }
  2315. }
  2316. }
  2317. fn on_window_close(window_id: WebviewId, windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>) {
  2318. if let Some(window_wrapper) = windows.borrow_mut().get_mut(&window_id) {
  2319. window_wrapper.inner = None;
  2320. }
  2321. }
  2322. pub fn center_window(window: &Window, window_size: WryPhysicalSize<u32>) -> Result<()> {
  2323. if let Some(monitor) = window.current_monitor() {
  2324. let screen_size = monitor.size();
  2325. let monitor_pos = monitor.position();
  2326. let x = (screen_size.width as i32 - window_size.width as i32) / 2;
  2327. let y = (screen_size.height as i32 - window_size.height as i32) / 2;
  2328. window.set_outer_position(WryPhysicalPosition::new(
  2329. monitor_pos.x + x,
  2330. monitor_pos.y + y,
  2331. ));
  2332. Ok(())
  2333. } else {
  2334. Err(Error::FailedToGetMonitor)
  2335. }
  2336. }
  2337. fn create_webview<T: UserEvent, F: Fn(RawWindow) + Send + 'static>(
  2338. window_id: WebviewId,
  2339. event_loop: &EventLoopWindowTarget<Message<T>>,
  2340. web_context_store: &WebContextStore,
  2341. context: Context<T>,
  2342. pending: PendingWindow<T, Wry<T>>,
  2343. before_webview_creation: Option<F>,
  2344. ) -> Result<WindowWrapper> {
  2345. #[allow(unused_mut)]
  2346. let PendingWindow {
  2347. webview_attributes,
  2348. uri_scheme_protocols,
  2349. mut window_builder,
  2350. label,
  2351. ipc_handler,
  2352. url,
  2353. #[cfg(target_os = "android")]
  2354. on_webview_created,
  2355. ..
  2356. } = pending;
  2357. let window_event_listeners = WindowEventListeners::default();
  2358. #[cfg(windows)]
  2359. {
  2360. window_builder.inner = window_builder
  2361. .inner
  2362. .with_drag_and_drop(webview_attributes.file_drop_handler_enabled);
  2363. }
  2364. #[cfg(windows)]
  2365. let window_theme = window_builder.inner.window.preferred_theme;
  2366. #[cfg(windows)]
  2367. let proxy = context.proxy.clone();
  2368. #[cfg(target_os = "macos")]
  2369. {
  2370. if window_builder.tabbing_identifier.is_none()
  2371. || window_builder.inner.window.transparent
  2372. || !window_builder.inner.window.decorations
  2373. {
  2374. window_builder.inner = window_builder.inner.with_automatic_window_tabbing(false);
  2375. }
  2376. }
  2377. let is_window_transparent = window_builder.inner.window.transparent;
  2378. let focused = window_builder.inner.window.focused;
  2379. let window = window_builder.inner.build(event_loop).unwrap();
  2380. context.webview_id_map.insert(window.id(), window_id);
  2381. if window_builder.center {
  2382. let _ = center_window(&window, window.inner_size());
  2383. }
  2384. if let Some(handler) = before_webview_creation {
  2385. let raw = RawWindow {
  2386. #[cfg(windows)]
  2387. hwnd: window.hwnd(),
  2388. #[cfg(any(
  2389. target_os = "linux",
  2390. target_os = "dragonfly",
  2391. target_os = "freebsd",
  2392. target_os = "netbsd",
  2393. target_os = "openbsd"
  2394. ))]
  2395. gtk_window: window.gtk_window(),
  2396. #[cfg(any(
  2397. target_os = "linux",
  2398. target_os = "dragonfly",
  2399. target_os = "freebsd",
  2400. target_os = "netbsd",
  2401. target_os = "openbsd"
  2402. ))]
  2403. default_vbox: window.default_vbox(),
  2404. _marker: &std::marker::PhantomData,
  2405. };
  2406. handler(raw);
  2407. }
  2408. let mut webview_builder = WebViewBuilder::new(window)
  2409. .map_err(|e| Error::CreateWebview(Box::new(e)))?
  2410. .with_focused(focused)
  2411. .with_url(&url)
  2412. .unwrap() // safe to unwrap because we validate the URL beforehand
  2413. .with_transparent(is_window_transparent)
  2414. .with_accept_first_mouse(webview_attributes.accept_first_mouse);
  2415. if webview_attributes.file_drop_handler_enabled {
  2416. webview_builder = webview_builder
  2417. .with_file_drop_handler(create_file_drop_handler(window_event_listeners.clone()));
  2418. }
  2419. if let Some(navigation_handler) = pending.navigation_handler {
  2420. webview_builder = webview_builder.with_navigation_handler(move |url| {
  2421. Url::parse(&url)
  2422. .map(|url| navigation_handler(&url))
  2423. .unwrap_or(true)
  2424. });
  2425. }
  2426. if let Some(user_agent) = webview_attributes.user_agent {
  2427. webview_builder = webview_builder.with_user_agent(&user_agent);
  2428. }
  2429. #[cfg(windows)]
  2430. {
  2431. if let Some(additional_browser_args) = webview_attributes.additional_browser_args {
  2432. webview_builder = webview_builder.with_additional_browser_args(&additional_browser_args);
  2433. }
  2434. if let Some(theme) = window_theme {
  2435. webview_builder = webview_builder.with_theme(match theme {
  2436. WryTheme::Dark => wry::webview::Theme::Dark,
  2437. WryTheme::Light => wry::webview::Theme::Light,
  2438. _ => wry::webview::Theme::Light,
  2439. });
  2440. }
  2441. }
  2442. #[cfg(windows)]
  2443. {
  2444. webview_builder = webview_builder.with_https_scheme(false);
  2445. }
  2446. if let Some(handler) = ipc_handler {
  2447. webview_builder =
  2448. webview_builder.with_ipc_handler(create_ipc_handler(context.clone(), label.clone(), handler));
  2449. }
  2450. for (scheme, protocol) in uri_scheme_protocols {
  2451. webview_builder =
  2452. webview_builder.with_asynchronous_custom_protocol(scheme, move |request, responder| {
  2453. protocol(
  2454. request,
  2455. Box::new(move |response| responder.respond(response)),
  2456. )
  2457. });
  2458. }
  2459. for script in webview_attributes.initialization_scripts {
  2460. webview_builder = webview_builder.with_initialization_script(&script);
  2461. }
  2462. let mut web_context = web_context_store.lock().expect("poisoned WebContext store");
  2463. let is_first_context = web_context.is_empty();
  2464. let automation_enabled = std::env::var("TAURI_WEBVIEW_AUTOMATION").as_deref() == Ok("true");
  2465. let web_context_key = // force a unique WebContext when automation is false;
  2466. // the context must be stored on the HashMap because it must outlive the WebView on macOS
  2467. if automation_enabled {
  2468. webview_attributes.data_directory.clone()
  2469. } else {
  2470. // unique key
  2471. let key = context.next_webcontext_id().to_string().into();
  2472. Some(key)
  2473. };
  2474. let entry = web_context.entry(web_context_key.clone());
  2475. let web_context = match entry {
  2476. Occupied(occupied) => occupied.into_mut(),
  2477. Vacant(vacant) => {
  2478. let mut web_context = WebContext::new(webview_attributes.data_directory);
  2479. web_context.set_allows_automation(if automation_enabled {
  2480. is_first_context
  2481. } else {
  2482. false
  2483. });
  2484. vacant.insert(web_context)
  2485. }
  2486. };
  2487. if webview_attributes.clipboard {
  2488. webview_builder.webview.clipboard = true;
  2489. }
  2490. if webview_attributes.incognito {
  2491. webview_builder.webview.incognito = true;
  2492. }
  2493. #[cfg(any(debug_assertions, feature = "devtools"))]
  2494. {
  2495. webview_builder = webview_builder.with_devtools(true);
  2496. }
  2497. #[cfg(target_os = "android")]
  2498. {
  2499. if let Some(on_webview_created) = on_webview_created {
  2500. webview_builder = webview_builder.on_webview_created(move |ctx| {
  2501. on_webview_created(tauri_runtime::window::CreationContext {
  2502. env: ctx.env,
  2503. activity: ctx.activity,
  2504. webview: ctx.webview,
  2505. })
  2506. });
  2507. }
  2508. }
  2509. let webview = webview_builder
  2510. .with_web_context(web_context)
  2511. .build()
  2512. .map_err(|e| Error::CreateWebview(Box::new(e)))?;
  2513. #[cfg(windows)]
  2514. {
  2515. let controller = webview.controller();
  2516. let proxy_ = proxy.clone();
  2517. let mut token = EventRegistrationToken::default();
  2518. unsafe {
  2519. controller.add_GotFocus(
  2520. &FocusChangedEventHandler::create(Box::new(move |_, _| {
  2521. let _ = proxy.send_event(Message::Webview(
  2522. window_id,
  2523. WebviewMessage::WebviewEvent(WebviewEvent::Focused(true)),
  2524. ));
  2525. Ok(())
  2526. })),
  2527. &mut token,
  2528. )
  2529. }
  2530. .unwrap();
  2531. unsafe {
  2532. controller.add_LostFocus(
  2533. &FocusChangedEventHandler::create(Box::new(move |_, _| {
  2534. let _ = proxy_.send_event(Message::Webview(
  2535. window_id,
  2536. WebviewMessage::WebviewEvent(WebviewEvent::Focused(false)),
  2537. ));
  2538. Ok(())
  2539. })),
  2540. &mut token,
  2541. )
  2542. }
  2543. .unwrap();
  2544. }
  2545. Ok(WindowWrapper {
  2546. label,
  2547. inner: Some(WindowHandle::Webview {
  2548. inner: Rc::new(webview),
  2549. context_store: web_context_store.clone(),
  2550. context_key: if automation_enabled {
  2551. None
  2552. } else {
  2553. web_context_key
  2554. },
  2555. }),
  2556. window_event_listeners,
  2557. })
  2558. }
  2559. /// Create a wry ipc handler from a tauri ipc handler.
  2560. fn create_ipc_handler<T: UserEvent>(
  2561. context: Context<T>,
  2562. label: String,
  2563. handler: WebviewIpcHandler<T, Wry<T>>,
  2564. ) -> Box<IpcHandler> {
  2565. Box::new(move |window, request| {
  2566. let window_id = context.webview_id_map.get(&window.id()).unwrap();
  2567. handler(
  2568. DetachedWindow {
  2569. dispatcher: WryDispatcher {
  2570. window_id,
  2571. context: context.clone(),
  2572. },
  2573. label: label.clone(),
  2574. },
  2575. request,
  2576. );
  2577. })
  2578. }
  2579. /// Create a wry file drop handler.
  2580. fn create_file_drop_handler(window_event_listeners: WindowEventListeners) -> Box<FileDropHandler> {
  2581. Box::new(move |_window, event| {
  2582. let event: FileDropEvent = FileDropEventWrapper(event).into();
  2583. let window_event = WindowEvent::FileDrop(event);
  2584. let listeners_map = window_event_listeners.lock().unwrap();
  2585. let has_listener = !listeners_map.is_empty();
  2586. let handlers = listeners_map.values();
  2587. for listener in handlers {
  2588. listener(&window_event);
  2589. }
  2590. // block the default OS action on file drop if we had a listener
  2591. has_listener
  2592. })
  2593. }