lib.rs 122 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174
  1. // Copyright 2019-2024 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 http::Request;
  12. use raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle};
  13. use tauri_runtime::{
  14. dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
  15. monitor::Monitor,
  16. webview::{DetachedWebview, DownloadEvent, PendingWebview, WebviewIpcHandler},
  17. window::{
  18. CursorIcon, DetachedWindow, DragDropEvent, PendingWindow, RawWindow, WebviewEvent,
  19. WindowBuilder, WindowBuilderBase, WindowEvent, WindowId,
  20. },
  21. DeviceEventFilter, Error, EventLoopProxy, ExitRequestedEventAction, Icon, ProgressBarState,
  22. ProgressBarStatus, Result, RunEvent, Runtime, RuntimeHandle, RuntimeInitArgs, UserAttentionType,
  23. UserEvent, WebviewDispatch, WebviewEventId, WindowDispatch, WindowEventId,
  24. };
  25. #[cfg(target_os = "macos")]
  26. use tao::platform::macos::{EventLoopWindowTargetExtMacOS, WindowBuilderExtMacOS};
  27. #[cfg(target_os = "linux")]
  28. use tao::platform::unix::{WindowBuilderExtUnix, WindowExtUnix};
  29. #[cfg(windows)]
  30. use tao::platform::windows::{WindowBuilderExtWindows, WindowExtWindows};
  31. #[cfg(windows)]
  32. use webview2_com::FocusChangedEventHandler;
  33. #[cfg(windows)]
  34. use windows::Win32::{Foundation::HWND, System::WinRT::EventRegistrationToken};
  35. #[cfg(windows)]
  36. use wry::WebViewBuilderExtWindows;
  37. use tao::{
  38. dpi::{
  39. LogicalPosition as TaoLogicalPosition, LogicalSize as TaoLogicalSize,
  40. PhysicalPosition as TaoPhysicalPosition, PhysicalSize as TaoPhysicalSize,
  41. Position as TaoPosition, Size as TaoSize,
  42. },
  43. event::{Event, StartCause, WindowEvent as TaoWindowEvent},
  44. event_loop::{
  45. ControlFlow, DeviceEventFilter as TaoDeviceEventFilter, EventLoop, EventLoopBuilder,
  46. EventLoopProxy as TaoEventLoopProxy, EventLoopWindowTarget,
  47. },
  48. monitor::MonitorHandle,
  49. window::{
  50. CursorIcon as TaoCursorIcon, Fullscreen, Icon as TaoWindowIcon,
  51. ProgressBarState as TaoProgressBarState, ProgressState as TaoProgressState, Theme as TaoTheme,
  52. UserAttentionType as TaoUserAttentionType,
  53. },
  54. };
  55. #[cfg(target_os = "macos")]
  56. use tauri_utils::TitleBarStyle;
  57. use tauri_utils::{config::WindowConfig, Theme};
  58. use url::Url;
  59. use wry::{
  60. DragDropEvent as WryDragDropEvent, ProxyConfig, ProxyEndpoint, WebContext, WebView,
  61. WebViewBuilder,
  62. };
  63. pub use tao;
  64. pub use tao::window::{Window, WindowBuilder as TaoWindowBuilder, WindowId as TaoWindowId};
  65. pub use wry;
  66. pub use wry::webview_version;
  67. #[cfg(windows)]
  68. use wry::WebViewExtWindows;
  69. #[cfg(target_os = "android")]
  70. use wry::{
  71. prelude::{dispatch, find_class},
  72. WebViewBuilderExtAndroid, WebViewExtAndroid,
  73. };
  74. #[cfg(not(any(
  75. target_os = "windows",
  76. target_os = "macos",
  77. target_os = "ios",
  78. target_os = "android"
  79. )))]
  80. use wry::{WebViewBuilderExtUnix, WebViewExtUnix};
  81. #[cfg(target_os = "macos")]
  82. pub use tao::platform::macos::{
  83. ActivationPolicy as TaoActivationPolicy, EventLoopExtMacOS, WindowExtMacOS,
  84. };
  85. #[cfg(target_os = "macos")]
  86. use tauri_runtime::ActivationPolicy;
  87. use std::{
  88. cell::RefCell,
  89. collections::{
  90. hash_map::Entry::{Occupied, Vacant},
  91. BTreeMap, HashMap,
  92. },
  93. fmt,
  94. ops::Deref,
  95. path::PathBuf,
  96. rc::Rc,
  97. sync::{
  98. atomic::{AtomicBool, AtomicU32, Ordering},
  99. mpsc::{channel, Sender},
  100. Arc, Mutex, Weak,
  101. },
  102. thread::{current as current_thread, ThreadId},
  103. };
  104. pub type WebviewId = u32;
  105. type IpcHandler = dyn Fn(Request<String>) + 'static;
  106. #[cfg(any(
  107. windows,
  108. target_os = "linux",
  109. target_os = "dragonfly",
  110. target_os = "freebsd",
  111. target_os = "netbsd",
  112. target_os = "openbsd"
  113. ))]
  114. mod undecorated_resizing;
  115. mod webview;
  116. pub use webview::Webview;
  117. pub type WebContextStore = Arc<Mutex<HashMap<Option<PathBuf>, WebContext>>>;
  118. // window
  119. pub type WindowEventHandler = Box<dyn Fn(&WindowEvent) + Send>;
  120. pub type WindowEventListeners = Arc<Mutex<HashMap<WindowEventId, WindowEventHandler>>>;
  121. pub type WebviewEventHandler = Box<dyn Fn(&WebviewEvent) + Send>;
  122. pub type WebviewEventListeners = Arc<Mutex<HashMap<WebviewEventId, WebviewEventHandler>>>;
  123. #[derive(Debug, Clone, Default)]
  124. pub struct WindowIdStore(Arc<Mutex<HashMap<TaoWindowId, WindowId>>>);
  125. impl WindowIdStore {
  126. pub fn insert(&self, w: TaoWindowId, id: WindowId) {
  127. self.0.lock().unwrap().insert(w, id);
  128. }
  129. fn get(&self, w: &TaoWindowId) -> Option<WindowId> {
  130. self.0.lock().unwrap().get(w).copied()
  131. }
  132. }
  133. #[macro_export]
  134. macro_rules! getter {
  135. ($self: ident, $rx: expr, $message: expr) => {{
  136. $crate::send_user_message(&$self.context, $message)?;
  137. $rx
  138. .recv()
  139. .map_err(|_| $crate::Error::FailedToReceiveMessage)
  140. }};
  141. }
  142. macro_rules! window_getter {
  143. ($self: ident, $message: expr) => {{
  144. let (tx, rx) = channel();
  145. getter!($self, rx, Message::Window($self.window_id, $message(tx)))
  146. }};
  147. }
  148. macro_rules! webview_getter {
  149. ($self: ident, $message: expr) => {{
  150. let (tx, rx) = channel();
  151. getter!(
  152. $self,
  153. rx,
  154. Message::Webview(
  155. *$self.window_id.lock().unwrap(),
  156. $self.webview_id,
  157. $message(tx)
  158. )
  159. )
  160. }};
  161. }
  162. pub(crate) fn send_user_message<T: UserEvent>(
  163. context: &Context<T>,
  164. message: Message<T>,
  165. ) -> Result<()> {
  166. if current_thread().id() == context.main_thread_id {
  167. handle_user_message(
  168. &context.main_thread.window_target,
  169. message,
  170. UserMessageContext {
  171. window_id_map: context.window_id_map.clone(),
  172. windows: context.main_thread.windows.clone(),
  173. },
  174. );
  175. Ok(())
  176. } else {
  177. context
  178. .proxy
  179. .send_event(message)
  180. .map_err(|_| Error::FailedToSendMessage)
  181. }
  182. }
  183. #[derive(Clone)]
  184. pub struct Context<T: UserEvent> {
  185. pub window_id_map: WindowIdStore,
  186. main_thread_id: ThreadId,
  187. pub proxy: TaoEventLoopProxy<Message<T>>,
  188. main_thread: DispatcherMainThreadContext<T>,
  189. plugins: Arc<Mutex<Vec<Box<dyn Plugin<T> + Send>>>>,
  190. next_window_id: Arc<AtomicU32>,
  191. next_webview_id: Arc<AtomicU32>,
  192. next_window_event_id: Arc<AtomicU32>,
  193. next_webview_event_id: Arc<AtomicU32>,
  194. next_webcontext_id: Arc<AtomicU32>,
  195. }
  196. impl<T: UserEvent> Context<T> {
  197. pub fn run_threaded<R, F>(&self, f: F) -> R
  198. where
  199. F: FnOnce(Option<&DispatcherMainThreadContext<T>>) -> R,
  200. {
  201. f(if current_thread().id() == self.main_thread_id {
  202. Some(&self.main_thread)
  203. } else {
  204. None
  205. })
  206. }
  207. fn next_window_id(&self) -> WindowId {
  208. self.next_window_id.fetch_add(1, Ordering::Relaxed).into()
  209. }
  210. fn next_webview_id(&self) -> WebviewId {
  211. self.next_webview_id.fetch_add(1, Ordering::Relaxed)
  212. }
  213. fn next_window_event_id(&self) -> u32 {
  214. self.next_window_event_id.fetch_add(1, Ordering::Relaxed)
  215. }
  216. fn next_webview_event_id(&self) -> u32 {
  217. self.next_webview_event_id.fetch_add(1, Ordering::Relaxed)
  218. }
  219. fn next_webcontext_id(&self) -> u32 {
  220. self.next_webcontext_id.fetch_add(1, Ordering::Relaxed)
  221. }
  222. }
  223. impl<T: UserEvent> Context<T> {
  224. fn create_window<F: Fn(RawWindow) + Send + 'static>(
  225. &self,
  226. pending: PendingWindow<T, Wry<T>>,
  227. after_window_creation: Option<F>,
  228. ) -> Result<DetachedWindow<T, Wry<T>>> {
  229. let label = pending.label.clone();
  230. let context = self.clone();
  231. let window_id = self.next_window_id();
  232. let webview_id = pending.webview.as_ref().map(|_| context.next_webview_id());
  233. send_user_message(
  234. self,
  235. Message::CreateWindow(
  236. window_id,
  237. Box::new(move |event_loop| {
  238. create_window(
  239. window_id,
  240. webview_id.unwrap_or_default(),
  241. event_loop,
  242. &context,
  243. pending,
  244. after_window_creation,
  245. )
  246. }),
  247. ),
  248. )?;
  249. let dispatcher = WryWindowDispatcher {
  250. window_id,
  251. context: self.clone(),
  252. };
  253. let detached_webview = webview_id.map(|id| DetachedWebview {
  254. label: label.clone(),
  255. dispatcher: WryWebviewDispatcher {
  256. window_id: Arc::new(Mutex::new(window_id)),
  257. webview_id: id,
  258. context: self.clone(),
  259. },
  260. });
  261. Ok(DetachedWindow {
  262. id: window_id,
  263. label,
  264. dispatcher,
  265. webview: detached_webview,
  266. })
  267. }
  268. fn create_webview(
  269. &self,
  270. window_id: WindowId,
  271. pending: PendingWebview<T, Wry<T>>,
  272. ) -> Result<DetachedWebview<T, Wry<T>>> {
  273. let label = pending.label.clone();
  274. let context = self.clone();
  275. let webview_id = self.next_webview_id();
  276. let window_id_wrapper = Arc::new(Mutex::new(window_id));
  277. let window_id_wrapper_ = window_id_wrapper.clone();
  278. send_user_message(
  279. self,
  280. Message::CreateWebview(
  281. window_id,
  282. Box::new(move |window| {
  283. create_webview(
  284. WebviewKind::WindowChild,
  285. window,
  286. window_id_wrapper_,
  287. webview_id,
  288. &context,
  289. pending,
  290. )
  291. }),
  292. ),
  293. )?;
  294. let dispatcher = WryWebviewDispatcher {
  295. window_id: window_id_wrapper,
  296. webview_id,
  297. context: self.clone(),
  298. };
  299. Ok(DetachedWebview { label, dispatcher })
  300. }
  301. }
  302. #[cfg(feature = "tracing")]
  303. #[derive(Debug, Clone, Default)]
  304. pub struct ActiveTraceSpanStore(Rc<RefCell<Vec<ActiveTracingSpan>>>);
  305. #[cfg(feature = "tracing")]
  306. impl ActiveTraceSpanStore {
  307. pub fn remove_window_draw(&self, window_id: TaoWindowId) {
  308. let mut store = self.0.borrow_mut();
  309. if let Some(index) = store
  310. .iter()
  311. .position(|t| matches!(t, ActiveTracingSpan::WindowDraw { id, span: _ } if id == &window_id))
  312. {
  313. store.remove(index);
  314. }
  315. }
  316. }
  317. #[cfg(feature = "tracing")]
  318. #[derive(Debug)]
  319. pub enum ActiveTracingSpan {
  320. WindowDraw {
  321. id: TaoWindowId,
  322. span: tracing::span::EnteredSpan,
  323. },
  324. }
  325. #[derive(Debug)]
  326. pub struct WindowsStore(RefCell<BTreeMap<WindowId, WindowWrapper>>);
  327. // SAFETY: we ensure this type is only used on the main thread.
  328. #[allow(clippy::non_send_fields_in_send_ty)]
  329. unsafe impl Send for WindowsStore {}
  330. // SAFETY: we ensure this type is only used on the main thread.
  331. #[allow(clippy::non_send_fields_in_send_ty)]
  332. unsafe impl Sync for WindowsStore {}
  333. #[derive(Debug, Clone)]
  334. pub struct DispatcherMainThreadContext<T: UserEvent> {
  335. pub window_target: EventLoopWindowTarget<Message<T>>,
  336. pub web_context: WebContextStore,
  337. // changing this to an Rc will cause frequent app crashes.
  338. pub windows: Arc<WindowsStore>,
  339. #[cfg(feature = "tracing")]
  340. pub active_tracing_spans: ActiveTraceSpanStore,
  341. }
  342. // SAFETY: we ensure this type is only used on the main thread.
  343. #[allow(clippy::non_send_fields_in_send_ty)]
  344. unsafe impl<T: UserEvent> Send for DispatcherMainThreadContext<T> {}
  345. // SAFETY: we ensure this type is only used on the main thread.
  346. #[allow(clippy::non_send_fields_in_send_ty)]
  347. unsafe impl<T: UserEvent> Sync for DispatcherMainThreadContext<T> {}
  348. impl<T: UserEvent> fmt::Debug for Context<T> {
  349. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  350. f.debug_struct("Context")
  351. .field("main_thread_id", &self.main_thread_id)
  352. .field("proxy", &self.proxy)
  353. .field("main_thread", &self.main_thread)
  354. .finish()
  355. }
  356. }
  357. pub struct DeviceEventFilterWrapper(pub TaoDeviceEventFilter);
  358. impl From<DeviceEventFilter> for DeviceEventFilterWrapper {
  359. fn from(item: DeviceEventFilter) -> Self {
  360. match item {
  361. DeviceEventFilter::Always => Self(TaoDeviceEventFilter::Always),
  362. DeviceEventFilter::Never => Self(TaoDeviceEventFilter::Never),
  363. DeviceEventFilter::Unfocused => Self(TaoDeviceEventFilter::Unfocused),
  364. }
  365. }
  366. }
  367. pub struct RectWrapper(pub wry::Rect);
  368. impl From<tauri_runtime::Rect> for RectWrapper {
  369. fn from(value: tauri_runtime::Rect) -> Self {
  370. RectWrapper(wry::Rect {
  371. position: value.position,
  372. size: value.size,
  373. })
  374. }
  375. }
  376. /// Wrapper around a [`tao::window::Icon`] that can be created from an [`Icon`].
  377. pub struct TaoIcon(pub TaoWindowIcon);
  378. impl TryFrom<Icon<'_>> for TaoIcon {
  379. type Error = Error;
  380. fn try_from(icon: Icon<'_>) -> std::result::Result<Self, Self::Error> {
  381. TaoWindowIcon::from_rgba(icon.rgba.to_vec(), icon.width, icon.height)
  382. .map(Self)
  383. .map_err(|e| Error::InvalidIcon(Box::new(e)))
  384. }
  385. }
  386. pub struct WindowEventWrapper(pub Option<WindowEvent>);
  387. impl WindowEventWrapper {
  388. fn parse(window: &WindowWrapper, event: &TaoWindowEvent<'_>) -> Self {
  389. match event {
  390. // resized event from tao doesn't include a reliable size on macOS
  391. // because wry replaces the NSView
  392. TaoWindowEvent::Resized(_) => {
  393. if let Some(w) = &window.inner {
  394. let size = inner_size(
  395. w,
  396. &window.webviews,
  397. window.has_children.load(Ordering::Relaxed),
  398. );
  399. Self(Some(WindowEvent::Resized(PhysicalSizeWrapper(size).into())))
  400. } else {
  401. Self(None)
  402. }
  403. }
  404. e => e.into(),
  405. }
  406. }
  407. }
  408. pub fn map_theme(theme: &TaoTheme) -> Theme {
  409. match theme {
  410. TaoTheme::Light => Theme::Light,
  411. TaoTheme::Dark => Theme::Dark,
  412. _ => Theme::Light,
  413. }
  414. }
  415. #[cfg(target_os = "macos")]
  416. fn tao_activation_policy(activation_policy: ActivationPolicy) -> TaoActivationPolicy {
  417. match activation_policy {
  418. ActivationPolicy::Regular => TaoActivationPolicy::Regular,
  419. ActivationPolicy::Accessory => TaoActivationPolicy::Accessory,
  420. ActivationPolicy::Prohibited => TaoActivationPolicy::Prohibited,
  421. _ => unimplemented!(),
  422. }
  423. }
  424. impl<'a> From<&TaoWindowEvent<'a>> for WindowEventWrapper {
  425. fn from(event: &TaoWindowEvent<'a>) -> Self {
  426. let event = match event {
  427. TaoWindowEvent::Resized(size) => WindowEvent::Resized(PhysicalSizeWrapper(*size).into()),
  428. TaoWindowEvent::Moved(position) => {
  429. WindowEvent::Moved(PhysicalPositionWrapper(*position).into())
  430. }
  431. TaoWindowEvent::Destroyed => WindowEvent::Destroyed,
  432. TaoWindowEvent::ScaleFactorChanged {
  433. scale_factor,
  434. new_inner_size,
  435. } => WindowEvent::ScaleFactorChanged {
  436. scale_factor: *scale_factor,
  437. new_inner_size: PhysicalSizeWrapper(**new_inner_size).into(),
  438. },
  439. #[cfg(any(target_os = "linux", target_os = "macos"))]
  440. TaoWindowEvent::Focused(focused) => WindowEvent::Focused(*focused),
  441. TaoWindowEvent::ThemeChanged(theme) => WindowEvent::ThemeChanged(map_theme(theme)),
  442. _ => return Self(None),
  443. };
  444. Self(Some(event))
  445. }
  446. }
  447. pub struct MonitorHandleWrapper(pub MonitorHandle);
  448. impl From<MonitorHandleWrapper> for Monitor {
  449. fn from(monitor: MonitorHandleWrapper) -> Monitor {
  450. Self {
  451. name: monitor.0.name(),
  452. position: PhysicalPositionWrapper(monitor.0.position()).into(),
  453. size: PhysicalSizeWrapper(monitor.0.size()).into(),
  454. scale_factor: monitor.0.scale_factor(),
  455. }
  456. }
  457. }
  458. pub struct PhysicalPositionWrapper<T>(pub TaoPhysicalPosition<T>);
  459. impl<T> From<PhysicalPositionWrapper<T>> for PhysicalPosition<T> {
  460. fn from(position: PhysicalPositionWrapper<T>) -> Self {
  461. Self {
  462. x: position.0.x,
  463. y: position.0.y,
  464. }
  465. }
  466. }
  467. impl<T> From<PhysicalPosition<T>> for PhysicalPositionWrapper<T> {
  468. fn from(position: PhysicalPosition<T>) -> Self {
  469. Self(TaoPhysicalPosition {
  470. x: position.x,
  471. y: position.y,
  472. })
  473. }
  474. }
  475. struct LogicalPositionWrapper<T>(TaoLogicalPosition<T>);
  476. impl<T> From<LogicalPosition<T>> for LogicalPositionWrapper<T> {
  477. fn from(position: LogicalPosition<T>) -> Self {
  478. Self(TaoLogicalPosition {
  479. x: position.x,
  480. y: position.y,
  481. })
  482. }
  483. }
  484. pub struct PhysicalSizeWrapper<T>(pub TaoPhysicalSize<T>);
  485. impl<T> From<PhysicalSizeWrapper<T>> for PhysicalSize<T> {
  486. fn from(size: PhysicalSizeWrapper<T>) -> Self {
  487. Self {
  488. width: size.0.width,
  489. height: size.0.height,
  490. }
  491. }
  492. }
  493. impl<T> From<PhysicalSize<T>> for PhysicalSizeWrapper<T> {
  494. fn from(size: PhysicalSize<T>) -> Self {
  495. Self(TaoPhysicalSize {
  496. width: size.width,
  497. height: size.height,
  498. })
  499. }
  500. }
  501. struct LogicalSizeWrapper<T>(TaoLogicalSize<T>);
  502. impl<T> From<LogicalSize<T>> for LogicalSizeWrapper<T> {
  503. fn from(size: LogicalSize<T>) -> Self {
  504. Self(TaoLogicalSize {
  505. width: size.width,
  506. height: size.height,
  507. })
  508. }
  509. }
  510. pub struct SizeWrapper(pub TaoSize);
  511. impl From<Size> for SizeWrapper {
  512. fn from(size: Size) -> Self {
  513. match size {
  514. Size::Logical(s) => Self(TaoSize::Logical(LogicalSizeWrapper::from(s).0)),
  515. Size::Physical(s) => Self(TaoSize::Physical(PhysicalSizeWrapper::from(s).0)),
  516. }
  517. }
  518. }
  519. pub struct PositionWrapper(pub TaoPosition);
  520. impl From<Position> for PositionWrapper {
  521. fn from(position: Position) -> Self {
  522. match position {
  523. Position::Logical(s) => Self(TaoPosition::Logical(LogicalPositionWrapper::from(s).0)),
  524. Position::Physical(s) => Self(TaoPosition::Physical(PhysicalPositionWrapper::from(s).0)),
  525. }
  526. }
  527. }
  528. #[derive(Debug, Clone)]
  529. pub struct UserAttentionTypeWrapper(pub TaoUserAttentionType);
  530. impl From<UserAttentionType> for UserAttentionTypeWrapper {
  531. fn from(request_type: UserAttentionType) -> Self {
  532. let o = match request_type {
  533. UserAttentionType::Critical => TaoUserAttentionType::Critical,
  534. UserAttentionType::Informational => TaoUserAttentionType::Informational,
  535. };
  536. Self(o)
  537. }
  538. }
  539. #[derive(Debug)]
  540. pub struct CursorIconWrapper(pub TaoCursorIcon);
  541. impl From<CursorIcon> for CursorIconWrapper {
  542. fn from(icon: CursorIcon) -> Self {
  543. use CursorIcon::*;
  544. let i = match icon {
  545. Default => TaoCursorIcon::Default,
  546. Crosshair => TaoCursorIcon::Crosshair,
  547. Hand => TaoCursorIcon::Hand,
  548. Arrow => TaoCursorIcon::Arrow,
  549. Move => TaoCursorIcon::Move,
  550. Text => TaoCursorIcon::Text,
  551. Wait => TaoCursorIcon::Wait,
  552. Help => TaoCursorIcon::Help,
  553. Progress => TaoCursorIcon::Progress,
  554. NotAllowed => TaoCursorIcon::NotAllowed,
  555. ContextMenu => TaoCursorIcon::ContextMenu,
  556. Cell => TaoCursorIcon::Cell,
  557. VerticalText => TaoCursorIcon::VerticalText,
  558. Alias => TaoCursorIcon::Alias,
  559. Copy => TaoCursorIcon::Copy,
  560. NoDrop => TaoCursorIcon::NoDrop,
  561. Grab => TaoCursorIcon::Grab,
  562. Grabbing => TaoCursorIcon::Grabbing,
  563. AllScroll => TaoCursorIcon::AllScroll,
  564. ZoomIn => TaoCursorIcon::ZoomIn,
  565. ZoomOut => TaoCursorIcon::ZoomOut,
  566. EResize => TaoCursorIcon::EResize,
  567. NResize => TaoCursorIcon::NResize,
  568. NeResize => TaoCursorIcon::NeResize,
  569. NwResize => TaoCursorIcon::NwResize,
  570. SResize => TaoCursorIcon::SResize,
  571. SeResize => TaoCursorIcon::SeResize,
  572. SwResize => TaoCursorIcon::SwResize,
  573. WResize => TaoCursorIcon::WResize,
  574. EwResize => TaoCursorIcon::EwResize,
  575. NsResize => TaoCursorIcon::NsResize,
  576. NeswResize => TaoCursorIcon::NeswResize,
  577. NwseResize => TaoCursorIcon::NwseResize,
  578. ColResize => TaoCursorIcon::ColResize,
  579. RowResize => TaoCursorIcon::RowResize,
  580. _ => TaoCursorIcon::Default,
  581. };
  582. Self(i)
  583. }
  584. }
  585. pub struct ProgressStateWrapper(pub TaoProgressState);
  586. impl From<ProgressBarStatus> for ProgressStateWrapper {
  587. fn from(status: ProgressBarStatus) -> Self {
  588. let state = match status {
  589. ProgressBarStatus::None => TaoProgressState::None,
  590. ProgressBarStatus::Normal => TaoProgressState::Normal,
  591. ProgressBarStatus::Indeterminate => TaoProgressState::Indeterminate,
  592. ProgressBarStatus::Paused => TaoProgressState::Paused,
  593. ProgressBarStatus::Error => TaoProgressState::Error,
  594. };
  595. Self(state)
  596. }
  597. }
  598. pub struct ProgressBarStateWrapper(pub TaoProgressBarState);
  599. impl From<ProgressBarState> for ProgressBarStateWrapper {
  600. fn from(progress_state: ProgressBarState) -> Self {
  601. Self(TaoProgressBarState {
  602. progress: progress_state.progress,
  603. state: progress_state
  604. .status
  605. .map(|state| ProgressStateWrapper::from(state).0),
  606. desktop_filename: progress_state.desktop_filename,
  607. })
  608. }
  609. }
  610. #[derive(Clone, Default)]
  611. pub struct WindowBuilderWrapper {
  612. inner: TaoWindowBuilder,
  613. center: bool,
  614. #[cfg(target_os = "macos")]
  615. tabbing_identifier: Option<String>,
  616. }
  617. impl std::fmt::Debug for WindowBuilderWrapper {
  618. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  619. let mut s = f.debug_struct("WindowBuilderWrapper");
  620. s.field("inner", &self.inner).field("center", &self.center);
  621. #[cfg(target_os = "macos")]
  622. {
  623. s.field("tabbing_identifier", &self.tabbing_identifier);
  624. }
  625. s.finish()
  626. }
  627. }
  628. // SAFETY: this type is `Send` since `menu_items` are read only here
  629. #[allow(clippy::non_send_fields_in_send_ty)]
  630. unsafe impl Send for WindowBuilderWrapper {}
  631. impl WindowBuilderBase for WindowBuilderWrapper {}
  632. impl WindowBuilder for WindowBuilderWrapper {
  633. fn new() -> Self {
  634. Self::default().focused(true)
  635. }
  636. fn with_config(config: &WindowConfig) -> Self {
  637. let mut window = WindowBuilderWrapper::new();
  638. #[cfg(target_os = "macos")]
  639. {
  640. window = window
  641. .hidden_title(config.hidden_title)
  642. .title_bar_style(config.title_bar_style);
  643. if let Some(identifier) = &config.tabbing_identifier {
  644. window = window.tabbing_identifier(identifier);
  645. }
  646. }
  647. #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
  648. {
  649. window = window.transparent(config.transparent);
  650. }
  651. #[cfg(all(
  652. target_os = "macos",
  653. not(feature = "macos-private-api"),
  654. debug_assertions
  655. ))]
  656. if config.transparent {
  657. eprintln!(
  658. "The window is set to be transparent but the `macos-private-api` is not enabled.
  659. This can be enabled via the `tauri.macOSPrivateApi` configuration property <https://tauri.app/docs/api/config#tauri.macOSPrivateApi>
  660. ");
  661. }
  662. #[cfg(target_os = "linux")]
  663. {
  664. // Mouse event is disabled on Linux since sudden event bursts could block event loop.
  665. window.inner = window.inner.with_cursor_moved_event(false);
  666. }
  667. #[cfg(desktop)]
  668. {
  669. window = window
  670. .title(config.title.to_string())
  671. .inner_size(config.width, config.height)
  672. .visible(config.visible)
  673. .resizable(config.resizable)
  674. .fullscreen(config.fullscreen)
  675. .decorations(config.decorations)
  676. .maximized(config.maximized)
  677. .always_on_bottom(config.always_on_bottom)
  678. .always_on_top(config.always_on_top)
  679. .visible_on_all_workspaces(config.visible_on_all_workspaces)
  680. .content_protected(config.content_protected)
  681. .skip_taskbar(config.skip_taskbar)
  682. .theme(config.theme)
  683. .closable(config.closable)
  684. .maximizable(config.maximizable)
  685. .minimizable(config.minimizable)
  686. .shadow(config.shadow);
  687. if let (Some(min_width), Some(min_height)) = (config.min_width, config.min_height) {
  688. window = window.min_inner_size(min_width, min_height);
  689. }
  690. if let (Some(max_width), Some(max_height)) = (config.max_width, config.max_height) {
  691. window = window.max_inner_size(max_width, max_height);
  692. }
  693. if let (Some(x), Some(y)) = (config.x, config.y) {
  694. window = window.position(x, y);
  695. }
  696. if config.center {
  697. window = window.center();
  698. }
  699. }
  700. window
  701. }
  702. fn center(mut self) -> Self {
  703. self.center = true;
  704. self
  705. }
  706. fn position(mut self, x: f64, y: f64) -> Self {
  707. self.inner = self.inner.with_position(TaoLogicalPosition::new(x, y));
  708. self
  709. }
  710. fn inner_size(mut self, width: f64, height: f64) -> Self {
  711. self.inner = self
  712. .inner
  713. .with_inner_size(TaoLogicalSize::new(width, height));
  714. self
  715. }
  716. fn min_inner_size(mut self, min_width: f64, min_height: f64) -> Self {
  717. self.inner = self
  718. .inner
  719. .with_min_inner_size(TaoLogicalSize::new(min_width, min_height));
  720. self
  721. }
  722. fn max_inner_size(mut self, max_width: f64, max_height: f64) -> Self {
  723. self.inner = self
  724. .inner
  725. .with_max_inner_size(TaoLogicalSize::new(max_width, max_height));
  726. self
  727. }
  728. fn resizable(mut self, resizable: bool) -> Self {
  729. self.inner = self.inner.with_resizable(resizable);
  730. self
  731. }
  732. fn maximizable(mut self, maximizable: bool) -> Self {
  733. self.inner = self.inner.with_maximizable(maximizable);
  734. self
  735. }
  736. fn minimizable(mut self, minimizable: bool) -> Self {
  737. self.inner = self.inner.with_minimizable(minimizable);
  738. self
  739. }
  740. fn closable(mut self, closable: bool) -> Self {
  741. self.inner = self.inner.with_closable(closable);
  742. self
  743. }
  744. fn title<S: Into<String>>(mut self, title: S) -> Self {
  745. self.inner = self.inner.with_title(title.into());
  746. self
  747. }
  748. fn fullscreen(mut self, fullscreen: bool) -> Self {
  749. self.inner = if fullscreen {
  750. self
  751. .inner
  752. .with_fullscreen(Some(Fullscreen::Borderless(None)))
  753. } else {
  754. self.inner.with_fullscreen(None)
  755. };
  756. self
  757. }
  758. fn focused(mut self, focused: bool) -> Self {
  759. self.inner = self.inner.with_focused(focused);
  760. self
  761. }
  762. fn maximized(mut self, maximized: bool) -> Self {
  763. self.inner = self.inner.with_maximized(maximized);
  764. self
  765. }
  766. fn visible(mut self, visible: bool) -> Self {
  767. self.inner = self.inner.with_visible(visible);
  768. self
  769. }
  770. #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
  771. fn transparent(mut self, transparent: bool) -> Self {
  772. self.inner = self.inner.with_transparent(transparent);
  773. self
  774. }
  775. fn decorations(mut self, decorations: bool) -> Self {
  776. self.inner = self.inner.with_decorations(decorations);
  777. self
  778. }
  779. fn always_on_bottom(mut self, always_on_bottom: bool) -> Self {
  780. self.inner = self.inner.with_always_on_bottom(always_on_bottom);
  781. self
  782. }
  783. fn always_on_top(mut self, always_on_top: bool) -> Self {
  784. self.inner = self.inner.with_always_on_top(always_on_top);
  785. self
  786. }
  787. fn visible_on_all_workspaces(mut self, visible_on_all_workspaces: bool) -> Self {
  788. self.inner = self
  789. .inner
  790. .with_visible_on_all_workspaces(visible_on_all_workspaces);
  791. self
  792. }
  793. fn content_protected(mut self, protected: bool) -> Self {
  794. self.inner = self.inner.with_content_protection(protected);
  795. self
  796. }
  797. fn shadow(#[allow(unused_mut)] mut self, _enable: bool) -> Self {
  798. #[cfg(windows)]
  799. {
  800. self.inner = self.inner.with_undecorated_shadow(_enable);
  801. }
  802. #[cfg(target_os = "macos")]
  803. {
  804. self.inner = self.inner.with_has_shadow(_enable);
  805. }
  806. self
  807. }
  808. #[cfg(windows)]
  809. fn owner(mut self, owner: HWND) -> Self {
  810. self.inner = self.inner.with_owner_window(owner.0);
  811. self
  812. }
  813. #[cfg(windows)]
  814. fn parent(mut self, parent: HWND) -> Self {
  815. self.inner = self.inner.with_parent_window(parent.0);
  816. self
  817. }
  818. #[cfg(target_os = "macos")]
  819. fn parent(mut self, parent: *mut std::ffi::c_void) -> Self {
  820. self.inner = self.inner.with_parent_window(parent);
  821. self
  822. }
  823. #[cfg(any(
  824. target_os = "linux",
  825. target_os = "dragonfly",
  826. target_os = "freebsd",
  827. target_os = "netbsd",
  828. target_os = "openbsd"
  829. ))]
  830. fn transient_for(mut self, parent: &impl gtk::glib::IsA<gtk::Window>) -> Self {
  831. self.inner = self.inner.with_transient_for(parent);
  832. self
  833. }
  834. #[cfg(windows)]
  835. fn drag_and_drop(mut self, enabled: bool) -> Self {
  836. self.inner = self.inner.with_drag_and_drop(enabled);
  837. self
  838. }
  839. #[cfg(target_os = "macos")]
  840. fn title_bar_style(mut self, style: TitleBarStyle) -> Self {
  841. match style {
  842. TitleBarStyle::Visible => {
  843. self.inner = self.inner.with_titlebar_transparent(false);
  844. // Fixes rendering issue when resizing window with devtools open (https://github.com/tauri-apps/tauri/issues/3914)
  845. self.inner = self.inner.with_fullsize_content_view(true);
  846. }
  847. TitleBarStyle::Transparent => {
  848. self.inner = self.inner.with_titlebar_transparent(true);
  849. self.inner = self.inner.with_fullsize_content_view(false);
  850. }
  851. TitleBarStyle::Overlay => {
  852. self.inner = self.inner.with_titlebar_transparent(true);
  853. self.inner = self.inner.with_fullsize_content_view(true);
  854. }
  855. }
  856. self
  857. }
  858. #[cfg(target_os = "macos")]
  859. fn hidden_title(mut self, hidden: bool) -> Self {
  860. self.inner = self.inner.with_title_hidden(hidden);
  861. self
  862. }
  863. #[cfg(target_os = "macos")]
  864. fn tabbing_identifier(mut self, identifier: &str) -> Self {
  865. self.inner = self.inner.with_tabbing_identifier(identifier);
  866. self.tabbing_identifier.replace(identifier.into());
  867. self
  868. }
  869. fn icon(mut self, icon: Icon) -> Result<Self> {
  870. self.inner = self
  871. .inner
  872. .with_window_icon(Some(TaoIcon::try_from(icon)?.0));
  873. Ok(self)
  874. }
  875. #[cfg(any(windows, target_os = "linux"))]
  876. fn skip_taskbar(mut self, skip: bool) -> Self {
  877. self.inner = self.inner.with_skip_taskbar(skip);
  878. self
  879. }
  880. #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))]
  881. fn skip_taskbar(self, _skip: bool) -> Self {
  882. self
  883. }
  884. #[allow(unused_variables, unused_mut)]
  885. fn theme(mut self, theme: Option<Theme>) -> Self {
  886. self.inner = self.inner.with_theme(if let Some(t) = theme {
  887. match t {
  888. Theme::Dark => Some(TaoTheme::Dark),
  889. _ => Some(TaoTheme::Light),
  890. }
  891. } else {
  892. None
  893. });
  894. self
  895. }
  896. fn has_icon(&self) -> bool {
  897. self.inner.window.window_icon.is_some()
  898. }
  899. }
  900. #[cfg(any(
  901. target_os = "linux",
  902. target_os = "dragonfly",
  903. target_os = "freebsd",
  904. target_os = "netbsd",
  905. target_os = "openbsd"
  906. ))]
  907. pub struct GtkWindow(pub gtk::ApplicationWindow);
  908. #[cfg(any(
  909. target_os = "linux",
  910. target_os = "dragonfly",
  911. target_os = "freebsd",
  912. target_os = "netbsd",
  913. target_os = "openbsd"
  914. ))]
  915. #[allow(clippy::non_send_fields_in_send_ty)]
  916. unsafe impl Send for GtkWindow {}
  917. #[cfg(any(
  918. target_os = "linux",
  919. target_os = "dragonfly",
  920. target_os = "freebsd",
  921. target_os = "netbsd",
  922. target_os = "openbsd"
  923. ))]
  924. pub struct GtkBox(pub gtk::Box);
  925. #[cfg(any(
  926. target_os = "linux",
  927. target_os = "dragonfly",
  928. target_os = "freebsd",
  929. target_os = "netbsd",
  930. target_os = "openbsd"
  931. ))]
  932. #[allow(clippy::non_send_fields_in_send_ty)]
  933. unsafe impl Send for GtkBox {}
  934. pub struct SendRawWindowHandle(pub raw_window_handle::RawWindowHandle);
  935. unsafe impl Send for SendRawWindowHandle {}
  936. #[cfg(target_os = "macos")]
  937. #[derive(Debug, Clone)]
  938. pub enum ApplicationMessage {
  939. Show,
  940. Hide,
  941. }
  942. pub enum WindowMessage {
  943. AddEventListener(WindowEventId, Box<dyn Fn(&WindowEvent) + Send>),
  944. // Getters
  945. ScaleFactor(Sender<f64>),
  946. InnerPosition(Sender<Result<PhysicalPosition<i32>>>),
  947. OuterPosition(Sender<Result<PhysicalPosition<i32>>>),
  948. InnerSize(Sender<PhysicalSize<u32>>),
  949. OuterSize(Sender<PhysicalSize<u32>>),
  950. IsFullscreen(Sender<bool>),
  951. IsMinimized(Sender<bool>),
  952. IsMaximized(Sender<bool>),
  953. IsFocused(Sender<bool>),
  954. IsDecorated(Sender<bool>),
  955. IsResizable(Sender<bool>),
  956. IsMaximizable(Sender<bool>),
  957. IsMinimizable(Sender<bool>),
  958. IsClosable(Sender<bool>),
  959. IsVisible(Sender<bool>),
  960. Title(Sender<String>),
  961. CurrentMonitor(Sender<Option<MonitorHandle>>),
  962. PrimaryMonitor(Sender<Option<MonitorHandle>>),
  963. AvailableMonitors(Sender<Vec<MonitorHandle>>),
  964. #[cfg(any(
  965. target_os = "linux",
  966. target_os = "dragonfly",
  967. target_os = "freebsd",
  968. target_os = "netbsd",
  969. target_os = "openbsd"
  970. ))]
  971. GtkWindow(Sender<GtkWindow>),
  972. #[cfg(any(
  973. target_os = "linux",
  974. target_os = "dragonfly",
  975. target_os = "freebsd",
  976. target_os = "netbsd",
  977. target_os = "openbsd"
  978. ))]
  979. GtkBox(Sender<GtkBox>),
  980. RawWindowHandle(Sender<std::result::Result<SendRawWindowHandle, raw_window_handle::HandleError>>),
  981. Theme(Sender<Theme>),
  982. // Setters
  983. Center,
  984. RequestUserAttention(Option<UserAttentionTypeWrapper>),
  985. SetResizable(bool),
  986. SetMaximizable(bool),
  987. SetMinimizable(bool),
  988. SetClosable(bool),
  989. SetTitle(String),
  990. Maximize,
  991. Unmaximize,
  992. Minimize,
  993. Unminimize,
  994. Show,
  995. Hide,
  996. Close,
  997. Destroy,
  998. SetDecorations(bool),
  999. SetShadow(bool),
  1000. SetAlwaysOnBottom(bool),
  1001. SetAlwaysOnTop(bool),
  1002. SetVisibleOnAllWorkspaces(bool),
  1003. SetContentProtected(bool),
  1004. SetSize(Size),
  1005. SetMinSize(Option<Size>),
  1006. SetMaxSize(Option<Size>),
  1007. SetPosition(Position),
  1008. SetFullscreen(bool),
  1009. SetFocus,
  1010. SetIcon(TaoWindowIcon),
  1011. SetSkipTaskbar(bool),
  1012. SetCursorGrab(bool),
  1013. SetCursorVisible(bool),
  1014. SetCursorIcon(CursorIcon),
  1015. SetCursorPosition(Position),
  1016. SetIgnoreCursorEvents(bool),
  1017. SetProgressBar(ProgressBarState),
  1018. DragWindow,
  1019. ResizeDragWindow(tauri_runtime::ResizeDirection),
  1020. RequestRedraw,
  1021. }
  1022. #[derive(Debug, Clone)]
  1023. pub enum SynthesizedWindowEvent {
  1024. Focused(bool),
  1025. DragDrop(DragDropEvent),
  1026. }
  1027. impl From<SynthesizedWindowEvent> for WindowEventWrapper {
  1028. fn from(event: SynthesizedWindowEvent) -> Self {
  1029. let event = match event {
  1030. SynthesizedWindowEvent::Focused(focused) => WindowEvent::Focused(focused),
  1031. SynthesizedWindowEvent::DragDrop(event) => WindowEvent::DragDrop(event),
  1032. };
  1033. Self(Some(event))
  1034. }
  1035. }
  1036. pub enum WebviewMessage {
  1037. AddEventListener(WebviewEventId, Box<dyn Fn(&WebviewEvent) + Send>),
  1038. #[cfg(not(all(feature = "tracing", not(target_os = "android"))))]
  1039. EvaluateScript(String),
  1040. #[cfg(all(feature = "tracing", not(target_os = "android")))]
  1041. EvaluateScript(String, Sender<()>, tracing::Span),
  1042. WebviewEvent(WebviewEvent),
  1043. SynthesizedWindowEvent(SynthesizedWindowEvent),
  1044. Navigate(Url),
  1045. Print,
  1046. Close,
  1047. SetPosition(Position),
  1048. SetSize(Size),
  1049. SetBounds(tauri_runtime::Rect),
  1050. SetFocus,
  1051. Reparent(WindowId, Sender<Result<()>>),
  1052. SetAutoResize(bool),
  1053. SetZoom(f64),
  1054. // Getters
  1055. Url(Sender<Result<Url>>),
  1056. Bounds(Sender<Result<tauri_runtime::Rect>>),
  1057. Position(Sender<Result<PhysicalPosition<i32>>>),
  1058. Size(Sender<Result<PhysicalSize<u32>>>),
  1059. WithWebview(Box<dyn FnOnce(Webview) + Send>),
  1060. // Devtools
  1061. #[cfg(any(debug_assertions, feature = "devtools"))]
  1062. OpenDevTools,
  1063. #[cfg(any(debug_assertions, feature = "devtools"))]
  1064. CloseDevTools,
  1065. #[cfg(any(debug_assertions, feature = "devtools"))]
  1066. IsDevToolsOpen(Sender<bool>),
  1067. }
  1068. pub type CreateWindowClosure<T> =
  1069. Box<dyn FnOnce(&EventLoopWindowTarget<Message<T>>) -> Result<WindowWrapper> + Send>;
  1070. pub type CreateWebviewClosure = Box<dyn FnOnce(&Window) -> Result<WebviewWrapper> + Send>;
  1071. pub enum Message<T: 'static> {
  1072. Task(Box<dyn FnOnce() + Send>),
  1073. #[cfg(target_os = "macos")]
  1074. SetActivationPolicy(ActivationPolicy),
  1075. RequestExit(i32),
  1076. #[cfg(target_os = "macos")]
  1077. Application(ApplicationMessage),
  1078. Window(WindowId, WindowMessage),
  1079. Webview(WindowId, WebviewId, WebviewMessage),
  1080. CreateWebview(WindowId, CreateWebviewClosure),
  1081. CreateWindow(WindowId, CreateWindowClosure<T>),
  1082. CreateRawWindow(
  1083. WindowId,
  1084. Box<dyn FnOnce() -> (String, TaoWindowBuilder) + Send>,
  1085. Sender<Result<Weak<Window>>>,
  1086. ),
  1087. UserEvent(T),
  1088. }
  1089. impl<T: UserEvent> Clone for Message<T> {
  1090. fn clone(&self) -> Self {
  1091. match self {
  1092. Self::UserEvent(t) => Self::UserEvent(t.clone()),
  1093. _ => unimplemented!(),
  1094. }
  1095. }
  1096. }
  1097. /// The Tauri [`WebviewDispatch`] for [`Wry`].
  1098. #[derive(Debug, Clone)]
  1099. pub struct WryWebviewDispatcher<T: UserEvent> {
  1100. window_id: Arc<Mutex<WindowId>>,
  1101. webview_id: WebviewId,
  1102. context: Context<T>,
  1103. }
  1104. impl<T: UserEvent> WebviewDispatch<T> for WryWebviewDispatcher<T> {
  1105. type Runtime = Wry<T>;
  1106. fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
  1107. send_user_message(&self.context, Message::Task(Box::new(f)))
  1108. }
  1109. fn on_webview_event<F: Fn(&WebviewEvent) + Send + 'static>(&self, f: F) -> WindowEventId {
  1110. let id = self.context.next_webview_event_id();
  1111. let _ = self.context.proxy.send_event(Message::Webview(
  1112. *self.window_id.lock().unwrap(),
  1113. self.webview_id,
  1114. WebviewMessage::AddEventListener(id, Box::new(f)),
  1115. ));
  1116. id
  1117. }
  1118. fn with_webview<F: FnOnce(Box<dyn std::any::Any>) + Send + 'static>(&self, f: F) -> Result<()> {
  1119. send_user_message(
  1120. &self.context,
  1121. Message::Webview(
  1122. *self.window_id.lock().unwrap(),
  1123. self.webview_id,
  1124. WebviewMessage::WithWebview(Box::new(move |webview| f(Box::new(webview)))),
  1125. ),
  1126. )
  1127. }
  1128. #[cfg(any(debug_assertions, feature = "devtools"))]
  1129. fn open_devtools(&self) {
  1130. let _ = send_user_message(
  1131. &self.context,
  1132. Message::Webview(
  1133. *self.window_id.lock().unwrap(),
  1134. self.webview_id,
  1135. WebviewMessage::OpenDevTools,
  1136. ),
  1137. );
  1138. }
  1139. #[cfg(any(debug_assertions, feature = "devtools"))]
  1140. fn close_devtools(&self) {
  1141. let _ = send_user_message(
  1142. &self.context,
  1143. Message::Webview(
  1144. *self.window_id.lock().unwrap(),
  1145. self.webview_id,
  1146. WebviewMessage::CloseDevTools,
  1147. ),
  1148. );
  1149. }
  1150. /// Gets the devtools window's current open state.
  1151. #[cfg(any(debug_assertions, feature = "devtools"))]
  1152. fn is_devtools_open(&self) -> Result<bool> {
  1153. webview_getter!(self, WebviewMessage::IsDevToolsOpen)
  1154. }
  1155. // Getters
  1156. fn url(&self) -> Result<Url> {
  1157. webview_getter!(self, WebviewMessage::Url)?
  1158. }
  1159. fn bounds(&self) -> Result<tauri_runtime::Rect> {
  1160. webview_getter!(self, WebviewMessage::Bounds)?
  1161. }
  1162. fn position(&self) -> Result<PhysicalPosition<i32>> {
  1163. webview_getter!(self, WebviewMessage::Position)?
  1164. }
  1165. fn size(&self) -> Result<PhysicalSize<u32>> {
  1166. webview_getter!(self, WebviewMessage::Size)?
  1167. }
  1168. // Setters
  1169. fn navigate(&self, url: Url) -> Result<()> {
  1170. send_user_message(
  1171. &self.context,
  1172. Message::Webview(
  1173. *self.window_id.lock().unwrap(),
  1174. self.webview_id,
  1175. WebviewMessage::Navigate(url),
  1176. ),
  1177. )
  1178. }
  1179. fn print(&self) -> Result<()> {
  1180. send_user_message(
  1181. &self.context,
  1182. Message::Webview(
  1183. *self.window_id.lock().unwrap(),
  1184. self.webview_id,
  1185. WebviewMessage::Print,
  1186. ),
  1187. )
  1188. }
  1189. fn close(&self) -> Result<()> {
  1190. send_user_message(
  1191. &self.context,
  1192. Message::Webview(
  1193. *self.window_id.lock().unwrap(),
  1194. self.webview_id,
  1195. WebviewMessage::Close,
  1196. ),
  1197. )
  1198. }
  1199. fn set_bounds(&self, bounds: tauri_runtime::Rect) -> Result<()> {
  1200. send_user_message(
  1201. &self.context,
  1202. Message::Webview(
  1203. *self.window_id.lock().unwrap(),
  1204. self.webview_id,
  1205. WebviewMessage::SetBounds(bounds),
  1206. ),
  1207. )
  1208. }
  1209. fn set_size(&self, size: Size) -> Result<()> {
  1210. send_user_message(
  1211. &self.context,
  1212. Message::Webview(
  1213. *self.window_id.lock().unwrap(),
  1214. self.webview_id,
  1215. WebviewMessage::SetSize(size),
  1216. ),
  1217. )
  1218. }
  1219. fn set_position(&self, position: Position) -> Result<()> {
  1220. send_user_message(
  1221. &self.context,
  1222. Message::Webview(
  1223. *self.window_id.lock().unwrap(),
  1224. self.webview_id,
  1225. WebviewMessage::SetPosition(position),
  1226. ),
  1227. )
  1228. }
  1229. fn set_focus(&self) -> Result<()> {
  1230. send_user_message(
  1231. &self.context,
  1232. Message::Webview(
  1233. *self.window_id.lock().unwrap(),
  1234. self.webview_id,
  1235. WebviewMessage::SetFocus,
  1236. ),
  1237. )
  1238. }
  1239. fn reparent(&self, window_id: WindowId) -> Result<()> {
  1240. let mut current_window_id = self.window_id.lock().unwrap();
  1241. let (tx, rx) = channel();
  1242. send_user_message(
  1243. &self.context,
  1244. Message::Webview(
  1245. *current_window_id,
  1246. self.webview_id,
  1247. WebviewMessage::Reparent(window_id, tx),
  1248. ),
  1249. )?;
  1250. rx.recv().unwrap()?;
  1251. *current_window_id = window_id;
  1252. Ok(())
  1253. }
  1254. fn set_auto_resize(&self, auto_resize: bool) -> Result<()> {
  1255. send_user_message(
  1256. &self.context,
  1257. Message::Webview(
  1258. *self.window_id.lock().unwrap(),
  1259. self.webview_id,
  1260. WebviewMessage::SetAutoResize(auto_resize),
  1261. ),
  1262. )
  1263. }
  1264. #[cfg(all(feature = "tracing", not(target_os = "android")))]
  1265. fn eval_script<S: Into<String>>(&self, script: S) -> Result<()> {
  1266. // use a channel so the EvaluateScript task uses the current span as parent
  1267. let (tx, rx) = channel();
  1268. getter!(
  1269. self,
  1270. rx,
  1271. Message::Webview(
  1272. *self.window_id.lock().unwrap(),
  1273. self.webview_id,
  1274. WebviewMessage::EvaluateScript(script.into(), tx, tracing::Span::current()),
  1275. )
  1276. )
  1277. }
  1278. #[cfg(not(all(feature = "tracing", not(target_os = "android"))))]
  1279. fn eval_script<S: Into<String>>(&self, script: S) -> Result<()> {
  1280. send_user_message(
  1281. &self.context,
  1282. Message::Webview(
  1283. *self.window_id.lock().unwrap(),
  1284. self.webview_id,
  1285. WebviewMessage::EvaluateScript(script.into()),
  1286. ),
  1287. )
  1288. }
  1289. fn set_zoom(&self, scale_factor: f64) -> Result<()> {
  1290. send_user_message(
  1291. &self.context,
  1292. Message::Webview(
  1293. *self.window_id.lock().unwrap(),
  1294. self.webview_id,
  1295. WebviewMessage::SetZoom(scale_factor),
  1296. ),
  1297. )
  1298. }
  1299. }
  1300. /// The Tauri [`WindowDispatch`] for [`Wry`].
  1301. #[derive(Debug, Clone)]
  1302. pub struct WryWindowDispatcher<T: UserEvent> {
  1303. window_id: WindowId,
  1304. context: Context<T>,
  1305. }
  1306. // SAFETY: this is safe since the `Context` usage is guarded on `send_user_message`.
  1307. #[allow(clippy::non_send_fields_in_send_ty)]
  1308. unsafe impl<T: UserEvent> Sync for WryWindowDispatcher<T> {}
  1309. fn get_raw_window_handle<T: UserEvent>(
  1310. dispatcher: &WryWindowDispatcher<T>,
  1311. ) -> Result<std::result::Result<SendRawWindowHandle, raw_window_handle::HandleError>> {
  1312. window_getter!(dispatcher, WindowMessage::RawWindowHandle)
  1313. }
  1314. impl<T: UserEvent> WindowDispatch<T> for WryWindowDispatcher<T> {
  1315. type Runtime = Wry<T>;
  1316. type WindowBuilder = WindowBuilderWrapper;
  1317. fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
  1318. send_user_message(&self.context, Message::Task(Box::new(f)))
  1319. }
  1320. fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) -> WindowEventId {
  1321. let id = self.context.next_window_event_id();
  1322. let _ = self.context.proxy.send_event(Message::Window(
  1323. self.window_id,
  1324. WindowMessage::AddEventListener(id, Box::new(f)),
  1325. ));
  1326. id
  1327. }
  1328. // Getters
  1329. fn scale_factor(&self) -> Result<f64> {
  1330. window_getter!(self, WindowMessage::ScaleFactor)
  1331. }
  1332. fn inner_position(&self) -> Result<PhysicalPosition<i32>> {
  1333. window_getter!(self, WindowMessage::InnerPosition)?
  1334. }
  1335. fn outer_position(&self) -> Result<PhysicalPosition<i32>> {
  1336. window_getter!(self, WindowMessage::OuterPosition)?
  1337. }
  1338. fn inner_size(&self) -> Result<PhysicalSize<u32>> {
  1339. window_getter!(self, WindowMessage::InnerSize)
  1340. }
  1341. fn outer_size(&self) -> Result<PhysicalSize<u32>> {
  1342. window_getter!(self, WindowMessage::OuterSize)
  1343. }
  1344. fn is_fullscreen(&self) -> Result<bool> {
  1345. window_getter!(self, WindowMessage::IsFullscreen)
  1346. }
  1347. fn is_minimized(&self) -> Result<bool> {
  1348. window_getter!(self, WindowMessage::IsMinimized)
  1349. }
  1350. fn is_maximized(&self) -> Result<bool> {
  1351. window_getter!(self, WindowMessage::IsMaximized)
  1352. }
  1353. fn is_focused(&self) -> Result<bool> {
  1354. window_getter!(self, WindowMessage::IsFocused)
  1355. }
  1356. /// Gets the window's current decoration state.
  1357. fn is_decorated(&self) -> Result<bool> {
  1358. window_getter!(self, WindowMessage::IsDecorated)
  1359. }
  1360. /// Gets the window's current resizable state.
  1361. fn is_resizable(&self) -> Result<bool> {
  1362. window_getter!(self, WindowMessage::IsResizable)
  1363. }
  1364. /// Gets the current native window's maximize button state
  1365. fn is_maximizable(&self) -> Result<bool> {
  1366. window_getter!(self, WindowMessage::IsMaximizable)
  1367. }
  1368. /// Gets the current native window's minimize button state
  1369. fn is_minimizable(&self) -> Result<bool> {
  1370. window_getter!(self, WindowMessage::IsMinimizable)
  1371. }
  1372. /// Gets the current native window's close button state
  1373. fn is_closable(&self) -> Result<bool> {
  1374. window_getter!(self, WindowMessage::IsClosable)
  1375. }
  1376. fn is_visible(&self) -> Result<bool> {
  1377. window_getter!(self, WindowMessage::IsVisible)
  1378. }
  1379. fn title(&self) -> Result<String> {
  1380. window_getter!(self, WindowMessage::Title)
  1381. }
  1382. fn current_monitor(&self) -> Result<Option<Monitor>> {
  1383. Ok(window_getter!(self, WindowMessage::CurrentMonitor)?.map(|m| MonitorHandleWrapper(m).into()))
  1384. }
  1385. fn primary_monitor(&self) -> Result<Option<Monitor>> {
  1386. Ok(window_getter!(self, WindowMessage::PrimaryMonitor)?.map(|m| MonitorHandleWrapper(m).into()))
  1387. }
  1388. fn available_monitors(&self) -> Result<Vec<Monitor>> {
  1389. Ok(
  1390. window_getter!(self, WindowMessage::AvailableMonitors)?
  1391. .into_iter()
  1392. .map(|m| MonitorHandleWrapper(m).into())
  1393. .collect(),
  1394. )
  1395. }
  1396. fn theme(&self) -> Result<Theme> {
  1397. window_getter!(self, WindowMessage::Theme)
  1398. }
  1399. #[cfg(any(
  1400. target_os = "linux",
  1401. target_os = "dragonfly",
  1402. target_os = "freebsd",
  1403. target_os = "netbsd",
  1404. target_os = "openbsd"
  1405. ))]
  1406. fn gtk_window(&self) -> Result<gtk::ApplicationWindow> {
  1407. window_getter!(self, WindowMessage::GtkWindow).map(|w| w.0)
  1408. }
  1409. #[cfg(any(
  1410. target_os = "linux",
  1411. target_os = "dragonfly",
  1412. target_os = "freebsd",
  1413. target_os = "netbsd",
  1414. target_os = "openbsd"
  1415. ))]
  1416. fn default_vbox(&self) -> Result<gtk::Box> {
  1417. window_getter!(self, WindowMessage::GtkBox).map(|w| w.0)
  1418. }
  1419. fn window_handle(
  1420. &self,
  1421. ) -> std::result::Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
  1422. get_raw_window_handle(self)
  1423. .map_err(|_| raw_window_handle::HandleError::Unavailable)
  1424. .and_then(|r| r.map(|h| unsafe { raw_window_handle::WindowHandle::borrow_raw(h.0) }))
  1425. }
  1426. // Setters
  1427. fn center(&self) -> Result<()> {
  1428. send_user_message(
  1429. &self.context,
  1430. Message::Window(self.window_id, WindowMessage::Center),
  1431. )
  1432. }
  1433. fn request_user_attention(&self, request_type: Option<UserAttentionType>) -> Result<()> {
  1434. send_user_message(
  1435. &self.context,
  1436. Message::Window(
  1437. self.window_id,
  1438. WindowMessage::RequestUserAttention(request_type.map(Into::into)),
  1439. ),
  1440. )
  1441. }
  1442. // Creates a window by dispatching a message to the event loop.
  1443. // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock.
  1444. fn create_window<F: Fn(RawWindow) + Send + 'static>(
  1445. &mut self,
  1446. pending: PendingWindow<T, Self::Runtime>,
  1447. after_window_creation: Option<F>,
  1448. ) -> Result<DetachedWindow<T, Self::Runtime>> {
  1449. self.context.create_window(pending, after_window_creation)
  1450. }
  1451. // Creates a webview by dispatching a message to the event loop.
  1452. // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock.
  1453. fn create_webview(
  1454. &mut self,
  1455. pending: PendingWebview<T, Self::Runtime>,
  1456. ) -> Result<DetachedWebview<T, Self::Runtime>> {
  1457. self.context.create_webview(self.window_id, pending)
  1458. }
  1459. fn set_resizable(&self, resizable: bool) -> Result<()> {
  1460. send_user_message(
  1461. &self.context,
  1462. Message::Window(self.window_id, WindowMessage::SetResizable(resizable)),
  1463. )
  1464. }
  1465. fn set_maximizable(&self, maximizable: bool) -> Result<()> {
  1466. send_user_message(
  1467. &self.context,
  1468. Message::Window(self.window_id, WindowMessage::SetMaximizable(maximizable)),
  1469. )
  1470. }
  1471. fn set_minimizable(&self, minimizable: bool) -> Result<()> {
  1472. send_user_message(
  1473. &self.context,
  1474. Message::Window(self.window_id, WindowMessage::SetMinimizable(minimizable)),
  1475. )
  1476. }
  1477. fn set_closable(&self, closable: bool) -> Result<()> {
  1478. send_user_message(
  1479. &self.context,
  1480. Message::Window(self.window_id, WindowMessage::SetClosable(closable)),
  1481. )
  1482. }
  1483. fn set_title<S: Into<String>>(&self, title: S) -> Result<()> {
  1484. send_user_message(
  1485. &self.context,
  1486. Message::Window(self.window_id, WindowMessage::SetTitle(title.into())),
  1487. )
  1488. }
  1489. fn maximize(&self) -> Result<()> {
  1490. send_user_message(
  1491. &self.context,
  1492. Message::Window(self.window_id, WindowMessage::Maximize),
  1493. )
  1494. }
  1495. fn unmaximize(&self) -> Result<()> {
  1496. send_user_message(
  1497. &self.context,
  1498. Message::Window(self.window_id, WindowMessage::Unmaximize),
  1499. )
  1500. }
  1501. fn minimize(&self) -> Result<()> {
  1502. send_user_message(
  1503. &self.context,
  1504. Message::Window(self.window_id, WindowMessage::Minimize),
  1505. )
  1506. }
  1507. fn unminimize(&self) -> Result<()> {
  1508. send_user_message(
  1509. &self.context,
  1510. Message::Window(self.window_id, WindowMessage::Unminimize),
  1511. )
  1512. }
  1513. fn show(&self) -> Result<()> {
  1514. send_user_message(
  1515. &self.context,
  1516. Message::Window(self.window_id, WindowMessage::Show),
  1517. )
  1518. }
  1519. fn hide(&self) -> Result<()> {
  1520. send_user_message(
  1521. &self.context,
  1522. Message::Window(self.window_id, WindowMessage::Hide),
  1523. )
  1524. }
  1525. fn close(&self) -> Result<()> {
  1526. // NOTE: close cannot use the `send_user_message` function because it accesses the event loop callback
  1527. self
  1528. .context
  1529. .proxy
  1530. .send_event(Message::Window(self.window_id, WindowMessage::Close))
  1531. .map_err(|_| Error::FailedToSendMessage)
  1532. }
  1533. fn destroy(&self) -> Result<()> {
  1534. // NOTE: destroy cannot use the `send_user_message` function because it accesses the event loop callback
  1535. self
  1536. .context
  1537. .proxy
  1538. .send_event(Message::Window(self.window_id, WindowMessage::Destroy))
  1539. .map_err(|_| Error::FailedToSendMessage)
  1540. }
  1541. fn set_decorations(&self, decorations: bool) -> Result<()> {
  1542. send_user_message(
  1543. &self.context,
  1544. Message::Window(self.window_id, WindowMessage::SetDecorations(decorations)),
  1545. )
  1546. }
  1547. fn set_shadow(&self, enable: bool) -> Result<()> {
  1548. send_user_message(
  1549. &self.context,
  1550. Message::Window(self.window_id, WindowMessage::SetShadow(enable)),
  1551. )
  1552. }
  1553. fn set_always_on_bottom(&self, always_on_bottom: bool) -> Result<()> {
  1554. send_user_message(
  1555. &self.context,
  1556. Message::Window(
  1557. self.window_id,
  1558. WindowMessage::SetAlwaysOnBottom(always_on_bottom),
  1559. ),
  1560. )
  1561. }
  1562. fn set_always_on_top(&self, always_on_top: bool) -> Result<()> {
  1563. send_user_message(
  1564. &self.context,
  1565. Message::Window(self.window_id, WindowMessage::SetAlwaysOnTop(always_on_top)),
  1566. )
  1567. }
  1568. fn set_visible_on_all_workspaces(&self, visible_on_all_workspaces: bool) -> Result<()> {
  1569. send_user_message(
  1570. &self.context,
  1571. Message::Window(
  1572. self.window_id,
  1573. WindowMessage::SetVisibleOnAllWorkspaces(visible_on_all_workspaces),
  1574. ),
  1575. )
  1576. }
  1577. fn set_content_protected(&self, protected: bool) -> Result<()> {
  1578. send_user_message(
  1579. &self.context,
  1580. Message::Window(
  1581. self.window_id,
  1582. WindowMessage::SetContentProtected(protected),
  1583. ),
  1584. )
  1585. }
  1586. fn set_size(&self, size: Size) -> Result<()> {
  1587. send_user_message(
  1588. &self.context,
  1589. Message::Window(self.window_id, WindowMessage::SetSize(size)),
  1590. )
  1591. }
  1592. fn set_min_size(&self, size: Option<Size>) -> Result<()> {
  1593. send_user_message(
  1594. &self.context,
  1595. Message::Window(self.window_id, WindowMessage::SetMinSize(size)),
  1596. )
  1597. }
  1598. fn set_max_size(&self, size: Option<Size>) -> Result<()> {
  1599. send_user_message(
  1600. &self.context,
  1601. Message::Window(self.window_id, WindowMessage::SetMaxSize(size)),
  1602. )
  1603. }
  1604. fn set_position(&self, position: Position) -> Result<()> {
  1605. send_user_message(
  1606. &self.context,
  1607. Message::Window(self.window_id, WindowMessage::SetPosition(position)),
  1608. )
  1609. }
  1610. fn set_fullscreen(&self, fullscreen: bool) -> Result<()> {
  1611. send_user_message(
  1612. &self.context,
  1613. Message::Window(self.window_id, WindowMessage::SetFullscreen(fullscreen)),
  1614. )
  1615. }
  1616. fn set_focus(&self) -> Result<()> {
  1617. send_user_message(
  1618. &self.context,
  1619. Message::Window(self.window_id, WindowMessage::SetFocus),
  1620. )
  1621. }
  1622. fn set_icon(&self, icon: Icon) -> Result<()> {
  1623. send_user_message(
  1624. &self.context,
  1625. Message::Window(
  1626. self.window_id,
  1627. WindowMessage::SetIcon(TaoIcon::try_from(icon)?.0),
  1628. ),
  1629. )
  1630. }
  1631. fn set_skip_taskbar(&self, skip: bool) -> Result<()> {
  1632. send_user_message(
  1633. &self.context,
  1634. Message::Window(self.window_id, WindowMessage::SetSkipTaskbar(skip)),
  1635. )
  1636. }
  1637. fn set_cursor_grab(&self, grab: bool) -> crate::Result<()> {
  1638. send_user_message(
  1639. &self.context,
  1640. Message::Window(self.window_id, WindowMessage::SetCursorGrab(grab)),
  1641. )
  1642. }
  1643. fn set_cursor_visible(&self, visible: bool) -> crate::Result<()> {
  1644. send_user_message(
  1645. &self.context,
  1646. Message::Window(self.window_id, WindowMessage::SetCursorVisible(visible)),
  1647. )
  1648. }
  1649. fn set_cursor_icon(&self, icon: CursorIcon) -> crate::Result<()> {
  1650. send_user_message(
  1651. &self.context,
  1652. Message::Window(self.window_id, WindowMessage::SetCursorIcon(icon)),
  1653. )
  1654. }
  1655. fn set_cursor_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
  1656. send_user_message(
  1657. &self.context,
  1658. Message::Window(
  1659. self.window_id,
  1660. WindowMessage::SetCursorPosition(position.into()),
  1661. ),
  1662. )
  1663. }
  1664. fn set_ignore_cursor_events(&self, ignore: bool) -> crate::Result<()> {
  1665. send_user_message(
  1666. &self.context,
  1667. Message::Window(self.window_id, WindowMessage::SetIgnoreCursorEvents(ignore)),
  1668. )
  1669. }
  1670. fn start_dragging(&self) -> Result<()> {
  1671. send_user_message(
  1672. &self.context,
  1673. Message::Window(self.window_id, WindowMessage::DragWindow),
  1674. )
  1675. }
  1676. fn start_resize_dragging(&self, direction: tauri_runtime::ResizeDirection) -> Result<()> {
  1677. send_user_message(
  1678. &self.context,
  1679. Message::Window(self.window_id, WindowMessage::ResizeDragWindow(direction)),
  1680. )
  1681. }
  1682. fn set_progress_bar(&self, progress_state: ProgressBarState) -> Result<()> {
  1683. send_user_message(
  1684. &self.context,
  1685. Message::Window(
  1686. self.window_id,
  1687. WindowMessage::SetProgressBar(progress_state),
  1688. ),
  1689. )
  1690. }
  1691. }
  1692. #[derive(Clone)]
  1693. pub struct WebviewWrapper {
  1694. label: String,
  1695. id: WebviewId,
  1696. inner: Rc<WebView>,
  1697. context_store: WebContextStore,
  1698. webview_event_listeners: WebviewEventListeners,
  1699. // the key of the WebContext if it's not shared
  1700. context_key: Option<PathBuf>,
  1701. bounds: Arc<Mutex<Option<WebviewBounds>>>,
  1702. }
  1703. impl Deref for WebviewWrapper {
  1704. type Target = WebView;
  1705. #[inline(always)]
  1706. fn deref(&self) -> &Self::Target {
  1707. &self.inner
  1708. }
  1709. }
  1710. impl Drop for WebviewWrapper {
  1711. fn drop(&mut self) {
  1712. if Rc::get_mut(&mut self.inner).is_some() {
  1713. self.context_store.lock().unwrap().remove(&self.context_key);
  1714. }
  1715. }
  1716. }
  1717. pub struct WindowWrapper {
  1718. label: String,
  1719. inner: Option<Arc<Window>>,
  1720. // whether this window has child webviews
  1721. // or it's just a container for a single webview
  1722. has_children: AtomicBool,
  1723. webviews: Vec<WebviewWrapper>,
  1724. window_event_listeners: WindowEventListeners,
  1725. #[cfg(windows)]
  1726. is_window_fullscreen: bool,
  1727. #[cfg(windows)]
  1728. is_window_transparent: bool,
  1729. #[cfg(windows)]
  1730. surface: Option<softbuffer::Surface<Arc<Window>, Arc<Window>>>,
  1731. }
  1732. impl fmt::Debug for WindowWrapper {
  1733. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  1734. f.debug_struct("WindowWrapper")
  1735. .field("label", &self.label)
  1736. .field("inner", &self.inner)
  1737. .finish()
  1738. }
  1739. }
  1740. #[derive(Debug, Clone)]
  1741. pub struct EventProxy<T: UserEvent>(TaoEventLoopProxy<Message<T>>);
  1742. #[cfg(target_os = "ios")]
  1743. #[allow(clippy::non_send_fields_in_send_ty)]
  1744. unsafe impl<T: UserEvent> Sync for EventProxy<T> {}
  1745. impl<T: UserEvent> EventLoopProxy<T> for EventProxy<T> {
  1746. fn send_event(&self, event: T) -> Result<()> {
  1747. self
  1748. .0
  1749. .send_event(Message::UserEvent(event))
  1750. .map_err(|_| Error::EventLoopClosed)
  1751. }
  1752. }
  1753. pub trait PluginBuilder<T: UserEvent> {
  1754. type Plugin: Plugin<T>;
  1755. fn build(self, context: Context<T>) -> Self::Plugin;
  1756. }
  1757. pub trait Plugin<T: UserEvent> {
  1758. fn on_event(
  1759. &mut self,
  1760. event: &Event<Message<T>>,
  1761. event_loop: &EventLoopWindowTarget<Message<T>>,
  1762. proxy: &TaoEventLoopProxy<Message<T>>,
  1763. control_flow: &mut ControlFlow,
  1764. context: EventLoopIterationContext<'_, T>,
  1765. web_context: &WebContextStore,
  1766. ) -> bool;
  1767. }
  1768. /// A Tauri [`Runtime`] wrapper around wry.
  1769. pub struct Wry<T: UserEvent> {
  1770. context: Context<T>,
  1771. event_loop: EventLoop<Message<T>>,
  1772. }
  1773. impl<T: UserEvent> fmt::Debug for Wry<T> {
  1774. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  1775. f.debug_struct("Wry")
  1776. .field("main_thread_id", &self.context.main_thread_id)
  1777. .field("event_loop", &self.event_loop)
  1778. .field("windows", &self.context.main_thread.windows)
  1779. .field("web_context", &self.context.main_thread.web_context)
  1780. .finish()
  1781. }
  1782. }
  1783. /// A handle to the Wry runtime.
  1784. #[derive(Debug, Clone)]
  1785. pub struct WryHandle<T: UserEvent> {
  1786. context: Context<T>,
  1787. }
  1788. // SAFETY: this is safe since the `Context` usage is guarded on `send_user_message`.
  1789. #[allow(clippy::non_send_fields_in_send_ty)]
  1790. unsafe impl<T: UserEvent> Sync for WryHandle<T> {}
  1791. impl<T: UserEvent> WryHandle<T> {
  1792. /// Creates a new tao window using a callback, and returns its window id.
  1793. pub fn create_tao_window<F: FnOnce() -> (String, TaoWindowBuilder) + Send + 'static>(
  1794. &self,
  1795. f: F,
  1796. ) -> Result<Weak<Window>> {
  1797. let id = self.context.next_window_id();
  1798. let (tx, rx) = channel();
  1799. send_user_message(&self.context, Message::CreateRawWindow(id, Box::new(f), tx))?;
  1800. rx.recv().unwrap()
  1801. }
  1802. /// Gets the [`WebviewId'] associated with the given [`WindowId`].
  1803. pub fn window_id(&self, window_id: TaoWindowId) -> WindowId {
  1804. *self
  1805. .context
  1806. .window_id_map
  1807. .0
  1808. .lock()
  1809. .unwrap()
  1810. .get(&window_id)
  1811. .unwrap()
  1812. }
  1813. /// Send a message to the event loop.
  1814. pub fn send_event(&self, message: Message<T>) -> Result<()> {
  1815. self
  1816. .context
  1817. .proxy
  1818. .send_event(message)
  1819. .map_err(|_| Error::FailedToSendMessage)?;
  1820. Ok(())
  1821. }
  1822. pub fn plugin<P: PluginBuilder<T> + 'static>(&mut self, plugin: P)
  1823. where
  1824. <P as PluginBuilder<T>>::Plugin: Send,
  1825. {
  1826. self
  1827. .context
  1828. .plugins
  1829. .lock()
  1830. .unwrap()
  1831. .push(Box::new(plugin.build(self.context.clone())));
  1832. }
  1833. }
  1834. impl<T: UserEvent> RuntimeHandle<T> for WryHandle<T> {
  1835. type Runtime = Wry<T>;
  1836. fn create_proxy(&self) -> EventProxy<T> {
  1837. EventProxy(self.context.proxy.clone())
  1838. }
  1839. #[cfg(target_os = "macos")]
  1840. fn set_activation_policy(&self, activation_policy: ActivationPolicy) -> Result<()> {
  1841. send_user_message(
  1842. &self.context,
  1843. Message::SetActivationPolicy(activation_policy),
  1844. )
  1845. }
  1846. fn request_exit(&self, code: i32) -> Result<()> {
  1847. // NOTE: request_exit cannot use the `send_user_message` function because it accesses the event loop callback
  1848. self
  1849. .context
  1850. .proxy
  1851. .send_event(Message::RequestExit(code))
  1852. .map_err(|_| Error::FailedToSendMessage)
  1853. }
  1854. // Creates a window by dispatching a message to the event loop.
  1855. // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock.
  1856. fn create_window<F: Fn(RawWindow) + Send + 'static>(
  1857. &self,
  1858. pending: PendingWindow<T, Self::Runtime>,
  1859. after_window_creation: Option<F>,
  1860. ) -> Result<DetachedWindow<T, Self::Runtime>> {
  1861. self.context.create_window(pending, after_window_creation)
  1862. }
  1863. // Creates a webview by dispatching a message to the event loop.
  1864. // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock.
  1865. fn create_webview(
  1866. &self,
  1867. window_id: WindowId,
  1868. pending: PendingWebview<T, Self::Runtime>,
  1869. ) -> Result<DetachedWebview<T, Self::Runtime>> {
  1870. self.context.create_webview(window_id, pending)
  1871. }
  1872. fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
  1873. send_user_message(&self.context, Message::Task(Box::new(f)))
  1874. }
  1875. fn display_handle(&self) -> std::result::Result<DisplayHandle, raw_window_handle::HandleError> {
  1876. self.context.main_thread.window_target.display_handle()
  1877. }
  1878. fn primary_monitor(&self) -> Option<Monitor> {
  1879. self
  1880. .context
  1881. .main_thread
  1882. .window_target
  1883. .primary_monitor()
  1884. .map(|m| MonitorHandleWrapper(m).into())
  1885. }
  1886. fn available_monitors(&self) -> Vec<Monitor> {
  1887. self
  1888. .context
  1889. .main_thread
  1890. .window_target
  1891. .available_monitors()
  1892. .map(|m| MonitorHandleWrapper(m).into())
  1893. .collect()
  1894. }
  1895. fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
  1896. self
  1897. .context
  1898. .main_thread
  1899. .window_target
  1900. .cursor_position()
  1901. .map(PhysicalPositionWrapper)
  1902. .map(Into::into)
  1903. .map_err(|_| Error::FailedToGetCursorPosition)
  1904. }
  1905. #[cfg(target_os = "macos")]
  1906. fn show(&self) -> tauri_runtime::Result<()> {
  1907. send_user_message(
  1908. &self.context,
  1909. Message::Application(ApplicationMessage::Show),
  1910. )
  1911. }
  1912. #[cfg(target_os = "macos")]
  1913. fn hide(&self) -> tauri_runtime::Result<()> {
  1914. send_user_message(
  1915. &self.context,
  1916. Message::Application(ApplicationMessage::Hide),
  1917. )
  1918. }
  1919. #[cfg(target_os = "android")]
  1920. fn find_class<'a>(
  1921. &self,
  1922. env: &mut jni::JNIEnv<'a>,
  1923. activity: &jni::objects::JObject<'_>,
  1924. name: impl Into<String>,
  1925. ) -> std::result::Result<jni::objects::JClass<'a>, jni::errors::Error> {
  1926. find_class(env, activity, name.into())
  1927. }
  1928. #[cfg(target_os = "android")]
  1929. fn run_on_android_context<F>(&self, f: F)
  1930. where
  1931. F: FnOnce(&mut jni::JNIEnv, &jni::objects::JObject, &jni::objects::JObject) + Send + 'static,
  1932. {
  1933. dispatch(f)
  1934. }
  1935. }
  1936. impl<T: UserEvent> Wry<T> {
  1937. fn init_with_builder(
  1938. mut event_loop_builder: EventLoopBuilder<Message<T>>,
  1939. #[allow(unused_variables)] args: RuntimeInitArgs,
  1940. ) -> Result<Self> {
  1941. #[cfg(windows)]
  1942. if let Some(hook) = args.msg_hook {
  1943. use tao::platform::windows::EventLoopBuilderExtWindows;
  1944. event_loop_builder.with_msg_hook(hook);
  1945. }
  1946. Self::init(event_loop_builder.build())
  1947. }
  1948. fn init(event_loop: EventLoop<Message<T>>) -> Result<Self> {
  1949. let main_thread_id = current_thread().id();
  1950. let web_context = WebContextStore::default();
  1951. let windows = Arc::new(WindowsStore(RefCell::new(BTreeMap::default())));
  1952. let window_id_map = WindowIdStore::default();
  1953. let context = Context {
  1954. window_id_map,
  1955. main_thread_id,
  1956. proxy: event_loop.create_proxy(),
  1957. main_thread: DispatcherMainThreadContext {
  1958. window_target: event_loop.deref().clone(),
  1959. web_context,
  1960. windows,
  1961. #[cfg(feature = "tracing")]
  1962. active_tracing_spans: Default::default(),
  1963. },
  1964. plugins: Default::default(),
  1965. next_window_id: Default::default(),
  1966. next_webview_id: Default::default(),
  1967. next_window_event_id: Default::default(),
  1968. next_webview_event_id: Default::default(),
  1969. next_webcontext_id: Default::default(),
  1970. };
  1971. Ok(Self {
  1972. context,
  1973. event_loop,
  1974. })
  1975. }
  1976. }
  1977. impl<T: UserEvent> Runtime<T> for Wry<T> {
  1978. type WindowDispatcher = WryWindowDispatcher<T>;
  1979. type WebviewDispatcher = WryWebviewDispatcher<T>;
  1980. type Handle = WryHandle<T>;
  1981. type EventLoopProxy = EventProxy<T>;
  1982. fn new(args: RuntimeInitArgs) -> Result<Self> {
  1983. Self::init_with_builder(EventLoopBuilder::<Message<T>>::with_user_event(), args)
  1984. }
  1985. #[cfg(any(
  1986. target_os = "linux",
  1987. target_os = "dragonfly",
  1988. target_os = "freebsd",
  1989. target_os = "netbsd",
  1990. target_os = "openbsd"
  1991. ))]
  1992. fn new_any_thread(args: RuntimeInitArgs) -> Result<Self> {
  1993. use tao::platform::unix::EventLoopBuilderExtUnix;
  1994. let mut event_loop_builder = EventLoopBuilder::<Message<T>>::with_user_event();
  1995. event_loop_builder.with_any_thread(true);
  1996. Self::init_with_builder(event_loop_builder, args)
  1997. }
  1998. #[cfg(windows)]
  1999. fn new_any_thread(args: RuntimeInitArgs) -> Result<Self> {
  2000. use tao::platform::windows::EventLoopBuilderExtWindows;
  2001. let mut event_loop_builder = EventLoopBuilder::<Message<T>>::with_user_event();
  2002. event_loop_builder.with_any_thread(true);
  2003. Self::init_with_builder(event_loop_builder, args)
  2004. }
  2005. fn create_proxy(&self) -> EventProxy<T> {
  2006. EventProxy(self.event_loop.create_proxy())
  2007. }
  2008. fn handle(&self) -> Self::Handle {
  2009. WryHandle {
  2010. context: self.context.clone(),
  2011. }
  2012. }
  2013. fn create_window<F: Fn(RawWindow) + Send + 'static>(
  2014. &self,
  2015. pending: PendingWindow<T, Self>,
  2016. after_window_creation: Option<F>,
  2017. ) -> Result<DetachedWindow<T, Self>> {
  2018. let label = pending.label.clone();
  2019. let window_id = self.context.next_window_id();
  2020. let webview_id = pending
  2021. .webview
  2022. .as_ref()
  2023. .map(|_| self.context.next_webview_id());
  2024. let window = create_window(
  2025. window_id,
  2026. webview_id.unwrap_or_default(),
  2027. &self.event_loop,
  2028. &self.context,
  2029. pending,
  2030. after_window_creation,
  2031. )?;
  2032. let dispatcher = WryWindowDispatcher {
  2033. window_id,
  2034. context: self.context.clone(),
  2035. };
  2036. self
  2037. .context
  2038. .main_thread
  2039. .windows
  2040. .0
  2041. .borrow_mut()
  2042. .insert(window_id, window);
  2043. let detached_webview = webview_id.map(|id| DetachedWebview {
  2044. label: label.clone(),
  2045. dispatcher: WryWebviewDispatcher {
  2046. window_id: Arc::new(Mutex::new(window_id)),
  2047. webview_id: id,
  2048. context: self.context.clone(),
  2049. },
  2050. });
  2051. Ok(DetachedWindow {
  2052. id: window_id,
  2053. label,
  2054. dispatcher,
  2055. webview: detached_webview,
  2056. })
  2057. }
  2058. fn create_webview(
  2059. &self,
  2060. window_id: WindowId,
  2061. pending: PendingWebview<T, Self>,
  2062. ) -> Result<DetachedWebview<T, Self>> {
  2063. let label = pending.label.clone();
  2064. let window = self
  2065. .context
  2066. .main_thread
  2067. .windows
  2068. .0
  2069. .borrow()
  2070. .get(&window_id)
  2071. .and_then(|w| w.inner.clone());
  2072. if let Some(window) = window {
  2073. let window_id_wrapper = Arc::new(Mutex::new(window_id));
  2074. let webview_id = self.context.next_webview_id();
  2075. let webview = create_webview(
  2076. WebviewKind::WindowChild,
  2077. &window,
  2078. window_id_wrapper.clone(),
  2079. webview_id,
  2080. &self.context,
  2081. pending,
  2082. )?;
  2083. self
  2084. .context
  2085. .main_thread
  2086. .windows
  2087. .0
  2088. .borrow_mut()
  2089. .get_mut(&window_id)
  2090. .map(|w| {
  2091. w.webviews.push(webview);
  2092. w.has_children.store(true, Ordering::Relaxed);
  2093. w
  2094. });
  2095. let dispatcher = WryWebviewDispatcher {
  2096. window_id: window_id_wrapper,
  2097. webview_id,
  2098. context: self.context.clone(),
  2099. };
  2100. Ok(DetachedWebview { label, dispatcher })
  2101. } else {
  2102. Err(Error::WindowNotFound)
  2103. }
  2104. }
  2105. fn primary_monitor(&self) -> Option<Monitor> {
  2106. self
  2107. .context
  2108. .main_thread
  2109. .window_target
  2110. .primary_monitor()
  2111. .map(|m| MonitorHandleWrapper(m).into())
  2112. }
  2113. fn available_monitors(&self) -> Vec<Monitor> {
  2114. self
  2115. .context
  2116. .main_thread
  2117. .window_target
  2118. .available_monitors()
  2119. .map(|m| MonitorHandleWrapper(m).into())
  2120. .collect()
  2121. }
  2122. fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
  2123. self
  2124. .context
  2125. .main_thread
  2126. .window_target
  2127. .cursor_position()
  2128. .map(PhysicalPositionWrapper)
  2129. .map(Into::into)
  2130. .map_err(|_| Error::FailedToGetCursorPosition)
  2131. }
  2132. #[cfg(target_os = "macos")]
  2133. fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
  2134. self
  2135. .event_loop
  2136. .set_activation_policy(tao_activation_policy(activation_policy));
  2137. }
  2138. #[cfg(target_os = "macos")]
  2139. fn show(&self) {
  2140. self.event_loop.show_application();
  2141. }
  2142. #[cfg(target_os = "macos")]
  2143. fn hide(&self) {
  2144. self.event_loop.hide_application();
  2145. }
  2146. fn set_device_event_filter(&mut self, filter: DeviceEventFilter) {
  2147. self
  2148. .event_loop
  2149. .set_device_event_filter(DeviceEventFilterWrapper::from(filter).0);
  2150. }
  2151. #[cfg(desktop)]
  2152. fn run_iteration<F: FnMut(RunEvent<T>) + 'static>(&mut self, mut callback: F) {
  2153. use tao::platform::run_return::EventLoopExtRunReturn;
  2154. let windows = self.context.main_thread.windows.clone();
  2155. let window_id_map = self.context.window_id_map.clone();
  2156. let web_context = &self.context.main_thread.web_context;
  2157. let plugins = self.context.plugins.clone();
  2158. #[cfg(feature = "tracing")]
  2159. let active_tracing_spans = self.context.main_thread.active_tracing_spans.clone();
  2160. let proxy = self.event_loop.create_proxy();
  2161. self
  2162. .event_loop
  2163. .run_return(|event, event_loop, control_flow| {
  2164. *control_flow = ControlFlow::Wait;
  2165. if let Event::MainEventsCleared = &event {
  2166. *control_flow = ControlFlow::Exit;
  2167. }
  2168. for p in plugins.lock().unwrap().iter_mut() {
  2169. let prevent_default = p.on_event(
  2170. &event,
  2171. event_loop,
  2172. &proxy,
  2173. control_flow,
  2174. EventLoopIterationContext {
  2175. callback: &mut callback,
  2176. window_id_map: window_id_map.clone(),
  2177. windows: windows.clone(),
  2178. #[cfg(feature = "tracing")]
  2179. active_tracing_spans: active_tracing_spans.clone(),
  2180. },
  2181. web_context,
  2182. );
  2183. if prevent_default {
  2184. return;
  2185. }
  2186. }
  2187. handle_event_loop(
  2188. event,
  2189. event_loop,
  2190. control_flow,
  2191. EventLoopIterationContext {
  2192. callback: &mut callback,
  2193. windows: windows.clone(),
  2194. window_id_map: window_id_map.clone(),
  2195. #[cfg(feature = "tracing")]
  2196. active_tracing_spans: active_tracing_spans.clone(),
  2197. },
  2198. );
  2199. });
  2200. }
  2201. fn run<F: FnMut(RunEvent<T>) + 'static>(self, mut callback: F) {
  2202. let windows = self.context.main_thread.windows.clone();
  2203. let window_id_map = self.context.window_id_map.clone();
  2204. let web_context = self.context.main_thread.web_context;
  2205. let plugins = self.context.plugins.clone();
  2206. #[cfg(feature = "tracing")]
  2207. let active_tracing_spans = self.context.main_thread.active_tracing_spans.clone();
  2208. let proxy = self.event_loop.create_proxy();
  2209. self.event_loop.run(move |event, event_loop, control_flow| {
  2210. for p in plugins.lock().unwrap().iter_mut() {
  2211. let prevent_default = p.on_event(
  2212. &event,
  2213. event_loop,
  2214. &proxy,
  2215. control_flow,
  2216. EventLoopIterationContext {
  2217. callback: &mut callback,
  2218. window_id_map: window_id_map.clone(),
  2219. windows: windows.clone(),
  2220. #[cfg(feature = "tracing")]
  2221. active_tracing_spans: active_tracing_spans.clone(),
  2222. },
  2223. &web_context,
  2224. );
  2225. if prevent_default {
  2226. return;
  2227. }
  2228. }
  2229. handle_event_loop(
  2230. event,
  2231. event_loop,
  2232. control_flow,
  2233. EventLoopIterationContext {
  2234. callback: &mut callback,
  2235. window_id_map: window_id_map.clone(),
  2236. windows: windows.clone(),
  2237. #[cfg(feature = "tracing")]
  2238. active_tracing_spans: active_tracing_spans.clone(),
  2239. },
  2240. );
  2241. })
  2242. }
  2243. }
  2244. pub struct EventLoopIterationContext<'a, T: UserEvent> {
  2245. pub callback: &'a mut (dyn FnMut(RunEvent<T>) + 'static),
  2246. pub window_id_map: WindowIdStore,
  2247. pub windows: Arc<WindowsStore>,
  2248. #[cfg(feature = "tracing")]
  2249. pub active_tracing_spans: ActiveTraceSpanStore,
  2250. }
  2251. struct UserMessageContext {
  2252. windows: Arc<WindowsStore>,
  2253. window_id_map: WindowIdStore,
  2254. }
  2255. fn handle_user_message<T: UserEvent>(
  2256. event_loop: &EventLoopWindowTarget<Message<T>>,
  2257. message: Message<T>,
  2258. context: UserMessageContext,
  2259. ) {
  2260. let UserMessageContext {
  2261. window_id_map,
  2262. windows,
  2263. } = context;
  2264. match message {
  2265. Message::Task(task) => task(),
  2266. #[cfg(target_os = "macos")]
  2267. Message::SetActivationPolicy(activation_policy) => {
  2268. event_loop.set_activation_policy_at_runtime(tao_activation_policy(activation_policy))
  2269. }
  2270. Message::RequestExit(_code) => panic!("cannot handle RequestExit on the main thread"),
  2271. #[cfg(target_os = "macos")]
  2272. Message::Application(application_message) => match application_message {
  2273. ApplicationMessage::Show => {
  2274. event_loop.show_application();
  2275. }
  2276. ApplicationMessage::Hide => {
  2277. event_loop.hide_application();
  2278. }
  2279. },
  2280. Message::Window(id, window_message) => {
  2281. let w = windows.0.borrow().get(&id).map(|w| {
  2282. (
  2283. w.inner.clone(),
  2284. w.webviews.clone(),
  2285. w.has_children.load(Ordering::Relaxed),
  2286. w.window_event_listeners.clone(),
  2287. )
  2288. });
  2289. if let Some((Some(window), webviews, has_children, window_event_listeners)) = w {
  2290. match window_message {
  2291. WindowMessage::AddEventListener(id, listener) => {
  2292. window_event_listeners.lock().unwrap().insert(id, listener);
  2293. }
  2294. // Getters
  2295. WindowMessage::ScaleFactor(tx) => tx.send(window.scale_factor()).unwrap(),
  2296. WindowMessage::InnerPosition(tx) => tx
  2297. .send(
  2298. window
  2299. .inner_position()
  2300. .map(|p| PhysicalPositionWrapper(p).into())
  2301. .map_err(|_| Error::FailedToSendMessage),
  2302. )
  2303. .unwrap(),
  2304. WindowMessage::OuterPosition(tx) => tx
  2305. .send(
  2306. window
  2307. .outer_position()
  2308. .map(|p| PhysicalPositionWrapper(p).into())
  2309. .map_err(|_| Error::FailedToSendMessage),
  2310. )
  2311. .unwrap(),
  2312. WindowMessage::InnerSize(tx) => tx
  2313. .send(PhysicalSizeWrapper(inner_size(&window, &webviews, has_children)).into())
  2314. .unwrap(),
  2315. WindowMessage::OuterSize(tx) => tx
  2316. .send(PhysicalSizeWrapper(window.outer_size()).into())
  2317. .unwrap(),
  2318. WindowMessage::IsFullscreen(tx) => tx.send(window.fullscreen().is_some()).unwrap(),
  2319. WindowMessage::IsMinimized(tx) => tx.send(window.is_minimized()).unwrap(),
  2320. WindowMessage::IsMaximized(tx) => tx.send(window.is_maximized()).unwrap(),
  2321. WindowMessage::IsFocused(tx) => tx.send(window.is_focused()).unwrap(),
  2322. WindowMessage::IsDecorated(tx) => tx.send(window.is_decorated()).unwrap(),
  2323. WindowMessage::IsResizable(tx) => tx.send(window.is_resizable()).unwrap(),
  2324. WindowMessage::IsMaximizable(tx) => tx.send(window.is_maximizable()).unwrap(),
  2325. WindowMessage::IsMinimizable(tx) => tx.send(window.is_minimizable()).unwrap(),
  2326. WindowMessage::IsClosable(tx) => tx.send(window.is_closable()).unwrap(),
  2327. WindowMessage::IsVisible(tx) => tx.send(window.is_visible()).unwrap(),
  2328. WindowMessage::Title(tx) => tx.send(window.title()).unwrap(),
  2329. WindowMessage::CurrentMonitor(tx) => tx.send(window.current_monitor()).unwrap(),
  2330. WindowMessage::PrimaryMonitor(tx) => tx.send(window.primary_monitor()).unwrap(),
  2331. WindowMessage::AvailableMonitors(tx) => {
  2332. tx.send(window.available_monitors().collect()).unwrap()
  2333. }
  2334. #[cfg(any(
  2335. target_os = "linux",
  2336. target_os = "dragonfly",
  2337. target_os = "freebsd",
  2338. target_os = "netbsd",
  2339. target_os = "openbsd"
  2340. ))]
  2341. WindowMessage::GtkWindow(tx) => tx.send(GtkWindow(window.gtk_window().clone())).unwrap(),
  2342. #[cfg(any(
  2343. target_os = "linux",
  2344. target_os = "dragonfly",
  2345. target_os = "freebsd",
  2346. target_os = "netbsd",
  2347. target_os = "openbsd"
  2348. ))]
  2349. WindowMessage::GtkBox(tx) => tx
  2350. .send(GtkBox(window.default_vbox().unwrap().clone()))
  2351. .unwrap(),
  2352. WindowMessage::RawWindowHandle(tx) => tx
  2353. .send(
  2354. window
  2355. .window_handle()
  2356. .map(|h| SendRawWindowHandle(h.as_raw())),
  2357. )
  2358. .unwrap(),
  2359. WindowMessage::Theme(tx) => {
  2360. tx.send(map_theme(&window.theme())).unwrap();
  2361. }
  2362. // Setters
  2363. WindowMessage::Center => {
  2364. #[cfg(not(target_os = "macos"))]
  2365. if let Some(monitor) = window.current_monitor() {
  2366. #[allow(unused_mut)]
  2367. let mut window_size = window.outer_size();
  2368. #[cfg(windows)]
  2369. if window.is_decorated() {
  2370. use windows::Win32::Foundation::RECT;
  2371. use windows::Win32::Graphics::Dwm::{
  2372. DwmGetWindowAttribute, DWMWA_EXTENDED_FRAME_BOUNDS,
  2373. };
  2374. let mut rect = RECT::default();
  2375. let result = unsafe {
  2376. DwmGetWindowAttribute(
  2377. HWND(window.hwnd()),
  2378. DWMWA_EXTENDED_FRAME_BOUNDS,
  2379. &mut rect as *mut _ as *mut _,
  2380. std::mem::size_of::<RECT>() as u32,
  2381. )
  2382. };
  2383. if result.is_ok() {
  2384. window_size.height = (rect.bottom - rect.top) as u32;
  2385. }
  2386. }
  2387. window.set_outer_position(calculate_window_center_position(window_size, monitor));
  2388. }
  2389. #[cfg(target_os = "macos")]
  2390. {
  2391. use cocoa::{appkit::NSWindow, base::id};
  2392. let ns_window: id = window.ns_window() as _;
  2393. unsafe { ns_window.center() };
  2394. }
  2395. }
  2396. WindowMessage::RequestUserAttention(request_type) => {
  2397. window.request_user_attention(request_type.map(|r| r.0));
  2398. }
  2399. WindowMessage::SetResizable(resizable) => window.set_resizable(resizable),
  2400. WindowMessage::SetMaximizable(maximizable) => window.set_maximizable(maximizable),
  2401. WindowMessage::SetMinimizable(minimizable) => window.set_minimizable(minimizable),
  2402. WindowMessage::SetClosable(closable) => window.set_closable(closable),
  2403. WindowMessage::SetTitle(title) => window.set_title(&title),
  2404. WindowMessage::Maximize => window.set_maximized(true),
  2405. WindowMessage::Unmaximize => window.set_maximized(false),
  2406. WindowMessage::Minimize => window.set_minimized(true),
  2407. WindowMessage::Unminimize => window.set_minimized(false),
  2408. WindowMessage::Show => window.set_visible(true),
  2409. WindowMessage::Hide => window.set_visible(false),
  2410. WindowMessage::Close => {
  2411. panic!("cannot handle `WindowMessage::Close` on the main thread")
  2412. }
  2413. WindowMessage::Destroy => {
  2414. panic!("cannot handle `WindowMessage::Destroy` on the main thread")
  2415. }
  2416. WindowMessage::SetDecorations(decorations) => window.set_decorations(decorations),
  2417. WindowMessage::SetShadow(_enable) => {
  2418. #[cfg(windows)]
  2419. window.set_undecorated_shadow(_enable);
  2420. #[cfg(target_os = "macos")]
  2421. window.set_has_shadow(_enable);
  2422. }
  2423. WindowMessage::SetAlwaysOnBottom(always_on_bottom) => {
  2424. window.set_always_on_bottom(always_on_bottom)
  2425. }
  2426. WindowMessage::SetAlwaysOnTop(always_on_top) => window.set_always_on_top(always_on_top),
  2427. WindowMessage::SetVisibleOnAllWorkspaces(visible_on_all_workspaces) => {
  2428. window.set_visible_on_all_workspaces(visible_on_all_workspaces)
  2429. }
  2430. WindowMessage::SetContentProtected(protected) => window.set_content_protection(protected),
  2431. WindowMessage::SetSize(size) => {
  2432. window.set_inner_size(SizeWrapper::from(size).0);
  2433. }
  2434. WindowMessage::SetMinSize(size) => {
  2435. window.set_min_inner_size(size.map(|s| SizeWrapper::from(s).0));
  2436. }
  2437. WindowMessage::SetMaxSize(size) => {
  2438. window.set_max_inner_size(size.map(|s| SizeWrapper::from(s).0));
  2439. }
  2440. WindowMessage::SetPosition(position) => {
  2441. window.set_outer_position(PositionWrapper::from(position).0)
  2442. }
  2443. WindowMessage::SetFullscreen(fullscreen) => {
  2444. if fullscreen {
  2445. window.set_fullscreen(Some(Fullscreen::Borderless(None)))
  2446. } else {
  2447. window.set_fullscreen(None)
  2448. }
  2449. #[cfg(windows)]
  2450. if let Some(w) = windows.0.borrow_mut().get_mut(&id) {
  2451. w.is_window_fullscreen = fullscreen;
  2452. }
  2453. }
  2454. WindowMessage::SetFocus => {
  2455. window.set_focus();
  2456. }
  2457. WindowMessage::SetIcon(icon) => {
  2458. window.set_window_icon(Some(icon));
  2459. }
  2460. #[allow(unused_variables)]
  2461. WindowMessage::SetSkipTaskbar(skip) => {
  2462. #[cfg(any(windows, target_os = "linux"))]
  2463. window.set_skip_taskbar(skip);
  2464. }
  2465. WindowMessage::SetCursorGrab(grab) => {
  2466. let _ = window.set_cursor_grab(grab);
  2467. }
  2468. WindowMessage::SetCursorVisible(visible) => {
  2469. window.set_cursor_visible(visible);
  2470. }
  2471. WindowMessage::SetCursorIcon(icon) => {
  2472. window.set_cursor_icon(CursorIconWrapper::from(icon).0);
  2473. }
  2474. WindowMessage::SetCursorPosition(position) => {
  2475. let _ = window.set_cursor_position(PositionWrapper::from(position).0);
  2476. }
  2477. WindowMessage::SetIgnoreCursorEvents(ignore) => {
  2478. let _ = window.set_ignore_cursor_events(ignore);
  2479. }
  2480. WindowMessage::DragWindow => {
  2481. let _ = window.drag_window();
  2482. }
  2483. WindowMessage::ResizeDragWindow(direction) => {
  2484. let _ = window.drag_resize_window(match direction {
  2485. tauri_runtime::ResizeDirection::East => tao::window::ResizeDirection::East,
  2486. tauri_runtime::ResizeDirection::North => tao::window::ResizeDirection::North,
  2487. tauri_runtime::ResizeDirection::NorthEast => tao::window::ResizeDirection::NorthEast,
  2488. tauri_runtime::ResizeDirection::NorthWest => tao::window::ResizeDirection::NorthWest,
  2489. tauri_runtime::ResizeDirection::South => tao::window::ResizeDirection::South,
  2490. tauri_runtime::ResizeDirection::SouthEast => tao::window::ResizeDirection::SouthEast,
  2491. tauri_runtime::ResizeDirection::SouthWest => tao::window::ResizeDirection::SouthWest,
  2492. tauri_runtime::ResizeDirection::West => tao::window::ResizeDirection::West,
  2493. });
  2494. }
  2495. WindowMessage::RequestRedraw => {
  2496. window.request_redraw();
  2497. }
  2498. WindowMessage::SetProgressBar(progress_state) => {
  2499. window.set_progress_bar(ProgressBarStateWrapper::from(progress_state).0);
  2500. }
  2501. }
  2502. }
  2503. }
  2504. Message::Webview(window_id, webview_id, webview_message) => {
  2505. #[cfg(any(
  2506. target_os = "macos",
  2507. windows,
  2508. target_os = "linux",
  2509. target_os = "dragonfly",
  2510. target_os = "freebsd",
  2511. target_os = "netbsd",
  2512. target_os = "openbsd"
  2513. ))]
  2514. if let WebviewMessage::Reparent(new_parent_window_id, tx) = webview_message {
  2515. let webview_handle = windows.0.borrow_mut().get_mut(&window_id).and_then(|w| {
  2516. w.webviews
  2517. .iter()
  2518. .position(|w| w.id == webview_id)
  2519. .map(|webview_index| w.webviews.remove(webview_index))
  2520. });
  2521. if let Some(webview) = webview_handle {
  2522. if let Some((Some(new_parent_window), new_parent_window_webviews)) = windows
  2523. .0
  2524. .borrow_mut()
  2525. .get_mut(&new_parent_window_id)
  2526. .map(|w| (w.inner.clone(), &mut w.webviews))
  2527. {
  2528. #[cfg(target_os = "macos")]
  2529. let reparent_result = {
  2530. use wry::WebViewExtMacOS;
  2531. webview.inner.reparent(new_parent_window.ns_window() as _)
  2532. };
  2533. #[cfg(windows)]
  2534. let reparent_result = { webview.inner.reparent(new_parent_window.hwnd()) };
  2535. #[cfg(any(
  2536. target_os = "linux",
  2537. target_os = "dragonfly",
  2538. target_os = "freebsd",
  2539. target_os = "netbsd",
  2540. target_os = "openbsd"
  2541. ))]
  2542. let reparent_result = {
  2543. if let Some(container) = new_parent_window.default_vbox() {
  2544. webview.inner.reparent(container)
  2545. } else {
  2546. Err(wry::Error::MessageSender)
  2547. }
  2548. };
  2549. match reparent_result {
  2550. Ok(_) => {
  2551. new_parent_window_webviews.push(webview);
  2552. tx.send(Ok(())).unwrap();
  2553. }
  2554. Err(e) => {
  2555. log::error!("failed to reparent webview: {e}");
  2556. tx.send(Err(Error::FailedToSendMessage)).unwrap();
  2557. }
  2558. }
  2559. }
  2560. } else {
  2561. tx.send(Err(Error::FailedToSendMessage)).unwrap();
  2562. }
  2563. return;
  2564. }
  2565. let webview_handle = windows.0.borrow().get(&window_id).map(|w| {
  2566. (
  2567. w.inner.clone(),
  2568. w.webviews.iter().find(|w| w.id == webview_id).cloned(),
  2569. )
  2570. });
  2571. if let Some((Some(window), Some(webview))) = webview_handle {
  2572. match webview_message {
  2573. WebviewMessage::WebviewEvent(_) => { /* already handled */ }
  2574. WebviewMessage::SynthesizedWindowEvent(_) => { /* already handled */ }
  2575. WebviewMessage::Reparent(_window_id, _tx) => { /* already handled */ }
  2576. WebviewMessage::AddEventListener(id, listener) => {
  2577. webview
  2578. .webview_event_listeners
  2579. .lock()
  2580. .unwrap()
  2581. .insert(id, listener);
  2582. }
  2583. #[cfg(all(feature = "tracing", not(target_os = "android")))]
  2584. WebviewMessage::EvaluateScript(script, tx, span) => {
  2585. let _span = span.entered();
  2586. if let Err(e) = webview.evaluate_script(&script) {
  2587. log::error!("{}", e);
  2588. }
  2589. tx.send(()).unwrap();
  2590. }
  2591. #[cfg(not(all(feature = "tracing", not(target_os = "android"))))]
  2592. WebviewMessage::EvaluateScript(script) => {
  2593. if let Err(e) = webview.evaluate_script(&script) {
  2594. log::error!("{}", e);
  2595. }
  2596. }
  2597. WebviewMessage::Navigate(url) => {
  2598. if let Err(e) = webview.load_url(url.as_str()) {
  2599. log::error!("failed to navigate to url {}: {}", url, e);
  2600. }
  2601. }
  2602. WebviewMessage::Print => {
  2603. let _ = webview.print();
  2604. }
  2605. WebviewMessage::Close => {
  2606. windows.0.borrow_mut().get_mut(&window_id).map(|window| {
  2607. if let Some(i) = window.webviews.iter().position(|w| w.id == webview.id) {
  2608. window.webviews.remove(i);
  2609. }
  2610. window
  2611. });
  2612. }
  2613. WebviewMessage::SetBounds(bounds) => {
  2614. let bounds: RectWrapper = bounds.into();
  2615. let bounds = bounds.0;
  2616. if let Some(b) = &mut *webview.bounds.lock().unwrap() {
  2617. let scale_factor = window.scale_factor();
  2618. let size = bounds.size.to_logical::<f32>(scale_factor);
  2619. let position = bounds.position.to_logical::<f32>(scale_factor);
  2620. let window_size = window.inner_size().to_logical::<f32>(scale_factor);
  2621. b.width_rate = size.width / window_size.width;
  2622. b.height_rate = size.height / window_size.height;
  2623. b.x_rate = position.x / window_size.width;
  2624. b.y_rate = position.y / window_size.height;
  2625. }
  2626. if let Err(e) = webview.set_bounds(bounds) {
  2627. log::error!("failed to set webview size: {e}");
  2628. }
  2629. }
  2630. WebviewMessage::SetSize(size) => match webview.bounds() {
  2631. Ok(mut bounds) => {
  2632. bounds.size = size;
  2633. let scale_factor = window.scale_factor();
  2634. let size = size.to_logical::<f32>(scale_factor);
  2635. if let Some(b) = &mut *webview.bounds.lock().unwrap() {
  2636. let window_size = window.inner_size().to_logical::<f32>(scale_factor);
  2637. b.width_rate = size.width / window_size.width;
  2638. b.height_rate = size.height / window_size.height;
  2639. }
  2640. if let Err(e) = webview.set_bounds(bounds) {
  2641. log::error!("failed to set webview size: {e}");
  2642. }
  2643. }
  2644. Err(e) => {
  2645. log::error!("failed to get webview bounds: {e}");
  2646. }
  2647. },
  2648. WebviewMessage::SetPosition(position) => match webview.bounds() {
  2649. Ok(mut bounds) => {
  2650. bounds.position = position;
  2651. let scale_factor = window.scale_factor();
  2652. let position = position.to_logical::<f32>(scale_factor);
  2653. if let Some(b) = &mut *webview.bounds.lock().unwrap() {
  2654. let window_size = window.inner_size().to_logical::<f32>(scale_factor);
  2655. b.x_rate = position.x / window_size.width;
  2656. b.y_rate = position.y / window_size.height;
  2657. }
  2658. if let Err(e) = webview.set_bounds(bounds) {
  2659. log::error!("failed to set webview position: {e}");
  2660. }
  2661. }
  2662. Err(e) => {
  2663. log::error!("failed to get webview bounds: {e}");
  2664. }
  2665. },
  2666. WebviewMessage::SetZoom(scale_factor) => {
  2667. if let Err(e) = webview.zoom(scale_factor) {
  2668. log::error!("failed to set webview zoom: {e}");
  2669. }
  2670. }
  2671. // Getters
  2672. WebviewMessage::Url(tx) => {
  2673. tx.send(
  2674. webview
  2675. .url()
  2676. .map(|u| u.parse().expect("invalid webview URL"))
  2677. .map_err(|_| Error::FailedToSendMessage),
  2678. )
  2679. .unwrap();
  2680. }
  2681. WebviewMessage::Bounds(tx) => {
  2682. tx.send(
  2683. webview
  2684. .bounds()
  2685. .map(|bounds| tauri_runtime::Rect {
  2686. size: bounds.size,
  2687. position: bounds.position,
  2688. })
  2689. .map_err(|_| Error::FailedToSendMessage),
  2690. )
  2691. .unwrap();
  2692. }
  2693. WebviewMessage::Position(tx) => {
  2694. tx.send(
  2695. webview
  2696. .bounds()
  2697. .map(|bounds| bounds.position.to_physical(window.scale_factor()))
  2698. .map_err(|_| Error::FailedToSendMessage),
  2699. )
  2700. .unwrap();
  2701. }
  2702. WebviewMessage::Size(tx) => {
  2703. tx.send(
  2704. webview
  2705. .bounds()
  2706. .map(|bounds| bounds.size.to_physical(window.scale_factor()))
  2707. .map_err(|_| Error::FailedToSendMessage),
  2708. )
  2709. .unwrap();
  2710. }
  2711. WebviewMessage::SetFocus => {
  2712. if let Err(e) = webview.focus() {
  2713. log::error!("failed to focus webview: {e}");
  2714. }
  2715. }
  2716. WebviewMessage::SetAutoResize(auto_resize) => match webview.bounds() {
  2717. Ok(bounds) => {
  2718. let scale_factor = window.scale_factor();
  2719. let window_size = window.inner_size().to_logical::<f32>(scale_factor);
  2720. *webview.bounds.lock().unwrap() = if auto_resize {
  2721. let size = bounds.size.to_logical::<f32>(scale_factor);
  2722. let position = bounds.position.to_logical::<f32>(scale_factor);
  2723. Some(WebviewBounds {
  2724. x_rate: position.x / window_size.width,
  2725. y_rate: position.y / window_size.height,
  2726. width_rate: size.width / window_size.width,
  2727. height_rate: size.height / window_size.height,
  2728. })
  2729. } else {
  2730. None
  2731. };
  2732. }
  2733. Err(e) => {
  2734. log::error!("failed to get webview bounds: {e}");
  2735. }
  2736. },
  2737. WebviewMessage::WithWebview(f) => {
  2738. #[cfg(any(
  2739. target_os = "linux",
  2740. target_os = "dragonfly",
  2741. target_os = "freebsd",
  2742. target_os = "netbsd",
  2743. target_os = "openbsd"
  2744. ))]
  2745. {
  2746. f(webview.webview());
  2747. }
  2748. #[cfg(target_os = "macos")]
  2749. {
  2750. use wry::WebViewExtMacOS;
  2751. f(Webview {
  2752. webview: webview.webview(),
  2753. manager: webview.manager(),
  2754. ns_window: webview.ns_window(),
  2755. });
  2756. }
  2757. #[cfg(target_os = "ios")]
  2758. {
  2759. use tao::platform::ios::WindowExtIOS;
  2760. use wry::WebViewExtIOS;
  2761. f(Webview {
  2762. webview: webview.inner.webview(),
  2763. manager: webview.inner.manager(),
  2764. view_controller: window.ui_view_controller() as cocoa::base::id,
  2765. });
  2766. }
  2767. #[cfg(windows)]
  2768. {
  2769. f(Webview {
  2770. controller: webview.controller(),
  2771. });
  2772. }
  2773. #[cfg(target_os = "android")]
  2774. {
  2775. f(webview.handle())
  2776. }
  2777. }
  2778. #[cfg(any(debug_assertions, feature = "devtools"))]
  2779. WebviewMessage::OpenDevTools => {
  2780. webview.open_devtools();
  2781. }
  2782. #[cfg(any(debug_assertions, feature = "devtools"))]
  2783. WebviewMessage::CloseDevTools => {
  2784. webview.close_devtools();
  2785. }
  2786. #[cfg(any(debug_assertions, feature = "devtools"))]
  2787. WebviewMessage::IsDevToolsOpen(tx) => {
  2788. tx.send(webview.is_devtools_open()).unwrap();
  2789. }
  2790. }
  2791. }
  2792. }
  2793. Message::CreateWebview(window_id, handler) => {
  2794. let window = windows
  2795. .0
  2796. .borrow()
  2797. .get(&window_id)
  2798. .and_then(|w| w.inner.clone());
  2799. if let Some(window) = window {
  2800. match handler(&window) {
  2801. Ok(webview) => {
  2802. windows.0.borrow_mut().get_mut(&window_id).map(|w| {
  2803. w.webviews.push(webview);
  2804. w.has_children.store(true, Ordering::Relaxed);
  2805. w
  2806. });
  2807. }
  2808. Err(e) => {
  2809. log::error!("{}", e);
  2810. }
  2811. }
  2812. }
  2813. }
  2814. Message::CreateWindow(window_id, handler) => match handler(event_loop) {
  2815. Ok(webview) => {
  2816. windows.0.borrow_mut().insert(window_id, webview);
  2817. }
  2818. Err(e) => {
  2819. log::error!("{}", e);
  2820. }
  2821. },
  2822. Message::CreateRawWindow(window_id, handler, sender) => {
  2823. let (label, builder) = handler();
  2824. #[cfg(windows)]
  2825. let is_window_fullscreen = builder.window.fullscreen.is_some();
  2826. #[cfg(windows)]
  2827. let is_window_transparent = builder.window.transparent;
  2828. if let Ok(window) = builder.build(event_loop) {
  2829. window_id_map.insert(window.id(), window_id);
  2830. let window = Arc::new(window);
  2831. #[cfg(windows)]
  2832. let surface = if is_window_transparent {
  2833. if let Ok(context) = softbuffer::Context::new(window.clone()) {
  2834. if let Ok(mut surface) = softbuffer::Surface::new(&context, window.clone()) {
  2835. clear_window_surface(&window, &mut surface);
  2836. Some(surface)
  2837. } else {
  2838. None
  2839. }
  2840. } else {
  2841. None
  2842. }
  2843. } else {
  2844. None
  2845. };
  2846. windows.0.borrow_mut().insert(
  2847. window_id,
  2848. WindowWrapper {
  2849. label,
  2850. has_children: AtomicBool::new(false),
  2851. inner: Some(window.clone()),
  2852. window_event_listeners: Default::default(),
  2853. webviews: Vec::new(),
  2854. #[cfg(windows)]
  2855. is_window_fullscreen,
  2856. #[cfg(windows)]
  2857. is_window_transparent,
  2858. #[cfg(windows)]
  2859. surface,
  2860. },
  2861. );
  2862. sender.send(Ok(Arc::downgrade(&window))).unwrap();
  2863. } else {
  2864. sender.send(Err(Error::CreateWindow)).unwrap();
  2865. }
  2866. }
  2867. Message::UserEvent(_) => (),
  2868. }
  2869. }
  2870. fn handle_event_loop<T: UserEvent>(
  2871. event: Event<'_, Message<T>>,
  2872. event_loop: &EventLoopWindowTarget<Message<T>>,
  2873. control_flow: &mut ControlFlow,
  2874. context: EventLoopIterationContext<'_, T>,
  2875. ) {
  2876. let EventLoopIterationContext {
  2877. callback,
  2878. window_id_map,
  2879. windows,
  2880. #[cfg(feature = "tracing")]
  2881. active_tracing_spans,
  2882. } = context;
  2883. if *control_flow != ControlFlow::Exit {
  2884. *control_flow = ControlFlow::Wait;
  2885. }
  2886. match event {
  2887. Event::NewEvents(StartCause::Init) => {
  2888. callback(RunEvent::Ready);
  2889. }
  2890. Event::NewEvents(StartCause::Poll) => {
  2891. callback(RunEvent::Resumed);
  2892. }
  2893. Event::MainEventsCleared => {
  2894. callback(RunEvent::MainEventsCleared);
  2895. }
  2896. Event::LoopDestroyed => {
  2897. callback(RunEvent::Exit);
  2898. }
  2899. #[cfg(any(feature = "tracing", windows))]
  2900. Event::RedrawRequested(id) => {
  2901. #[cfg(windows)]
  2902. if let Some(window_id) = window_id_map.get(&id) {
  2903. let mut windows_ref = windows.0.borrow_mut();
  2904. if let Some(window) = windows_ref.get_mut(&window_id) {
  2905. if window.is_window_transparent {
  2906. if let Some(surface) = &mut window.surface {
  2907. if let Some(window) = &window.inner {
  2908. clear_window_surface(window, surface)
  2909. }
  2910. }
  2911. }
  2912. }
  2913. }
  2914. #[cfg(feature = "tracing")]
  2915. active_tracing_spans.remove_window_draw(id);
  2916. }
  2917. Event::UserEvent(Message::Webview(
  2918. window_id,
  2919. webview_id,
  2920. WebviewMessage::WebviewEvent(event),
  2921. )) => {
  2922. let windows_ref = windows.0.borrow();
  2923. if let Some(window) = windows_ref.get(&window_id) {
  2924. if let Some(webview) = window.webviews.iter().find(|w| w.id == webview_id) {
  2925. let label = webview.label.clone();
  2926. let webview_event_listeners = webview.webview_event_listeners.clone();
  2927. drop(windows_ref);
  2928. callback(RunEvent::WebviewEvent {
  2929. label,
  2930. event: event.clone(),
  2931. });
  2932. let listeners = webview_event_listeners.lock().unwrap();
  2933. let handlers = listeners.values();
  2934. for handler in handlers {
  2935. handler(&event);
  2936. }
  2937. }
  2938. }
  2939. }
  2940. Event::UserEvent(Message::Webview(
  2941. window_id,
  2942. _webview_id,
  2943. WebviewMessage::SynthesizedWindowEvent(event),
  2944. )) => {
  2945. if let Some(event) = WindowEventWrapper::from(event).0 {
  2946. let windows_ref = windows.0.borrow();
  2947. let window = windows_ref.get(&window_id);
  2948. if let Some(window) = window {
  2949. let label = window.label.clone();
  2950. let window_event_listeners = window.window_event_listeners.clone();
  2951. drop(windows_ref);
  2952. callback(RunEvent::WindowEvent {
  2953. label,
  2954. event: event.clone(),
  2955. });
  2956. let listeners = window_event_listeners.lock().unwrap();
  2957. let handlers = listeners.values();
  2958. for handler in handlers {
  2959. handler(&event);
  2960. }
  2961. }
  2962. }
  2963. }
  2964. Event::WindowEvent {
  2965. event, window_id, ..
  2966. } => {
  2967. if let Some(window_id) = window_id_map.get(&window_id) {
  2968. {
  2969. let windows_ref = windows.0.borrow();
  2970. if let Some(window) = windows_ref.get(&window_id) {
  2971. if let Some(event) = WindowEventWrapper::parse(window, &event).0 {
  2972. let label = window.label.clone();
  2973. let window_event_listeners = window.window_event_listeners.clone();
  2974. drop(windows_ref);
  2975. callback(RunEvent::WindowEvent {
  2976. label,
  2977. event: event.clone(),
  2978. });
  2979. let listeners = window_event_listeners.lock().unwrap();
  2980. let handlers = listeners.values();
  2981. for handler in handlers {
  2982. handler(&event);
  2983. }
  2984. }
  2985. }
  2986. }
  2987. match event {
  2988. #[cfg(windows)]
  2989. TaoWindowEvent::ThemeChanged(theme) => {
  2990. if let Some(window) = windows.0.borrow().get(&window_id) {
  2991. for webview in &window.webviews {
  2992. let theme = match theme {
  2993. TaoTheme::Dark => wry::Theme::Dark,
  2994. TaoTheme::Light => wry::Theme::Light,
  2995. _ => wry::Theme::Light,
  2996. };
  2997. if let Err(e) = webview.set_theme(theme) {
  2998. log::error!("failed to set theme: {e}");
  2999. }
  3000. }
  3001. }
  3002. }
  3003. TaoWindowEvent::CloseRequested => {
  3004. on_close_requested(callback, window_id, windows.clone());
  3005. }
  3006. TaoWindowEvent::Destroyed => {
  3007. let removed = windows.0.borrow_mut().remove(&window_id).is_some();
  3008. if removed {
  3009. let is_empty = windows.0.borrow().is_empty();
  3010. if is_empty {
  3011. let (tx, rx) = channel();
  3012. callback(RunEvent::ExitRequested { code: None, tx });
  3013. let recv = rx.try_recv();
  3014. let should_prevent = matches!(recv, Ok(ExitRequestedEventAction::Prevent));
  3015. if !should_prevent {
  3016. *control_flow = ControlFlow::Exit;
  3017. }
  3018. }
  3019. }
  3020. }
  3021. TaoWindowEvent::Resized(size) => {
  3022. if let Some((Some(window), webviews)) = windows
  3023. .0
  3024. .borrow()
  3025. .get(&window_id)
  3026. .map(|w| (w.inner.clone(), w.webviews.clone()))
  3027. {
  3028. let size = size.to_logical::<f32>(window.scale_factor());
  3029. for webview in webviews {
  3030. if let Some(b) = &*webview.bounds.lock().unwrap() {
  3031. if let Err(e) = webview.set_bounds(wry::Rect {
  3032. position: LogicalPosition::new(size.width * b.x_rate, size.height * b.y_rate)
  3033. .into(),
  3034. size: LogicalSize::new(size.width * b.width_rate, size.height * b.height_rate)
  3035. .into(),
  3036. }) {
  3037. log::error!("failed to autoresize webview: {e}");
  3038. }
  3039. }
  3040. }
  3041. }
  3042. }
  3043. _ => {}
  3044. }
  3045. }
  3046. }
  3047. Event::UserEvent(message) => match message {
  3048. Message::RequestExit(code) => {
  3049. let (tx, rx) = channel();
  3050. callback(RunEvent::ExitRequested {
  3051. code: Some(code),
  3052. tx,
  3053. });
  3054. let recv = rx.try_recv();
  3055. let should_prevent = matches!(recv, Ok(ExitRequestedEventAction::Prevent));
  3056. if !should_prevent {
  3057. *control_flow = ControlFlow::Exit;
  3058. }
  3059. }
  3060. Message::Window(id, WindowMessage::Close) => {
  3061. on_close_requested(callback, id, windows.clone());
  3062. }
  3063. Message::Window(id, WindowMessage::Destroy) => {
  3064. on_window_close(id, windows.clone());
  3065. }
  3066. Message::UserEvent(t) => callback(RunEvent::UserEvent(t)),
  3067. message => {
  3068. handle_user_message(
  3069. event_loop,
  3070. message,
  3071. UserMessageContext {
  3072. window_id_map,
  3073. windows,
  3074. },
  3075. );
  3076. }
  3077. },
  3078. #[cfg(any(target_os = "macos", target_os = "ios"))]
  3079. Event::Opened { urls } => {
  3080. callback(RunEvent::Opened { urls });
  3081. }
  3082. _ => (),
  3083. }
  3084. }
  3085. fn on_close_requested<'a, T: UserEvent>(
  3086. callback: &'a mut (dyn FnMut(RunEvent<T>) + 'static),
  3087. window_id: WindowId,
  3088. windows: Arc<WindowsStore>,
  3089. ) {
  3090. let (tx, rx) = channel();
  3091. let windows_ref = windows.0.borrow();
  3092. if let Some(w) = windows_ref.get(&window_id) {
  3093. let label = w.label.clone();
  3094. let window_event_listeners = w.window_event_listeners.clone();
  3095. drop(windows_ref);
  3096. let listeners = window_event_listeners.lock().unwrap();
  3097. let handlers = listeners.values();
  3098. for handler in handlers {
  3099. handler(&WindowEvent::CloseRequested {
  3100. signal_tx: tx.clone(),
  3101. });
  3102. }
  3103. callback(RunEvent::WindowEvent {
  3104. label,
  3105. event: WindowEvent::CloseRequested { signal_tx: tx },
  3106. });
  3107. if let Ok(true) = rx.try_recv() {
  3108. } else {
  3109. on_window_close(window_id, windows);
  3110. }
  3111. }
  3112. }
  3113. fn on_window_close(window_id: WindowId, windows: Arc<WindowsStore>) {
  3114. if let Some(window_wrapper) = windows.0.borrow_mut().get_mut(&window_id) {
  3115. window_wrapper.inner = None;
  3116. #[cfg(windows)]
  3117. window_wrapper.surface.take();
  3118. }
  3119. }
  3120. fn parse_proxy_url(url: &Url) -> Result<ProxyConfig> {
  3121. let host = url.host().map(|h| h.to_string()).unwrap_or_default();
  3122. let port = url.port().map(|p| p.to_string()).unwrap_or_default();
  3123. if url.scheme() == "http" {
  3124. let config = ProxyConfig::Http(ProxyEndpoint { host, port });
  3125. Ok(config)
  3126. } else if url.scheme() == "socks5" {
  3127. let config = ProxyConfig::Socks5(ProxyEndpoint { host, port });
  3128. Ok(config)
  3129. } else {
  3130. Err(Error::InvalidProxyUrl)
  3131. }
  3132. }
  3133. fn create_window<T: UserEvent, F: Fn(RawWindow) + Send + 'static>(
  3134. window_id: WindowId,
  3135. webview_id: u32,
  3136. event_loop: &EventLoopWindowTarget<Message<T>>,
  3137. context: &Context<T>,
  3138. pending: PendingWindow<T, Wry<T>>,
  3139. after_window_creation: Option<F>,
  3140. ) -> Result<WindowWrapper> {
  3141. #[allow(unused_mut)]
  3142. let PendingWindow {
  3143. mut window_builder,
  3144. label,
  3145. webview,
  3146. } = pending;
  3147. #[cfg(feature = "tracing")]
  3148. let _webview_create_span = tracing::debug_span!("wry::webview::create").entered();
  3149. #[cfg(feature = "tracing")]
  3150. let window_draw_span = tracing::debug_span!("wry::window::draw").entered();
  3151. #[cfg(feature = "tracing")]
  3152. let window_create_span =
  3153. tracing::debug_span!(parent: &window_draw_span, "wry::window::create").entered();
  3154. let window_event_listeners = WindowEventListeners::default();
  3155. #[cfg(windows)]
  3156. let is_window_transparent = window_builder.inner.window.transparent;
  3157. #[cfg(windows)]
  3158. let is_window_fullscreen = window_builder.inner.window.fullscreen.is_some();
  3159. #[cfg(target_os = "macos")]
  3160. {
  3161. if window_builder.tabbing_identifier.is_none()
  3162. || window_builder.inner.window.transparent
  3163. || !window_builder.inner.window.decorations
  3164. {
  3165. window_builder.inner = window_builder.inner.with_automatic_window_tabbing(false);
  3166. }
  3167. }
  3168. #[cfg(desktop)]
  3169. if window_builder.center {
  3170. let monitor = if let Some(window_position) = &window_builder.inner.window.position {
  3171. event_loop.available_monitors().find(|m| {
  3172. let monitor_pos = m.position();
  3173. let monitor_size = m.size();
  3174. // type annotations required for 32bit targets.
  3175. let window_position: LogicalPosition<i32> = window_position.to_logical(m.scale_factor());
  3176. monitor_pos.x <= window_position.x
  3177. && window_position.x <= monitor_pos.x + monitor_size.width as i32
  3178. && monitor_pos.y <= window_position.y
  3179. && window_position.y <= monitor_pos.y + monitor_size.height as i32
  3180. })
  3181. } else {
  3182. event_loop.primary_monitor()
  3183. };
  3184. if let Some(monitor) = monitor {
  3185. let desired_size = window_builder
  3186. .inner
  3187. .window
  3188. .inner_size
  3189. .unwrap_or_else(|| TaoPhysicalSize::new(800, 600).into());
  3190. let scale_factor = monitor.scale_factor();
  3191. #[allow(unused_mut)]
  3192. let mut window_size = window_builder
  3193. .inner
  3194. .window
  3195. .inner_size_constraints
  3196. .clamp(desired_size, scale_factor)
  3197. .to_physical::<u32>(scale_factor);
  3198. #[cfg(windows)]
  3199. {
  3200. if window_builder.inner.window.decorations {
  3201. use windows::Win32::UI::WindowsAndMessaging::{AdjustWindowRect, WS_OVERLAPPEDWINDOW};
  3202. let mut rect = windows::Win32::Foundation::RECT::default();
  3203. let result = unsafe { AdjustWindowRect(&mut rect, WS_OVERLAPPEDWINDOW, false) };
  3204. if result.is_ok() {
  3205. window_size.width += (rect.right - rect.left) as u32;
  3206. // rect.bottom is made out of shadow, and we don't care about it
  3207. window_size.height += -rect.top as u32;
  3208. }
  3209. }
  3210. }
  3211. let position = calculate_window_center_position(window_size, monitor);
  3212. let logical_position = position.to_logical::<f64>(scale_factor);
  3213. window_builder = window_builder.position(logical_position.x, logical_position.y);
  3214. }
  3215. }
  3216. let window = window_builder.inner.build(event_loop).unwrap();
  3217. #[cfg(feature = "tracing")]
  3218. {
  3219. drop(window_create_span);
  3220. context
  3221. .main_thread
  3222. .active_tracing_spans
  3223. .0
  3224. .borrow_mut()
  3225. .push(ActiveTracingSpan::WindowDraw {
  3226. id: window.id(),
  3227. span: window_draw_span,
  3228. });
  3229. }
  3230. context.window_id_map.insert(window.id(), window_id);
  3231. if let Some(handler) = after_window_creation {
  3232. let raw = RawWindow {
  3233. #[cfg(windows)]
  3234. hwnd: window.hwnd(),
  3235. #[cfg(any(
  3236. target_os = "linux",
  3237. target_os = "dragonfly",
  3238. target_os = "freebsd",
  3239. target_os = "netbsd",
  3240. target_os = "openbsd"
  3241. ))]
  3242. gtk_window: window.gtk_window(),
  3243. #[cfg(any(
  3244. target_os = "linux",
  3245. target_os = "dragonfly",
  3246. target_os = "freebsd",
  3247. target_os = "netbsd",
  3248. target_os = "openbsd"
  3249. ))]
  3250. default_vbox: window.default_vbox(),
  3251. _marker: &std::marker::PhantomData,
  3252. };
  3253. handler(raw);
  3254. }
  3255. let mut webviews = Vec::new();
  3256. if let Some(webview) = webview {
  3257. webviews.push(create_webview(
  3258. #[cfg(feature = "unstable")]
  3259. WebviewKind::WindowChild,
  3260. #[cfg(not(feature = "unstable"))]
  3261. WebviewKind::WindowContent,
  3262. &window,
  3263. Arc::new(Mutex::new(window_id)),
  3264. webview_id,
  3265. context,
  3266. webview,
  3267. )?);
  3268. }
  3269. let window = Arc::new(window);
  3270. #[cfg(windows)]
  3271. let surface = if is_window_transparent {
  3272. if let Ok(context) = softbuffer::Context::new(window.clone()) {
  3273. if let Ok(mut surface) = softbuffer::Surface::new(&context, window.clone()) {
  3274. clear_window_surface(&window, &mut surface);
  3275. Some(surface)
  3276. } else {
  3277. None
  3278. }
  3279. } else {
  3280. None
  3281. }
  3282. } else {
  3283. None
  3284. };
  3285. Ok(WindowWrapper {
  3286. label,
  3287. has_children: AtomicBool::new(false),
  3288. inner: Some(window),
  3289. webviews,
  3290. window_event_listeners,
  3291. #[cfg(windows)]
  3292. is_window_fullscreen,
  3293. #[cfg(windows)]
  3294. is_window_transparent,
  3295. #[cfg(windows)]
  3296. surface,
  3297. })
  3298. }
  3299. /// the kind of the webview
  3300. #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
  3301. enum WebviewKind {
  3302. // webview is the entire window content
  3303. WindowContent,
  3304. // webview is a child of the window, which can contain other webviews too
  3305. WindowChild,
  3306. }
  3307. #[derive(Debug, Clone)]
  3308. struct WebviewBounds {
  3309. x_rate: f32,
  3310. y_rate: f32,
  3311. width_rate: f32,
  3312. height_rate: f32,
  3313. }
  3314. fn create_webview<T: UserEvent>(
  3315. kind: WebviewKind,
  3316. window: &Window,
  3317. window_id: Arc<Mutex<WindowId>>,
  3318. id: WebviewId,
  3319. context: &Context<T>,
  3320. pending: PendingWebview<T, Wry<T>>,
  3321. ) -> Result<WebviewWrapper> {
  3322. #[allow(unused_mut)]
  3323. let PendingWebview {
  3324. webview_attributes,
  3325. uri_scheme_protocols,
  3326. label,
  3327. ipc_handler,
  3328. url,
  3329. ..
  3330. } = pending;
  3331. let builder = match kind {
  3332. #[cfg(not(any(
  3333. target_os = "windows",
  3334. target_os = "macos",
  3335. target_os = "ios",
  3336. target_os = "android"
  3337. )))]
  3338. WebviewKind::WindowChild => {
  3339. // only way to account for menu bar height, and also works for multiwebviews :)
  3340. let vbox = window.default_vbox().unwrap();
  3341. WebViewBuilder::new_gtk(vbox)
  3342. }
  3343. #[cfg(any(
  3344. target_os = "windows",
  3345. target_os = "macos",
  3346. target_os = "ios",
  3347. target_os = "android"
  3348. ))]
  3349. WebviewKind::WindowChild => WebViewBuilder::new_as_child(&window),
  3350. WebviewKind::WindowContent => {
  3351. #[cfg(any(
  3352. target_os = "windows",
  3353. target_os = "macos",
  3354. target_os = "ios",
  3355. target_os = "android"
  3356. ))]
  3357. let builder = WebViewBuilder::new(&window);
  3358. #[cfg(not(any(
  3359. target_os = "windows",
  3360. target_os = "macos",
  3361. target_os = "ios",
  3362. target_os = "android"
  3363. )))]
  3364. let builder = {
  3365. let vbox = window.default_vbox().unwrap();
  3366. WebViewBuilder::new_gtk(vbox)
  3367. };
  3368. builder
  3369. }
  3370. };
  3371. let mut webview_builder = builder
  3372. .with_focused(window.is_focused())
  3373. .with_url(&url)
  3374. .with_transparent(webview_attributes.transparent)
  3375. .with_accept_first_mouse(webview_attributes.accept_first_mouse)
  3376. .with_hotkeys_zoom(webview_attributes.zoom_hotkeys_enabled);
  3377. #[cfg(windows)]
  3378. if kind == WebviewKind::WindowContent {
  3379. webview_builder = webview_builder.with_initialization_script(undecorated_resizing::SCRIPT);
  3380. }
  3381. if webview_attributes.drag_drop_handler_enabled {
  3382. let proxy = context.proxy.clone();
  3383. let window_id_ = window_id.clone();
  3384. webview_builder = webview_builder.with_drag_drop_handler(move |event| {
  3385. let event = match event {
  3386. WryDragDropEvent::Enter {
  3387. paths,
  3388. position: (x, y),
  3389. } => DragDropEvent::Dragged {
  3390. paths,
  3391. position: PhysicalPosition::new(x as _, y as _),
  3392. },
  3393. WryDragDropEvent::Over { position: (x, y) } => DragDropEvent::DragOver {
  3394. position: PhysicalPosition::new(x as _, y as _),
  3395. },
  3396. WryDragDropEvent::Drop {
  3397. paths,
  3398. position: (x, y),
  3399. } => DragDropEvent::Dropped {
  3400. paths,
  3401. position: PhysicalPosition::new(x as _, y as _),
  3402. },
  3403. WryDragDropEvent::Leave => DragDropEvent::Cancelled,
  3404. _ => unimplemented!(),
  3405. };
  3406. let message = if kind == WebviewKind::WindowContent {
  3407. WebviewMessage::SynthesizedWindowEvent(SynthesizedWindowEvent::DragDrop(event))
  3408. } else {
  3409. WebviewMessage::WebviewEvent(WebviewEvent::DragDrop(event))
  3410. };
  3411. let _ = proxy.send_event(Message::Webview(*window_id_.lock().unwrap(), id, message));
  3412. true
  3413. });
  3414. }
  3415. if let Some(navigation_handler) = pending.navigation_handler {
  3416. webview_builder = webview_builder.with_navigation_handler(move |url| {
  3417. url
  3418. .parse()
  3419. .map(|url| navigation_handler(&url))
  3420. .unwrap_or(true)
  3421. });
  3422. }
  3423. let webview_bounds = if let Some(bounds) = webview_attributes.bounds {
  3424. let bounds: RectWrapper = bounds.into();
  3425. let bounds = bounds.0;
  3426. let scale_factor = window.scale_factor();
  3427. let position = bounds.position.to_logical::<f32>(scale_factor);
  3428. let size = bounds.size.to_logical::<f32>(scale_factor);
  3429. webview_builder = webview_builder.with_bounds(bounds);
  3430. let window_size = window.inner_size().to_logical::<f32>(scale_factor);
  3431. if webview_attributes.auto_resize {
  3432. Some(WebviewBounds {
  3433. x_rate: position.x / window_size.width,
  3434. y_rate: position.y / window_size.height,
  3435. width_rate: size.width / window_size.width,
  3436. height_rate: size.height / window_size.height,
  3437. })
  3438. } else {
  3439. None
  3440. }
  3441. } else {
  3442. #[cfg(feature = "unstable")]
  3443. {
  3444. webview_builder = webview_builder.with_bounds(wry::Rect {
  3445. position: LogicalPosition::new(0, 0).into(),
  3446. size: window.inner_size().into(),
  3447. });
  3448. Some(WebviewBounds {
  3449. x_rate: 0.,
  3450. y_rate: 0.,
  3451. width_rate: 1.,
  3452. height_rate: 1.,
  3453. })
  3454. }
  3455. #[cfg(not(feature = "unstable"))]
  3456. None
  3457. };
  3458. if let Some(download_handler) = pending.download_handler {
  3459. let download_handler_ = download_handler.clone();
  3460. webview_builder = webview_builder.with_download_started_handler(move |url, path| {
  3461. if let Ok(url) = url.parse() {
  3462. download_handler_(DownloadEvent::Requested {
  3463. url,
  3464. destination: path,
  3465. })
  3466. } else {
  3467. false
  3468. }
  3469. });
  3470. webview_builder = webview_builder.with_download_completed_handler(move |url, path, success| {
  3471. if let Ok(url) = url.parse() {
  3472. download_handler(DownloadEvent::Finished { url, path, success });
  3473. }
  3474. });
  3475. }
  3476. if let Some(page_load_handler) = pending.on_page_load_handler {
  3477. webview_builder = webview_builder.with_on_page_load_handler(move |event, url| {
  3478. let _ = url.parse().map(|url| {
  3479. page_load_handler(
  3480. url,
  3481. match event {
  3482. wry::PageLoadEvent::Started => tauri_runtime::webview::PageLoadEvent::Started,
  3483. wry::PageLoadEvent::Finished => tauri_runtime::webview::PageLoadEvent::Finished,
  3484. },
  3485. )
  3486. });
  3487. });
  3488. }
  3489. if let Some(user_agent) = webview_attributes.user_agent {
  3490. webview_builder = webview_builder.with_user_agent(&user_agent);
  3491. }
  3492. if let Some(proxy_url) = webview_attributes.proxy_url {
  3493. let config = parse_proxy_url(&proxy_url)?;
  3494. webview_builder = webview_builder.with_proxy_config(config);
  3495. }
  3496. #[cfg(windows)]
  3497. {
  3498. if let Some(additional_browser_args) = webview_attributes.additional_browser_args {
  3499. webview_builder = webview_builder.with_additional_browser_args(&additional_browser_args);
  3500. }
  3501. webview_builder = webview_builder.with_theme(match window.theme() {
  3502. TaoTheme::Dark => wry::Theme::Dark,
  3503. TaoTheme::Light => wry::Theme::Light,
  3504. _ => wry::Theme::Light,
  3505. });
  3506. }
  3507. #[cfg(windows)]
  3508. {
  3509. webview_builder = webview_builder.with_https_scheme(false);
  3510. }
  3511. webview_builder = webview_builder.with_ipc_handler(create_ipc_handler(
  3512. kind,
  3513. window_id.clone(),
  3514. id,
  3515. context.clone(),
  3516. label.clone(),
  3517. ipc_handler,
  3518. ));
  3519. for (scheme, protocol) in uri_scheme_protocols {
  3520. webview_builder =
  3521. webview_builder.with_asynchronous_custom_protocol(scheme, move |request, responder| {
  3522. protocol(
  3523. request,
  3524. Box::new(move |response| responder.respond(response)),
  3525. )
  3526. });
  3527. }
  3528. for script in webview_attributes.initialization_scripts {
  3529. webview_builder = webview_builder.with_initialization_script(&script);
  3530. }
  3531. let mut web_context = context
  3532. .main_thread
  3533. .web_context
  3534. .lock()
  3535. .expect("poisoned WebContext store");
  3536. let is_first_context = web_context.is_empty();
  3537. let automation_enabled = std::env::var("TAURI_WEBVIEW_AUTOMATION").as_deref() == Ok("true");
  3538. let web_context_key = // force a unique WebContext when automation is false;
  3539. // the context must be stored on the HashMap because it must outlive the WebView on macOS
  3540. if automation_enabled {
  3541. webview_attributes.data_directory.clone()
  3542. } else {
  3543. // unique key
  3544. let key = context.next_webcontext_id().to_string().into();
  3545. Some(key)
  3546. };
  3547. let entry = web_context.entry(web_context_key.clone());
  3548. let web_context = match entry {
  3549. Occupied(occupied) => occupied.into_mut(),
  3550. Vacant(vacant) => {
  3551. let mut web_context = WebContext::new(webview_attributes.data_directory);
  3552. web_context.set_allows_automation(if automation_enabled {
  3553. is_first_context
  3554. } else {
  3555. false
  3556. });
  3557. vacant.insert(web_context)
  3558. }
  3559. };
  3560. if webview_attributes.clipboard {
  3561. webview_builder.attrs.clipboard = true;
  3562. }
  3563. if webview_attributes.incognito {
  3564. webview_builder.attrs.incognito = true;
  3565. }
  3566. #[cfg(any(debug_assertions, feature = "devtools"))]
  3567. {
  3568. webview_builder = webview_builder.with_devtools(true);
  3569. }
  3570. #[cfg(target_os = "android")]
  3571. {
  3572. if let Some(on_webview_created) = pending.on_webview_created {
  3573. webview_builder = webview_builder.on_webview_created(move |ctx| {
  3574. on_webview_created(tauri_runtime::webview::CreationContext {
  3575. env: ctx.env,
  3576. activity: ctx.activity,
  3577. webview: ctx.webview,
  3578. })
  3579. });
  3580. }
  3581. }
  3582. let webview = webview_builder
  3583. .with_web_context(web_context)
  3584. .build()
  3585. .map_err(|e| Error::CreateWebview(Box::new(e)))?;
  3586. #[cfg(any(
  3587. target_os = "linux",
  3588. target_os = "dragonfly",
  3589. target_os = "freebsd",
  3590. target_os = "netbsd",
  3591. target_os = "openbsd"
  3592. ))]
  3593. if kind == WebviewKind::WindowContent {
  3594. undecorated_resizing::attach_resize_handler(&webview);
  3595. }
  3596. #[cfg(windows)]
  3597. if kind == WebviewKind::WindowContent {
  3598. let controller = webview.controller();
  3599. let proxy = context.proxy.clone();
  3600. let proxy_ = proxy.clone();
  3601. let window_id_ = window_id.clone();
  3602. let mut token = EventRegistrationToken::default();
  3603. unsafe {
  3604. controller.add_GotFocus(
  3605. &FocusChangedEventHandler::create(Box::new(move |_, _| {
  3606. let _ = proxy.send_event(Message::Webview(
  3607. *window_id_.lock().unwrap(),
  3608. id,
  3609. WebviewMessage::SynthesizedWindowEvent(SynthesizedWindowEvent::Focused(true)),
  3610. ));
  3611. Ok(())
  3612. })),
  3613. &mut token,
  3614. )
  3615. }
  3616. .unwrap();
  3617. unsafe {
  3618. controller.add_LostFocus(
  3619. &FocusChangedEventHandler::create(Box::new(move |_, _| {
  3620. let _ = proxy_.send_event(Message::Webview(
  3621. *window_id.lock().unwrap(),
  3622. id,
  3623. WebviewMessage::SynthesizedWindowEvent(SynthesizedWindowEvent::Focused(false)),
  3624. ));
  3625. Ok(())
  3626. })),
  3627. &mut token,
  3628. )
  3629. }
  3630. .unwrap();
  3631. }
  3632. Ok(WebviewWrapper {
  3633. label,
  3634. id,
  3635. inner: Rc::new(webview),
  3636. context_store: context.main_thread.web_context.clone(),
  3637. webview_event_listeners: Default::default(),
  3638. context_key: if automation_enabled {
  3639. None
  3640. } else {
  3641. web_context_key
  3642. },
  3643. bounds: Arc::new(Mutex::new(webview_bounds)),
  3644. })
  3645. }
  3646. /// Create a wry ipc handler from a tauri ipc handler.
  3647. fn create_ipc_handler<T: UserEvent>(
  3648. _kind: WebviewKind,
  3649. window_id: Arc<Mutex<WindowId>>,
  3650. webview_id: WebviewId,
  3651. context: Context<T>,
  3652. label: String,
  3653. ipc_handler: Option<WebviewIpcHandler<T, Wry<T>>>,
  3654. ) -> Box<IpcHandler> {
  3655. Box::new(move |request| {
  3656. #[cfg(windows)]
  3657. if _kind == WebviewKind::WindowContent
  3658. && undecorated_resizing::handle_request(context.clone(), *window_id.lock().unwrap(), &request)
  3659. {
  3660. return;
  3661. }
  3662. if let Some(handler) = &ipc_handler {
  3663. handler(
  3664. DetachedWebview {
  3665. label: label.clone(),
  3666. dispatcher: WryWebviewDispatcher {
  3667. window_id: window_id.clone(),
  3668. webview_id,
  3669. context: context.clone(),
  3670. },
  3671. },
  3672. request,
  3673. );
  3674. }
  3675. })
  3676. }
  3677. #[cfg(target_os = "macos")]
  3678. fn inner_size(
  3679. window: &Window,
  3680. webviews: &[WebviewWrapper],
  3681. has_children: bool,
  3682. ) -> TaoPhysicalSize<u32> {
  3683. if !has_children && webviews.len() > 0 {
  3684. use wry::WebViewExtMacOS;
  3685. let webview = webviews.first().unwrap();
  3686. let view_frame = unsafe { cocoa::appkit::NSView::frame(webview.webview()) };
  3687. let logical: TaoLogicalSize<f64> = (view_frame.size.width, view_frame.size.height).into();
  3688. return logical.to_physical(window.scale_factor());
  3689. }
  3690. window.inner_size()
  3691. }
  3692. #[cfg(not(target_os = "macos"))]
  3693. #[allow(unused_variables)]
  3694. fn inner_size(
  3695. window: &Window,
  3696. webviews: &[WebviewWrapper],
  3697. has_children: bool,
  3698. ) -> TaoPhysicalSize<u32> {
  3699. window.inner_size()
  3700. }
  3701. fn calculate_window_center_position(
  3702. window_size: TaoPhysicalSize<u32>,
  3703. target_monitor: MonitorHandle,
  3704. ) -> TaoPhysicalPosition<i32> {
  3705. #[cfg(windows)]
  3706. {
  3707. use tao::platform::windows::MonitorHandleExtWindows;
  3708. use windows::Win32::Graphics::Gdi::{GetMonitorInfoW, HMONITOR, MONITORINFO};
  3709. let mut monitor_info = MONITORINFO {
  3710. cbSize: std::mem::size_of::<MONITORINFO>() as u32,
  3711. ..Default::default()
  3712. };
  3713. let status = unsafe { GetMonitorInfoW(HMONITOR(target_monitor.hmonitor()), &mut monitor_info) };
  3714. if status.into() {
  3715. let available_width = monitor_info.rcWork.right - monitor_info.rcWork.left;
  3716. let available_height = monitor_info.rcWork.bottom - monitor_info.rcWork.top;
  3717. let x = (available_width - window_size.width as i32) / 2 + monitor_info.rcWork.left;
  3718. let y = (available_height - window_size.height as i32) / 2 + monitor_info.rcWork.top;
  3719. return TaoPhysicalPosition::new(x, y);
  3720. }
  3721. }
  3722. let screen_size = target_monitor.size();
  3723. let monitor_pos = target_monitor.position();
  3724. let x = (screen_size.width as i32 - window_size.width as i32) / 2 + monitor_pos.x;
  3725. let y = (screen_size.height as i32 - window_size.height as i32) / 2 + monitor_pos.y;
  3726. TaoPhysicalPosition::new(x, y)
  3727. }
  3728. #[cfg(windows)]
  3729. fn clear_window_surface(
  3730. window: &Window,
  3731. surface: &mut softbuffer::Surface<Arc<Window>, Arc<Window>>,
  3732. ) {
  3733. let size = window.inner_size();
  3734. if let (Some(width), Some(height)) = (
  3735. std::num::NonZeroU32::new(size.width),
  3736. std::num::NonZeroU32::new(size.height),
  3737. ) {
  3738. surface.resize(width, height).unwrap();
  3739. let mut buffer = surface.buffer_mut().unwrap();
  3740. buffer.fill(0);
  3741. let _ = buffer.present();
  3742. }
  3743. }