lib.rs 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973
  1. // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. //! The [`wry`] Tauri [`Runtime`].
  5. use tauri_runtime::{
  6. monitor::Monitor,
  7. webview::{
  8. FileDropEvent, FileDropHandler, RpcRequest, WebviewRpcHandler, WindowBuilder, WindowBuilderBase,
  9. },
  10. window::{
  11. dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
  12. DetachedWindow, PendingWindow, WindowEvent,
  13. },
  14. ClipboardManager, Dispatch, Error, GlobalShortcutManager, Icon, Params, Result, RunEvent,
  15. RunIteration, Runtime, RuntimeHandle, UserAttentionType,
  16. };
  17. #[cfg(feature = "menu")]
  18. use tauri_runtime::window::MenuEvent;
  19. #[cfg(feature = "system-tray")]
  20. use tauri_runtime::{SystemTray, SystemTrayEvent};
  21. #[cfg(windows)]
  22. use winapi::shared::windef::HWND;
  23. #[cfg(windows)]
  24. use wry::application::platform::windows::WindowBuilderExtWindows;
  25. #[cfg(feature = "system-tray")]
  26. use wry::application::system_tray::{SystemTray as WrySystemTray, SystemTrayBuilder};
  27. use tauri_utils::config::WindowConfig;
  28. use uuid::Uuid;
  29. use wry::{
  30. application::{
  31. accelerator::{Accelerator, AcceleratorId},
  32. clipboard::Clipboard,
  33. dpi::{
  34. LogicalPosition as WryLogicalPosition, LogicalSize as WryLogicalSize,
  35. PhysicalPosition as WryPhysicalPosition, PhysicalSize as WryPhysicalSize,
  36. Position as WryPosition, Size as WrySize,
  37. },
  38. event::{Event, WindowEvent as WryWindowEvent},
  39. event_loop::{ControlFlow, EventLoop, EventLoopProxy, EventLoopWindowTarget},
  40. monitor::MonitorHandle,
  41. platform::global_shortcut::{GlobalShortcut, ShortcutManager as WryShortcutManager},
  42. window::{
  43. Fullscreen, Icon as WindowIcon, UserAttentionType as WryUserAttentionType, Window,
  44. WindowBuilder as WryWindowBuilder, WindowId,
  45. },
  46. },
  47. webview::{
  48. FileDropEvent as WryFileDropEvent, RpcRequest as WryRpcRequest, RpcResponse, WebContext,
  49. WebView, WebViewBuilder,
  50. },
  51. };
  52. use std::{
  53. collections::HashMap,
  54. convert::TryFrom,
  55. fs::read,
  56. sync::{
  57. atomic::{AtomicBool, Ordering},
  58. mpsc::{channel, Sender},
  59. Arc, Mutex, MutexGuard,
  60. },
  61. thread::{current as current_thread, ThreadId},
  62. };
  63. #[cfg(any(feature = "menu", feature = "system-tray"))]
  64. mod menu;
  65. #[cfg(any(feature = "menu", feature = "system-tray"))]
  66. use menu::*;
  67. mod mime_type;
  68. use mime_type::MimeType;
  69. type MainTask = Arc<Mutex<Option<Box<dyn FnOnce() + Send>>>>;
  70. type CreateWebviewHandler =
  71. Box<dyn FnOnce(&EventLoopWindowTarget<Message>) -> Result<WebviewWrapper> + Send>;
  72. type WindowEventHandler = Box<dyn Fn(&WindowEvent) + Send>;
  73. type WindowEventListenersMap = Arc<Mutex<HashMap<Uuid, WindowEventHandler>>>;
  74. type WindowEventListeners = Arc<Mutex<HashMap<WindowId, WindowEventListenersMap>>>;
  75. type GlobalShortcutListeners = Arc<Mutex<HashMap<AcceleratorId, Box<dyn Fn() + Send>>>>;
  76. macro_rules! dispatcher_getter {
  77. ($self: ident, $message: expr) => {{
  78. if current_thread().id() == $self.context.main_thread_id
  79. && !$self.context.is_event_loop_running.load(Ordering::Relaxed)
  80. {
  81. panic!("This API cannot be called when the event loop is not running");
  82. }
  83. let (tx, rx) = channel();
  84. $self
  85. .context
  86. .proxy
  87. .send_event(Message::Window($self.window_id, $message(tx)))
  88. .map_err(|_| Error::FailedToSendMessage)?;
  89. rx.recv().unwrap()
  90. }};
  91. }
  92. macro_rules! getter {
  93. ($self: ident, $rx: expr, $message: expr) => {{
  94. if current_thread().id() == $self.context.main_thread_id
  95. && !$self.context.is_event_loop_running.load(Ordering::Relaxed)
  96. {
  97. panic!("This API cannot be called when the event loop is not running");
  98. }
  99. $self
  100. .context
  101. .proxy
  102. .send_event($message)
  103. .map_err(|_| Error::FailedToSendMessage)?;
  104. $rx.recv().unwrap()
  105. }};
  106. }
  107. #[derive(Clone)]
  108. struct EventLoopContext {
  109. main_thread_id: ThreadId,
  110. is_event_loop_running: Arc<AtomicBool>,
  111. proxy: EventLoopProxy<Message>,
  112. }
  113. #[derive(Debug, Clone)]
  114. struct GlobalShortcutWrapper(GlobalShortcut);
  115. unsafe impl Send for GlobalShortcutWrapper {}
  116. /// Wrapper around [`WryShortcutManager`].
  117. #[derive(Clone)]
  118. pub struct GlobalShortcutManagerHandle {
  119. context: EventLoopContext,
  120. shortcuts: Arc<Mutex<HashMap<String, (AcceleratorId, GlobalShortcutWrapper)>>>,
  121. listeners: GlobalShortcutListeners,
  122. }
  123. impl GlobalShortcutManager for GlobalShortcutManagerHandle {
  124. fn is_registered(&self, accelerator: &str) -> Result<bool> {
  125. let (tx, rx) = channel();
  126. Ok(getter!(
  127. self,
  128. rx,
  129. Message::GlobalShortcut(GlobalShortcutMessage::IsRegistered(
  130. accelerator.parse().expect("invalid accelerator"),
  131. tx
  132. ))
  133. ))
  134. }
  135. fn register<F: Fn() + Send + 'static>(&mut self, accelerator: &str, handler: F) -> Result<()> {
  136. let wry_accelerator: Accelerator = accelerator.parse().expect("invalid accelerator");
  137. let id = wry_accelerator.clone().id();
  138. let (tx, rx) = channel();
  139. let shortcut = getter!(
  140. self,
  141. rx,
  142. Message::GlobalShortcut(GlobalShortcutMessage::Register(wry_accelerator, tx))
  143. )?;
  144. self.listeners.lock().unwrap().insert(id, Box::new(handler));
  145. self
  146. .shortcuts
  147. .lock()
  148. .unwrap()
  149. .insert(accelerator.into(), (id, shortcut));
  150. Ok(())
  151. }
  152. fn unregister_all(&mut self) -> Result<()> {
  153. let (tx, rx) = channel();
  154. getter!(
  155. self,
  156. rx,
  157. Message::GlobalShortcut(GlobalShortcutMessage::UnregisterAll(tx))
  158. )?;
  159. self.listeners.lock().unwrap().clear();
  160. self.shortcuts.lock().unwrap().clear();
  161. Ok(())
  162. }
  163. fn unregister(&mut self, accelerator: &str) -> Result<()> {
  164. if let Some((accelerator_id, shortcut)) = self.shortcuts.lock().unwrap().remove(accelerator) {
  165. let (tx, rx) = channel();
  166. getter!(
  167. self,
  168. rx,
  169. Message::GlobalShortcut(GlobalShortcutMessage::Unregister(shortcut, tx))
  170. )?;
  171. self.listeners.lock().unwrap().remove(&accelerator_id);
  172. }
  173. Ok(())
  174. }
  175. }
  176. #[derive(Clone)]
  177. pub struct ClipboardManagerWrapper {
  178. context: EventLoopContext,
  179. }
  180. impl ClipboardManager for ClipboardManagerWrapper {
  181. fn read_text(&self) -> Result<Option<String>> {
  182. let (tx, rx) = channel();
  183. Ok(getter!(
  184. self,
  185. rx,
  186. Message::Clipboard(ClipboardMessage::ReadText(tx))
  187. ))
  188. }
  189. fn write_text<T: Into<String>>(&mut self, text: T) -> Result<()> {
  190. let (tx, rx) = channel();
  191. getter!(
  192. self,
  193. rx,
  194. Message::Clipboard(ClipboardMessage::WriteText(text.into(), tx))
  195. );
  196. Ok(())
  197. }
  198. }
  199. /// Wrapper around a [`wry::application::window::Icon`] that can be created from an [`Icon`].
  200. pub struct WryIcon(WindowIcon);
  201. fn icon_err<E: std::error::Error + Send + 'static>(e: E) -> Error {
  202. Error::InvalidIcon(Box::new(e))
  203. }
  204. impl TryFrom<Icon> for WryIcon {
  205. type Error = Error;
  206. fn try_from(icon: Icon) -> std::result::Result<Self, Self::Error> {
  207. let image_bytes = match icon {
  208. Icon::File(path) => read(path).map_err(icon_err)?,
  209. Icon::Raw(raw) => raw,
  210. _ => unimplemented!(),
  211. };
  212. let extension = infer::get(&image_bytes)
  213. .expect("could not determine icon extension")
  214. .extension();
  215. match extension {
  216. #[cfg(windows)]
  217. "ico" => {
  218. let icon_dir = ico::IconDir::read(std::io::Cursor::new(image_bytes)).map_err(icon_err)?;
  219. let entry = &icon_dir.entries()[0];
  220. let icon = WindowIcon::from_rgba(
  221. entry.decode().map_err(icon_err)?.rgba_data().to_vec(),
  222. entry.width(),
  223. entry.height(),
  224. )
  225. .map_err(icon_err)?;
  226. Ok(Self(icon))
  227. }
  228. #[cfg(target_os = "linux")]
  229. "png" => {
  230. let decoder = png::Decoder::new(std::io::Cursor::new(image_bytes));
  231. let (info, mut reader) = decoder.read_info().map_err(icon_err)?;
  232. let mut buffer = Vec::new();
  233. while let Ok(Some(row)) = reader.next_row() {
  234. buffer.extend(row);
  235. }
  236. let icon = WindowIcon::from_rgba(buffer, info.width, info.height).map_err(icon_err)?;
  237. Ok(Self(icon))
  238. }
  239. _ => panic!(
  240. "image `{}` extension not supported; please file a Tauri feature request",
  241. extension
  242. ),
  243. }
  244. }
  245. }
  246. struct WindowEventWrapper(Option<WindowEvent>);
  247. impl<'a> From<&WryWindowEvent<'a>> for WindowEventWrapper {
  248. fn from(event: &WryWindowEvent<'a>) -> Self {
  249. let event = match event {
  250. WryWindowEvent::Resized(size) => WindowEvent::Resized(PhysicalSizeWrapper(*size).into()),
  251. WryWindowEvent::Moved(position) => {
  252. WindowEvent::Moved(PhysicalPositionWrapper(*position).into())
  253. }
  254. WryWindowEvent::CloseRequested => WindowEvent::CloseRequested,
  255. WryWindowEvent::Destroyed => WindowEvent::Destroyed,
  256. WryWindowEvent::Focused(focused) => WindowEvent::Focused(*focused),
  257. WryWindowEvent::ScaleFactorChanged {
  258. scale_factor,
  259. new_inner_size,
  260. } => WindowEvent::ScaleFactorChanged {
  261. scale_factor: *scale_factor,
  262. new_inner_size: PhysicalSizeWrapper(**new_inner_size).into(),
  263. },
  264. _ => return Self(None),
  265. };
  266. Self(Some(event))
  267. }
  268. }
  269. pub struct MonitorHandleWrapper(MonitorHandle);
  270. impl From<MonitorHandleWrapper> for Monitor {
  271. fn from(monitor: MonitorHandleWrapper) -> Monitor {
  272. Self {
  273. name: monitor.0.name(),
  274. position: PhysicalPositionWrapper(monitor.0.position()).into(),
  275. size: PhysicalSizeWrapper(monitor.0.size()).into(),
  276. scale_factor: monitor.0.scale_factor(),
  277. }
  278. }
  279. }
  280. struct PhysicalPositionWrapper<T>(WryPhysicalPosition<T>);
  281. impl<T> From<PhysicalPositionWrapper<T>> for PhysicalPosition<T> {
  282. fn from(position: PhysicalPositionWrapper<T>) -> Self {
  283. Self {
  284. x: position.0.x,
  285. y: position.0.y,
  286. }
  287. }
  288. }
  289. impl<T> From<PhysicalPosition<T>> for PhysicalPositionWrapper<T> {
  290. fn from(position: PhysicalPosition<T>) -> Self {
  291. Self(WryPhysicalPosition {
  292. x: position.x,
  293. y: position.y,
  294. })
  295. }
  296. }
  297. struct LogicalPositionWrapper<T>(WryLogicalPosition<T>);
  298. impl<T> From<LogicalPosition<T>> for LogicalPositionWrapper<T> {
  299. fn from(position: LogicalPosition<T>) -> Self {
  300. Self(WryLogicalPosition {
  301. x: position.x,
  302. y: position.y,
  303. })
  304. }
  305. }
  306. struct PhysicalSizeWrapper<T>(WryPhysicalSize<T>);
  307. impl<T> From<PhysicalSizeWrapper<T>> for PhysicalSize<T> {
  308. fn from(size: PhysicalSizeWrapper<T>) -> Self {
  309. Self {
  310. width: size.0.width,
  311. height: size.0.height,
  312. }
  313. }
  314. }
  315. impl<T> From<PhysicalSize<T>> for PhysicalSizeWrapper<T> {
  316. fn from(size: PhysicalSize<T>) -> Self {
  317. Self(WryPhysicalSize {
  318. width: size.width,
  319. height: size.height,
  320. })
  321. }
  322. }
  323. struct LogicalSizeWrapper<T>(WryLogicalSize<T>);
  324. impl<T> From<LogicalSize<T>> for LogicalSizeWrapper<T> {
  325. fn from(size: LogicalSize<T>) -> Self {
  326. Self(WryLogicalSize {
  327. width: size.width,
  328. height: size.height,
  329. })
  330. }
  331. }
  332. struct SizeWrapper(WrySize);
  333. impl From<Size> for SizeWrapper {
  334. fn from(size: Size) -> Self {
  335. match size {
  336. Size::Logical(s) => Self(WrySize::Logical(LogicalSizeWrapper::from(s).0)),
  337. Size::Physical(s) => Self(WrySize::Physical(PhysicalSizeWrapper::from(s).0)),
  338. }
  339. }
  340. }
  341. struct PositionWrapper(WryPosition);
  342. impl From<Position> for PositionWrapper {
  343. fn from(position: Position) -> Self {
  344. match position {
  345. Position::Logical(s) => Self(WryPosition::Logical(LogicalPositionWrapper::from(s).0)),
  346. Position::Physical(s) => Self(WryPosition::Physical(PhysicalPositionWrapper::from(s).0)),
  347. }
  348. }
  349. }
  350. #[derive(Debug, Clone)]
  351. struct UserAttentionTypeWrapper(WryUserAttentionType);
  352. impl From<UserAttentionType> for UserAttentionTypeWrapper {
  353. fn from(request_type: UserAttentionType) -> UserAttentionTypeWrapper {
  354. let o = match request_type {
  355. UserAttentionType::Critical => WryUserAttentionType::Critical,
  356. UserAttentionType::Informational => WryUserAttentionType::Informational,
  357. };
  358. Self(o)
  359. }
  360. }
  361. #[derive(Debug, Clone, Default)]
  362. pub struct WindowBuilderWrapper {
  363. inner: WryWindowBuilder,
  364. center: bool,
  365. #[cfg(feature = "menu")]
  366. menu: Menu<u16>,
  367. }
  368. // safe since `menu_items` are read only here
  369. unsafe impl Send for WindowBuilderWrapper {}
  370. impl WindowBuilderBase for WindowBuilderWrapper {}
  371. impl WindowBuilder for WindowBuilderWrapper {
  372. fn new() -> Self {
  373. Default::default()
  374. }
  375. fn with_config(config: WindowConfig) -> Self {
  376. let mut window = WindowBuilderWrapper::new()
  377. .title(config.title.to_string())
  378. .inner_size(config.width, config.height)
  379. .visible(config.visible)
  380. .resizable(config.resizable)
  381. .decorations(config.decorations)
  382. .maximized(config.maximized)
  383. .fullscreen(config.fullscreen)
  384. .transparent(config.transparent)
  385. .always_on_top(config.always_on_top)
  386. .skip_taskbar(config.skip_taskbar);
  387. if let (Some(min_width), Some(min_height)) = (config.min_width, config.min_height) {
  388. window = window.min_inner_size(min_width, min_height);
  389. }
  390. if let (Some(max_width), Some(max_height)) = (config.max_width, config.max_height) {
  391. window = window.max_inner_size(max_width, max_height);
  392. }
  393. if let (Some(x), Some(y)) = (config.x, config.y) {
  394. window = window.position(x, y);
  395. }
  396. if config.focus {
  397. window = window.focus();
  398. }
  399. window
  400. }
  401. #[cfg(feature = "menu")]
  402. fn menu<I: MenuId>(mut self, menu: Menu<I>) -> Self {
  403. self.menu = convert_menu_id(Menu::new(), menu);
  404. self
  405. }
  406. fn center(mut self) -> Self {
  407. self.center = true;
  408. self
  409. }
  410. fn position(mut self, x: f64, y: f64) -> Self {
  411. self.inner = self.inner.with_position(WryLogicalPosition::new(x, y));
  412. self
  413. }
  414. fn inner_size(mut self, width: f64, height: f64) -> Self {
  415. self.inner = self
  416. .inner
  417. .with_inner_size(WryLogicalSize::new(width, height));
  418. self
  419. }
  420. fn min_inner_size(mut self, min_width: f64, min_height: f64) -> Self {
  421. self.inner = self
  422. .inner
  423. .with_min_inner_size(WryLogicalSize::new(min_width, min_height));
  424. self
  425. }
  426. fn max_inner_size(mut self, max_width: f64, max_height: f64) -> Self {
  427. self.inner = self
  428. .inner
  429. .with_max_inner_size(WryLogicalSize::new(max_width, max_height));
  430. self
  431. }
  432. fn resizable(mut self, resizable: bool) -> Self {
  433. self.inner = self.inner.with_resizable(resizable);
  434. self
  435. }
  436. fn title<S: Into<String>>(mut self, title: S) -> Self {
  437. self.inner = self.inner.with_title(title.into());
  438. self
  439. }
  440. fn fullscreen(mut self, fullscreen: bool) -> Self {
  441. self.inner = if fullscreen {
  442. self
  443. .inner
  444. .with_fullscreen(Some(Fullscreen::Borderless(None)))
  445. } else {
  446. self.inner.with_fullscreen(None)
  447. };
  448. self
  449. }
  450. fn focus(mut self) -> Self {
  451. self.inner = self.inner.with_focus();
  452. self
  453. }
  454. fn maximized(mut self, maximized: bool) -> Self {
  455. self.inner = self.inner.with_maximized(maximized);
  456. self
  457. }
  458. fn visible(mut self, visible: bool) -> Self {
  459. self.inner = self.inner.with_visible(visible);
  460. self
  461. }
  462. fn transparent(mut self, transparent: bool) -> Self {
  463. self.inner = self.inner.with_transparent(transparent);
  464. self
  465. }
  466. fn decorations(mut self, decorations: bool) -> Self {
  467. self.inner = self.inner.with_decorations(decorations);
  468. self
  469. }
  470. fn always_on_top(mut self, always_on_top: bool) -> Self {
  471. self.inner = self.inner.with_always_on_top(always_on_top);
  472. self
  473. }
  474. #[cfg(windows)]
  475. fn parent_window(mut self, parent: HWND) -> Self {
  476. self.inner = self.inner.with_parent_window(parent);
  477. self
  478. }
  479. #[cfg(windows)]
  480. fn owner_window(mut self, owner: HWND) -> Self {
  481. self.inner = self.inner.with_owner_window(owner);
  482. self
  483. }
  484. fn icon(mut self, icon: Icon) -> Result<Self> {
  485. self.inner = self
  486. .inner
  487. .with_window_icon(Some(WryIcon::try_from(icon)?.0));
  488. Ok(self)
  489. }
  490. fn skip_taskbar(mut self, skip: bool) -> Self {
  491. self.inner = self.inner.with_skip_taskbar(skip);
  492. self
  493. }
  494. fn has_icon(&self) -> bool {
  495. self.inner.window.window_icon.is_some()
  496. }
  497. #[cfg(feature = "menu")]
  498. fn has_menu(&self) -> bool {
  499. self.inner.window.window_menu.is_some()
  500. }
  501. }
  502. pub struct RpcRequestWrapper(WryRpcRequest);
  503. impl From<RpcRequestWrapper> for RpcRequest {
  504. fn from(request: RpcRequestWrapper) -> Self {
  505. Self {
  506. command: request.0.method,
  507. params: request.0.params,
  508. }
  509. }
  510. }
  511. pub struct FileDropEventWrapper(WryFileDropEvent);
  512. impl From<FileDropEventWrapper> for FileDropEvent {
  513. fn from(event: FileDropEventWrapper) -> Self {
  514. match event.0 {
  515. WryFileDropEvent::Hovered(paths) => FileDropEvent::Hovered(paths),
  516. WryFileDropEvent::Dropped(paths) => FileDropEvent::Dropped(paths),
  517. WryFileDropEvent::Cancelled => FileDropEvent::Cancelled,
  518. }
  519. }
  520. }
  521. #[cfg(windows)]
  522. struct Hwnd(HWND);
  523. #[cfg(windows)]
  524. unsafe impl Send for Hwnd {}
  525. #[derive(Debug, Clone)]
  526. enum WindowMessage {
  527. // Getters
  528. ScaleFactor(Sender<f64>),
  529. InnerPosition(Sender<Result<PhysicalPosition<i32>>>),
  530. OuterPosition(Sender<Result<PhysicalPosition<i32>>>),
  531. InnerSize(Sender<PhysicalSize<u32>>),
  532. OuterSize(Sender<PhysicalSize<u32>>),
  533. IsFullscreen(Sender<bool>),
  534. IsMaximized(Sender<bool>),
  535. IsDecorated(Sender<bool>),
  536. IsResizable(Sender<bool>),
  537. IsVisible(Sender<bool>),
  538. #[cfg(feature = "menu")]
  539. IsMenuVisible(Sender<bool>),
  540. CurrentMonitor(Sender<Option<MonitorHandle>>),
  541. PrimaryMonitor(Sender<Option<MonitorHandle>>),
  542. AvailableMonitors(Sender<Vec<MonitorHandle>>),
  543. #[cfg(windows)]
  544. Hwnd(Sender<Hwnd>),
  545. // Setters
  546. Center(Sender<Result<()>>),
  547. RequestUserAttention(Option<UserAttentionTypeWrapper>),
  548. SetResizable(bool),
  549. SetTitle(String),
  550. Maximize,
  551. Unmaximize,
  552. Minimize,
  553. Unminimize,
  554. #[cfg(feature = "menu")]
  555. ShowMenu,
  556. #[cfg(feature = "menu")]
  557. HideMenu,
  558. Show,
  559. Hide,
  560. Close,
  561. SetDecorations(bool),
  562. SetAlwaysOnTop(bool),
  563. SetSize(Size),
  564. SetMinSize(Option<Size>),
  565. SetMaxSize(Option<Size>),
  566. SetPosition(Position),
  567. SetFullscreen(bool),
  568. SetFocus,
  569. SetIcon(WindowIcon),
  570. SetSkipTaskbar(bool),
  571. DragWindow,
  572. #[cfg(feature = "menu")]
  573. UpdateMenuItem(u16, menu::MenuUpdate),
  574. }
  575. #[derive(Debug, Clone)]
  576. enum WebviewMessage {
  577. EvaluateScript(String),
  578. Print,
  579. }
  580. #[cfg(feature = "system-tray")]
  581. #[derive(Clone)]
  582. pub(crate) enum TrayMessage {
  583. UpdateItem(u16, menu::MenuUpdate),
  584. UpdateIcon(Icon),
  585. #[cfg(windows)]
  586. Remove,
  587. }
  588. #[derive(Clone)]
  589. pub(crate) enum GlobalShortcutMessage {
  590. IsRegistered(Accelerator, Sender<bool>),
  591. Register(Accelerator, Sender<Result<GlobalShortcutWrapper>>),
  592. Unregister(GlobalShortcutWrapper, Sender<Result<()>>),
  593. UnregisterAll(Sender<Result<()>>),
  594. }
  595. #[derive(Clone)]
  596. pub(crate) enum ClipboardMessage {
  597. WriteText(String, Sender<()>),
  598. ReadText(Sender<Option<String>>),
  599. }
  600. #[derive(Clone)]
  601. pub(crate) enum Message {
  602. Task(MainTask),
  603. Window(WindowId, WindowMessage),
  604. Webview(WindowId, WebviewMessage),
  605. #[cfg(feature = "system-tray")]
  606. Tray(TrayMessage),
  607. CreateWebview(Arc<Mutex<Option<CreateWebviewHandler>>>, Sender<WindowId>),
  608. GlobalShortcut(GlobalShortcutMessage),
  609. Clipboard(ClipboardMessage),
  610. }
  611. #[derive(Clone)]
  612. struct DispatcherContext {
  613. main_thread_id: ThreadId,
  614. is_event_loop_running: Arc<AtomicBool>,
  615. proxy: EventLoopProxy<Message>,
  616. window_event_listeners: WindowEventListeners,
  617. #[cfg(feature = "menu")]
  618. menu_event_listeners: MenuEventListeners,
  619. }
  620. /// The Tauri [`Dispatch`] for [`Wry`].
  621. #[derive(Clone)]
  622. pub struct WryDispatcher {
  623. window_id: WindowId,
  624. context: DispatcherContext,
  625. }
  626. impl Dispatch for WryDispatcher {
  627. type Runtime = Wry;
  628. type WindowBuilder = WindowBuilderWrapper;
  629. fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
  630. self
  631. .context
  632. .proxy
  633. .send_event(Message::Task(Arc::new(Mutex::new(Some(Box::new(f))))))
  634. .map_err(|_| Error::FailedToSendMessage)
  635. }
  636. fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) -> Uuid {
  637. let id = Uuid::new_v4();
  638. self
  639. .context
  640. .window_event_listeners
  641. .lock()
  642. .unwrap()
  643. .get(&self.window_id)
  644. .unwrap()
  645. .lock()
  646. .unwrap()
  647. .insert(id, Box::new(f));
  648. id
  649. }
  650. #[cfg(feature = "menu")]
  651. fn on_menu_event<F: Fn(&MenuEvent) + Send + 'static>(&self, f: F) -> Uuid {
  652. let id = Uuid::new_v4();
  653. self
  654. .context
  655. .menu_event_listeners
  656. .lock()
  657. .unwrap()
  658. .get(&self.window_id)
  659. .unwrap()
  660. .lock()
  661. .unwrap()
  662. .insert(id, Box::new(f));
  663. id
  664. }
  665. // Getters
  666. fn scale_factor(&self) -> Result<f64> {
  667. Ok(dispatcher_getter!(self, WindowMessage::ScaleFactor))
  668. }
  669. fn inner_position(&self) -> Result<PhysicalPosition<i32>> {
  670. dispatcher_getter!(self, WindowMessage::InnerPosition)
  671. }
  672. fn outer_position(&self) -> Result<PhysicalPosition<i32>> {
  673. dispatcher_getter!(self, WindowMessage::OuterPosition)
  674. }
  675. fn inner_size(&self) -> Result<PhysicalSize<u32>> {
  676. Ok(dispatcher_getter!(self, WindowMessage::InnerSize))
  677. }
  678. fn outer_size(&self) -> Result<PhysicalSize<u32>> {
  679. Ok(dispatcher_getter!(self, WindowMessage::OuterSize))
  680. }
  681. fn is_fullscreen(&self) -> Result<bool> {
  682. Ok(dispatcher_getter!(self, WindowMessage::IsFullscreen))
  683. }
  684. fn is_maximized(&self) -> Result<bool> {
  685. Ok(dispatcher_getter!(self, WindowMessage::IsMaximized))
  686. }
  687. /// Gets the window’s current decoration state.
  688. fn is_decorated(&self) -> Result<bool> {
  689. Ok(dispatcher_getter!(self, WindowMessage::IsDecorated))
  690. }
  691. /// Gets the window’s current resizable state.
  692. fn is_resizable(&self) -> Result<bool> {
  693. Ok(dispatcher_getter!(self, WindowMessage::IsResizable))
  694. }
  695. fn is_visible(&self) -> Result<bool> {
  696. Ok(dispatcher_getter!(self, WindowMessage::IsVisible))
  697. }
  698. #[cfg(feature = "menu")]
  699. fn is_menu_visible(&self) -> Result<bool> {
  700. Ok(dispatcher_getter!(self, WindowMessage::IsMenuVisible))
  701. }
  702. fn current_monitor(&self) -> Result<Option<Monitor>> {
  703. Ok(
  704. dispatcher_getter!(self, WindowMessage::CurrentMonitor)
  705. .map(|m| MonitorHandleWrapper(m).into()),
  706. )
  707. }
  708. fn primary_monitor(&self) -> Result<Option<Monitor>> {
  709. Ok(
  710. dispatcher_getter!(self, WindowMessage::PrimaryMonitor)
  711. .map(|m| MonitorHandleWrapper(m).into()),
  712. )
  713. }
  714. fn available_monitors(&self) -> Result<Vec<Monitor>> {
  715. Ok(
  716. dispatcher_getter!(self, WindowMessage::AvailableMonitors)
  717. .into_iter()
  718. .map(|m| MonitorHandleWrapper(m).into())
  719. .collect(),
  720. )
  721. }
  722. #[cfg(windows)]
  723. fn hwnd(&self) -> Result<HWND> {
  724. Ok(dispatcher_getter!(self, WindowMessage::Hwnd).0)
  725. }
  726. // Setters
  727. fn center(&self) -> Result<()> {
  728. dispatcher_getter!(self, WindowMessage::Center)
  729. }
  730. fn print(&self) -> Result<()> {
  731. self
  732. .context
  733. .proxy
  734. .send_event(Message::Webview(self.window_id, WebviewMessage::Print))
  735. .map_err(|_| Error::FailedToSendMessage)
  736. }
  737. fn request_user_attention(&self, request_type: Option<UserAttentionType>) -> Result<()> {
  738. self
  739. .context
  740. .proxy
  741. .send_event(Message::Window(
  742. self.window_id,
  743. WindowMessage::RequestUserAttention(request_type.map(Into::into)),
  744. ))
  745. .map_err(|_| Error::FailedToSendMessage)
  746. }
  747. // Creates a window by dispatching a message to the event loop.
  748. // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock.
  749. fn create_window<P: Params<Runtime = Self::Runtime>>(
  750. &mut self,
  751. pending: PendingWindow<P>,
  752. ) -> Result<DetachedWindow<P>> {
  753. let (tx, rx) = channel();
  754. let label = pending.label.clone();
  755. let context = self.context.clone();
  756. self
  757. .context
  758. .proxy
  759. .send_event(Message::CreateWebview(
  760. Arc::new(Mutex::new(Some(Box::new(move |event_loop| {
  761. create_webview(event_loop, context, pending)
  762. })))),
  763. tx,
  764. ))
  765. .map_err(|_| Error::FailedToSendMessage)?;
  766. let window_id = rx.recv().unwrap();
  767. let dispatcher = WryDispatcher {
  768. window_id,
  769. context: self.context.clone(),
  770. };
  771. Ok(DetachedWindow { label, dispatcher })
  772. }
  773. fn set_resizable(&self, resizable: bool) -> Result<()> {
  774. self
  775. .context
  776. .proxy
  777. .send_event(Message::Window(
  778. self.window_id,
  779. WindowMessage::SetResizable(resizable),
  780. ))
  781. .map_err(|_| Error::FailedToSendMessage)
  782. }
  783. fn set_title<S: Into<String>>(&self, title: S) -> Result<()> {
  784. self
  785. .context
  786. .proxy
  787. .send_event(Message::Window(
  788. self.window_id,
  789. WindowMessage::SetTitle(title.into()),
  790. ))
  791. .map_err(|_| Error::FailedToSendMessage)
  792. }
  793. fn maximize(&self) -> Result<()> {
  794. self
  795. .context
  796. .proxy
  797. .send_event(Message::Window(self.window_id, WindowMessage::Maximize))
  798. .map_err(|_| Error::FailedToSendMessage)
  799. }
  800. fn unmaximize(&self) -> Result<()> {
  801. self
  802. .context
  803. .proxy
  804. .send_event(Message::Window(self.window_id, WindowMessage::Unmaximize))
  805. .map_err(|_| Error::FailedToSendMessage)
  806. }
  807. fn minimize(&self) -> Result<()> {
  808. self
  809. .context
  810. .proxy
  811. .send_event(Message::Window(self.window_id, WindowMessage::Minimize))
  812. .map_err(|_| Error::FailedToSendMessage)
  813. }
  814. fn unminimize(&self) -> Result<()> {
  815. self
  816. .context
  817. .proxy
  818. .send_event(Message::Window(self.window_id, WindowMessage::Unminimize))
  819. .map_err(|_| Error::FailedToSendMessage)
  820. }
  821. #[cfg(feature = "menu")]
  822. fn show_menu(&self) -> Result<()> {
  823. self
  824. .context
  825. .proxy
  826. .send_event(Message::Window(self.window_id, WindowMessage::ShowMenu))
  827. .map_err(|_| Error::FailedToSendMessage)
  828. }
  829. #[cfg(feature = "menu")]
  830. fn hide_menu(&self) -> Result<()> {
  831. self
  832. .context
  833. .proxy
  834. .send_event(Message::Window(self.window_id, WindowMessage::HideMenu))
  835. .map_err(|_| Error::FailedToSendMessage)
  836. }
  837. fn show(&self) -> Result<()> {
  838. self
  839. .context
  840. .proxy
  841. .send_event(Message::Window(self.window_id, WindowMessage::Show))
  842. .map_err(|_| Error::FailedToSendMessage)
  843. }
  844. fn hide(&self) -> Result<()> {
  845. self
  846. .context
  847. .proxy
  848. .send_event(Message::Window(self.window_id, WindowMessage::Hide))
  849. .map_err(|_| Error::FailedToSendMessage)
  850. }
  851. fn close(&self) -> Result<()> {
  852. self
  853. .context
  854. .proxy
  855. .send_event(Message::Window(self.window_id, WindowMessage::Close))
  856. .map_err(|_| Error::FailedToSendMessage)
  857. }
  858. fn set_decorations(&self, decorations: bool) -> Result<()> {
  859. self
  860. .context
  861. .proxy
  862. .send_event(Message::Window(
  863. self.window_id,
  864. WindowMessage::SetDecorations(decorations),
  865. ))
  866. .map_err(|_| Error::FailedToSendMessage)
  867. }
  868. fn set_always_on_top(&self, always_on_top: bool) -> Result<()> {
  869. self
  870. .context
  871. .proxy
  872. .send_event(Message::Window(
  873. self.window_id,
  874. WindowMessage::SetAlwaysOnTop(always_on_top),
  875. ))
  876. .map_err(|_| Error::FailedToSendMessage)
  877. }
  878. fn set_size(&self, size: Size) -> Result<()> {
  879. self
  880. .context
  881. .proxy
  882. .send_event(Message::Window(
  883. self.window_id,
  884. WindowMessage::SetSize(size),
  885. ))
  886. .map_err(|_| Error::FailedToSendMessage)
  887. }
  888. fn set_min_size(&self, size: Option<Size>) -> Result<()> {
  889. self
  890. .context
  891. .proxy
  892. .send_event(Message::Window(
  893. self.window_id,
  894. WindowMessage::SetMinSize(size),
  895. ))
  896. .map_err(|_| Error::FailedToSendMessage)
  897. }
  898. fn set_max_size(&self, size: Option<Size>) -> Result<()> {
  899. self
  900. .context
  901. .proxy
  902. .send_event(Message::Window(
  903. self.window_id,
  904. WindowMessage::SetMaxSize(size),
  905. ))
  906. .map_err(|_| Error::FailedToSendMessage)
  907. }
  908. fn set_position(&self, position: Position) -> Result<()> {
  909. self
  910. .context
  911. .proxy
  912. .send_event(Message::Window(
  913. self.window_id,
  914. WindowMessage::SetPosition(position),
  915. ))
  916. .map_err(|_| Error::FailedToSendMessage)
  917. }
  918. fn set_fullscreen(&self, fullscreen: bool) -> Result<()> {
  919. self
  920. .context
  921. .proxy
  922. .send_event(Message::Window(
  923. self.window_id,
  924. WindowMessage::SetFullscreen(fullscreen),
  925. ))
  926. .map_err(|_| Error::FailedToSendMessage)
  927. }
  928. fn set_focus(&self) -> Result<()> {
  929. self
  930. .context
  931. .proxy
  932. .send_event(Message::Window(self.window_id, WindowMessage::SetFocus))
  933. .map_err(|_| Error::FailedToSendMessage)
  934. }
  935. fn set_icon(&self, icon: Icon) -> Result<()> {
  936. self
  937. .context
  938. .proxy
  939. .send_event(Message::Window(
  940. self.window_id,
  941. WindowMessage::SetIcon(WryIcon::try_from(icon)?.0),
  942. ))
  943. .map_err(|_| Error::FailedToSendMessage)
  944. }
  945. fn set_skip_taskbar(&self, skip: bool) -> Result<()> {
  946. self
  947. .context
  948. .proxy
  949. .send_event(Message::Window(
  950. self.window_id,
  951. WindowMessage::SetSkipTaskbar(skip),
  952. ))
  953. .map_err(|_| Error::FailedToSendMessage)
  954. }
  955. fn start_dragging(&self) -> Result<()> {
  956. self
  957. .context
  958. .proxy
  959. .send_event(Message::Window(self.window_id, WindowMessage::DragWindow))
  960. .map_err(|_| Error::FailedToSendMessage)
  961. }
  962. fn eval_script<S: Into<String>>(&self, script: S) -> Result<()> {
  963. self
  964. .context
  965. .proxy
  966. .send_event(Message::Webview(
  967. self.window_id,
  968. WebviewMessage::EvaluateScript(script.into()),
  969. ))
  970. .map_err(|_| Error::FailedToSendMessage)
  971. }
  972. #[cfg(feature = "menu")]
  973. fn update_menu_item(&self, id: u16, update: menu::MenuUpdate) -> Result<()> {
  974. self
  975. .context
  976. .proxy
  977. .send_event(Message::Window(
  978. self.window_id,
  979. WindowMessage::UpdateMenuItem(id, update),
  980. ))
  981. .map_err(|_| Error::FailedToSendMessage)
  982. }
  983. }
  984. #[cfg(feature = "system-tray")]
  985. #[derive(Clone, Default)]
  986. struct TrayContext {
  987. tray: Arc<Mutex<Option<Arc<Mutex<WrySystemTray>>>>>,
  988. listeners: SystemTrayEventListeners,
  989. items: SystemTrayItems,
  990. }
  991. struct WebviewWrapper {
  992. label: String,
  993. inner: WebView,
  994. #[cfg(feature = "menu")]
  995. menu_items: HashMap<u16, WryCustomMenuItem>,
  996. #[cfg(feature = "menu")]
  997. is_menu_visible: AtomicBool,
  998. }
  999. /// A Tauri [`Runtime`] wrapper around wry.
  1000. pub struct Wry {
  1001. main_thread_id: ThreadId,
  1002. global_shortcut_manager: Arc<Mutex<WryShortcutManager>>,
  1003. global_shortcut_manager_handle: GlobalShortcutManagerHandle,
  1004. clipboard_manager: Arc<Mutex<Clipboard>>,
  1005. clipboard_manager_handle: ClipboardManagerWrapper,
  1006. is_event_loop_running: Arc<AtomicBool>,
  1007. event_loop: EventLoop<Message>,
  1008. webviews: Arc<Mutex<HashMap<WindowId, WebviewWrapper>>>,
  1009. window_event_listeners: WindowEventListeners,
  1010. #[cfg(feature = "menu")]
  1011. menu_event_listeners: MenuEventListeners,
  1012. #[cfg(feature = "system-tray")]
  1013. tray_context: TrayContext,
  1014. }
  1015. /// A handle to the Wry runtime.
  1016. #[derive(Clone)]
  1017. pub struct WryHandle {
  1018. dispatcher_context: DispatcherContext,
  1019. }
  1020. impl RuntimeHandle for WryHandle {
  1021. type Runtime = Wry;
  1022. // Creates a window by dispatching a message to the event loop.
  1023. // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock.
  1024. fn create_window<P: Params<Runtime = Self::Runtime>>(
  1025. &self,
  1026. pending: PendingWindow<P>,
  1027. ) -> Result<DetachedWindow<P>> {
  1028. let (tx, rx) = channel();
  1029. let label = pending.label.clone();
  1030. let dispatcher_context = self.dispatcher_context.clone();
  1031. self
  1032. .dispatcher_context
  1033. .proxy
  1034. .send_event(Message::CreateWebview(
  1035. Arc::new(Mutex::new(Some(Box::new(move |event_loop| {
  1036. create_webview(event_loop, dispatcher_context, pending)
  1037. })))),
  1038. tx,
  1039. ))
  1040. .map_err(|_| Error::FailedToSendMessage)?;
  1041. let window_id = rx.recv().unwrap();
  1042. let dispatcher = WryDispatcher {
  1043. window_id,
  1044. context: self.dispatcher_context.clone(),
  1045. };
  1046. Ok(DetachedWindow { label, dispatcher })
  1047. }
  1048. #[cfg(all(windows, feature = "system-tray"))]
  1049. fn remove_system_tray(&self) -> Result<()> {
  1050. self
  1051. .dispatcher_context
  1052. .proxy
  1053. .send_event(Message::Tray(TrayMessage::Remove))
  1054. .map_err(|_| Error::FailedToSendMessage)
  1055. }
  1056. }
  1057. impl Runtime for Wry {
  1058. type Dispatcher = WryDispatcher;
  1059. type Handle = WryHandle;
  1060. type GlobalShortcutManager = GlobalShortcutManagerHandle;
  1061. type ClipboardManager = ClipboardManagerWrapper;
  1062. #[cfg(feature = "system-tray")]
  1063. type TrayHandler = SystemTrayHandle;
  1064. fn new() -> Result<Self> {
  1065. let event_loop = EventLoop::<Message>::with_user_event();
  1066. let proxy = event_loop.create_proxy();
  1067. let main_thread_id = current_thread().id();
  1068. let is_event_loop_running = Arc::new(AtomicBool::default());
  1069. let event_loop_context = EventLoopContext {
  1070. main_thread_id,
  1071. is_event_loop_running: is_event_loop_running.clone(),
  1072. proxy,
  1073. };
  1074. let global_shortcut_manager = WryShortcutManager::new(&event_loop);
  1075. let global_shortcut_listeners = GlobalShortcutListeners::default();
  1076. let clipboard_manager = Clipboard::new();
  1077. let clipboard_manager_handle = ClipboardManagerWrapper {
  1078. context: event_loop_context.clone(),
  1079. };
  1080. Ok(Self {
  1081. main_thread_id,
  1082. global_shortcut_manager: Arc::new(Mutex::new(global_shortcut_manager)),
  1083. global_shortcut_manager_handle: GlobalShortcutManagerHandle {
  1084. context: event_loop_context,
  1085. shortcuts: Default::default(),
  1086. listeners: global_shortcut_listeners,
  1087. },
  1088. clipboard_manager: Arc::new(Mutex::new(clipboard_manager)),
  1089. clipboard_manager_handle,
  1090. is_event_loop_running,
  1091. event_loop,
  1092. webviews: Default::default(),
  1093. window_event_listeners: Default::default(),
  1094. #[cfg(feature = "menu")]
  1095. menu_event_listeners: Default::default(),
  1096. #[cfg(feature = "system-tray")]
  1097. tray_context: Default::default(),
  1098. })
  1099. }
  1100. fn handle(&self) -> Self::Handle {
  1101. WryHandle {
  1102. dispatcher_context: DispatcherContext {
  1103. main_thread_id: self.main_thread_id,
  1104. is_event_loop_running: self.is_event_loop_running.clone(),
  1105. proxy: self.event_loop.create_proxy(),
  1106. window_event_listeners: self.window_event_listeners.clone(),
  1107. #[cfg(feature = "menu")]
  1108. menu_event_listeners: self.menu_event_listeners.clone(),
  1109. },
  1110. }
  1111. }
  1112. fn global_shortcut_manager(&self) -> Self::GlobalShortcutManager {
  1113. self.global_shortcut_manager_handle.clone()
  1114. }
  1115. fn clipboard_manager(&self) -> Self::ClipboardManager {
  1116. self.clipboard_manager_handle.clone()
  1117. }
  1118. fn create_window<P: Params<Runtime = Self>>(
  1119. &self,
  1120. pending: PendingWindow<P>,
  1121. ) -> Result<DetachedWindow<P>> {
  1122. let label = pending.label.clone();
  1123. let proxy = self.event_loop.create_proxy();
  1124. let webview = create_webview(
  1125. &self.event_loop,
  1126. DispatcherContext {
  1127. main_thread_id: self.main_thread_id,
  1128. is_event_loop_running: self.is_event_loop_running.clone(),
  1129. proxy: proxy.clone(),
  1130. window_event_listeners: self.window_event_listeners.clone(),
  1131. #[cfg(feature = "menu")]
  1132. menu_event_listeners: self.menu_event_listeners.clone(),
  1133. },
  1134. pending,
  1135. )?;
  1136. let dispatcher = WryDispatcher {
  1137. window_id: webview.inner.window().id(),
  1138. context: DispatcherContext {
  1139. main_thread_id: self.main_thread_id,
  1140. is_event_loop_running: self.is_event_loop_running.clone(),
  1141. proxy,
  1142. window_event_listeners: self.window_event_listeners.clone(),
  1143. #[cfg(feature = "menu")]
  1144. menu_event_listeners: self.menu_event_listeners.clone(),
  1145. },
  1146. };
  1147. self
  1148. .webviews
  1149. .lock()
  1150. .unwrap()
  1151. .insert(webview.inner.window().id(), webview);
  1152. Ok(DetachedWindow { label, dispatcher })
  1153. }
  1154. #[cfg(feature = "system-tray")]
  1155. fn system_tray<I: MenuId>(&self, system_tray: SystemTray<I>) -> Result<Self::TrayHandler> {
  1156. let icon = system_tray
  1157. .icon
  1158. .expect("tray icon not set")
  1159. .into_tray_icon();
  1160. let mut items = HashMap::new();
  1161. let tray = SystemTrayBuilder::new(
  1162. icon,
  1163. system_tray
  1164. .menu
  1165. .map(|menu| to_wry_context_menu(&mut items, menu)),
  1166. )
  1167. .build(&self.event_loop)
  1168. .map_err(|e| Error::SystemTray(Box::new(e)))?;
  1169. *self.tray_context.items.lock().unwrap() = items;
  1170. *self.tray_context.tray.lock().unwrap() = Some(Arc::new(Mutex::new(tray)));
  1171. Ok(SystemTrayHandle {
  1172. proxy: self.event_loop.create_proxy(),
  1173. })
  1174. }
  1175. #[cfg(feature = "system-tray")]
  1176. fn on_system_tray_event<F: Fn(&SystemTrayEvent) + Send + 'static>(&mut self, f: F) -> Uuid {
  1177. let id = Uuid::new_v4();
  1178. self
  1179. .tray_context
  1180. .listeners
  1181. .lock()
  1182. .unwrap()
  1183. .insert(id, Box::new(f));
  1184. id
  1185. }
  1186. #[cfg(any(target_os = "windows", target_os = "macos"))]
  1187. fn run_iteration<F: Fn(RunEvent) + 'static>(&mut self, callback: F) -> RunIteration {
  1188. use wry::application::platform::run_return::EventLoopExtRunReturn;
  1189. let webviews = self.webviews.clone();
  1190. let window_event_listeners = self.window_event_listeners.clone();
  1191. #[cfg(feature = "menu")]
  1192. let menu_event_listeners = self.menu_event_listeners.clone();
  1193. #[cfg(feature = "system-tray")]
  1194. let tray_context = self.tray_context.clone();
  1195. let global_shortcut_manager = self.global_shortcut_manager.clone();
  1196. let global_shortcut_manager_handle = self.global_shortcut_manager_handle.clone();
  1197. let clipboard_manager = self.clipboard_manager.clone();
  1198. let mut iteration = RunIteration::default();
  1199. self.is_event_loop_running.store(true, Ordering::Relaxed);
  1200. self
  1201. .event_loop
  1202. .run_return(|event, event_loop, control_flow| {
  1203. if let Event::MainEventsCleared = &event {
  1204. *control_flow = ControlFlow::Exit;
  1205. }
  1206. iteration = handle_event_loop(
  1207. event,
  1208. event_loop,
  1209. control_flow,
  1210. EventLoopIterationContext {
  1211. callback: &callback,
  1212. webviews: webviews.lock().expect("poisoned webview collection"),
  1213. window_event_listeners: &window_event_listeners,
  1214. global_shortcut_manager: global_shortcut_manager.clone(),
  1215. global_shortcut_manager_handle: &global_shortcut_manager_handle,
  1216. clipboard_manager: clipboard_manager.clone(),
  1217. #[cfg(feature = "menu")]
  1218. menu_event_listeners: &menu_event_listeners,
  1219. #[cfg(feature = "system-tray")]
  1220. tray_context: &tray_context,
  1221. },
  1222. );
  1223. });
  1224. self.is_event_loop_running.store(false, Ordering::Relaxed);
  1225. iteration
  1226. }
  1227. fn run<F: Fn(RunEvent) + 'static>(self, callback: F) {
  1228. self.is_event_loop_running.store(true, Ordering::Relaxed);
  1229. let webviews = self.webviews.clone();
  1230. let window_event_listeners = self.window_event_listeners.clone();
  1231. #[cfg(feature = "menu")]
  1232. let menu_event_listeners = self.menu_event_listeners.clone();
  1233. #[cfg(feature = "system-tray")]
  1234. let tray_context = self.tray_context;
  1235. let global_shortcut_manager = self.global_shortcut_manager.clone();
  1236. let global_shortcut_manager_handle = self.global_shortcut_manager_handle.clone();
  1237. let clipboard_manager = self.clipboard_manager.clone();
  1238. self.event_loop.run(move |event, event_loop, control_flow| {
  1239. handle_event_loop(
  1240. event,
  1241. event_loop,
  1242. control_flow,
  1243. EventLoopIterationContext {
  1244. callback: &callback,
  1245. webviews: webviews.lock().expect("poisoned webview collection"),
  1246. window_event_listeners: &window_event_listeners,
  1247. global_shortcut_manager: global_shortcut_manager.clone(),
  1248. global_shortcut_manager_handle: &global_shortcut_manager_handle,
  1249. clipboard_manager: clipboard_manager.clone(),
  1250. #[cfg(feature = "menu")]
  1251. menu_event_listeners: &menu_event_listeners,
  1252. #[cfg(feature = "system-tray")]
  1253. tray_context: &tray_context,
  1254. },
  1255. );
  1256. })
  1257. }
  1258. }
  1259. struct EventLoopIterationContext<'a> {
  1260. callback: &'a (dyn Fn(RunEvent) + 'static),
  1261. webviews: MutexGuard<'a, HashMap<WindowId, WebviewWrapper>>,
  1262. window_event_listeners: &'a WindowEventListeners,
  1263. global_shortcut_manager: Arc<Mutex<WryShortcutManager>>,
  1264. global_shortcut_manager_handle: &'a GlobalShortcutManagerHandle,
  1265. clipboard_manager: Arc<Mutex<Clipboard>>,
  1266. #[cfg(feature = "menu")]
  1267. menu_event_listeners: &'a MenuEventListeners,
  1268. #[cfg(feature = "system-tray")]
  1269. tray_context: &'a TrayContext,
  1270. }
  1271. fn handle_event_loop(
  1272. event: Event<Message>,
  1273. event_loop: &EventLoopWindowTarget<Message>,
  1274. control_flow: &mut ControlFlow,
  1275. context: EventLoopIterationContext<'_>,
  1276. ) -> RunIteration {
  1277. let EventLoopIterationContext {
  1278. callback,
  1279. mut webviews,
  1280. window_event_listeners,
  1281. global_shortcut_manager,
  1282. global_shortcut_manager_handle,
  1283. clipboard_manager,
  1284. #[cfg(feature = "menu")]
  1285. menu_event_listeners,
  1286. #[cfg(feature = "system-tray")]
  1287. tray_context,
  1288. } = context;
  1289. *control_flow = ControlFlow::Wait;
  1290. match event {
  1291. Event::GlobalShortcutEvent(accelerator_id) => {
  1292. for (id, handler) in &*global_shortcut_manager_handle.listeners.lock().unwrap() {
  1293. if accelerator_id == *id {
  1294. handler();
  1295. }
  1296. }
  1297. }
  1298. #[cfg(feature = "menu")]
  1299. Event::MenuEvent {
  1300. window_id,
  1301. menu_id,
  1302. origin: MenuType::MenuBar,
  1303. } => {
  1304. let window_id = window_id.unwrap(); // always Some on MenuBar event
  1305. let event = MenuEvent {
  1306. menu_item_id: menu_id.0,
  1307. };
  1308. let listeners = menu_event_listeners.lock().unwrap();
  1309. let window_menu_event_listeners = listeners.get(&window_id).cloned().unwrap_or_default();
  1310. for handler in window_menu_event_listeners.lock().unwrap().values() {
  1311. handler(&event);
  1312. }
  1313. }
  1314. #[cfg(feature = "system-tray")]
  1315. Event::MenuEvent {
  1316. window_id: _,
  1317. menu_id,
  1318. origin: MenuType::ContextMenu,
  1319. } => {
  1320. let event = SystemTrayEvent::MenuItemClick(menu_id.0);
  1321. for handler in tray_context.listeners.lock().unwrap().values() {
  1322. handler(&event);
  1323. }
  1324. }
  1325. #[cfg(feature = "system-tray")]
  1326. Event::TrayEvent {
  1327. bounds,
  1328. event,
  1329. position: _cursor_position,
  1330. } => {
  1331. let (position, size) = (
  1332. PhysicalPositionWrapper(bounds.position).into(),
  1333. PhysicalSizeWrapper(bounds.size).into(),
  1334. );
  1335. let event = match event {
  1336. TrayEvent::LeftClick => SystemTrayEvent::LeftClick { position, size },
  1337. TrayEvent::RightClick => SystemTrayEvent::RightClick { position, size },
  1338. TrayEvent::DoubleClick => SystemTrayEvent::DoubleClick { position, size },
  1339. };
  1340. for handler in tray_context.listeners.lock().unwrap().values() {
  1341. handler(&event);
  1342. }
  1343. }
  1344. Event::WindowEvent { event, window_id } => {
  1345. if let Some(event) = WindowEventWrapper::from(&event).0 {
  1346. for handler in window_event_listeners
  1347. .lock()
  1348. .unwrap()
  1349. .get(&window_id)
  1350. .unwrap()
  1351. .lock()
  1352. .unwrap()
  1353. .values()
  1354. {
  1355. handler(&event);
  1356. }
  1357. }
  1358. match event {
  1359. WryWindowEvent::CloseRequested => {
  1360. on_window_close(
  1361. callback,
  1362. window_id,
  1363. &mut webviews,
  1364. control_flow,
  1365. #[cfg(feature = "menu")]
  1366. menu_event_listeners.clone(),
  1367. );
  1368. }
  1369. WryWindowEvent::Resized(_) => {
  1370. if let Err(e) = webviews[&window_id].inner.resize() {
  1371. eprintln!("{}", e);
  1372. }
  1373. }
  1374. _ => {}
  1375. }
  1376. }
  1377. Event::UserEvent(message) => match message {
  1378. Message::Task(task) => {
  1379. if let Some(task) = task.lock().unwrap().take() {
  1380. task();
  1381. }
  1382. }
  1383. Message::Window(id, window_message) => {
  1384. if let Some(webview) = webviews.get_mut(&id) {
  1385. let window = webview.inner.window();
  1386. match window_message {
  1387. // Getters
  1388. WindowMessage::ScaleFactor(tx) => tx.send(window.scale_factor()).unwrap(),
  1389. WindowMessage::InnerPosition(tx) => tx
  1390. .send(
  1391. window
  1392. .inner_position()
  1393. .map(|p| PhysicalPositionWrapper(p).into())
  1394. .map_err(|_| Error::FailedToSendMessage),
  1395. )
  1396. .unwrap(),
  1397. WindowMessage::OuterPosition(tx) => tx
  1398. .send(
  1399. window
  1400. .outer_position()
  1401. .map(|p| PhysicalPositionWrapper(p).into())
  1402. .map_err(|_| Error::FailedToSendMessage),
  1403. )
  1404. .unwrap(),
  1405. WindowMessage::InnerSize(tx) => tx
  1406. .send(PhysicalSizeWrapper(window.inner_size()).into())
  1407. .unwrap(),
  1408. WindowMessage::OuterSize(tx) => tx
  1409. .send(PhysicalSizeWrapper(window.outer_size()).into())
  1410. .unwrap(),
  1411. WindowMessage::IsFullscreen(tx) => tx.send(window.fullscreen().is_some()).unwrap(),
  1412. WindowMessage::IsMaximized(tx) => tx.send(window.is_maximized()).unwrap(),
  1413. WindowMessage::IsDecorated(tx) => tx.send(window.is_decorated()).unwrap(),
  1414. WindowMessage::IsResizable(tx) => tx.send(window.is_resizable()).unwrap(),
  1415. WindowMessage::IsVisible(tx) => tx.send(window.is_visible()).unwrap(),
  1416. #[cfg(feature = "menu")]
  1417. WindowMessage::IsMenuVisible(tx) => tx
  1418. .send(webview.is_menu_visible.load(Ordering::Relaxed))
  1419. .unwrap(),
  1420. WindowMessage::CurrentMonitor(tx) => tx.send(window.current_monitor()).unwrap(),
  1421. WindowMessage::PrimaryMonitor(tx) => tx.send(window.primary_monitor()).unwrap(),
  1422. WindowMessage::AvailableMonitors(tx) => {
  1423. tx.send(window.available_monitors().collect()).unwrap()
  1424. }
  1425. #[cfg(windows)]
  1426. WindowMessage::Hwnd(tx) => {
  1427. use wry::application::platform::windows::WindowExtWindows;
  1428. tx.send(Hwnd(window.hwnd() as HWND)).unwrap()
  1429. }
  1430. // Setters
  1431. WindowMessage::Center(tx) => {
  1432. tx.send(center_window(window)).unwrap();
  1433. }
  1434. WindowMessage::RequestUserAttention(request_type) => {
  1435. window.request_user_attention(request_type.map(|r| r.0));
  1436. }
  1437. WindowMessage::SetResizable(resizable) => window.set_resizable(resizable),
  1438. WindowMessage::SetTitle(title) => window.set_title(&title),
  1439. WindowMessage::Maximize => window.set_maximized(true),
  1440. WindowMessage::Unmaximize => window.set_maximized(false),
  1441. WindowMessage::Minimize => window.set_minimized(true),
  1442. WindowMessage::Unminimize => window.set_minimized(false),
  1443. #[cfg(feature = "menu")]
  1444. WindowMessage::ShowMenu => {
  1445. window.show_menu();
  1446. webview.is_menu_visible.store(true, Ordering::Relaxed);
  1447. }
  1448. #[cfg(feature = "menu")]
  1449. WindowMessage::HideMenu => {
  1450. window.hide_menu();
  1451. webview.is_menu_visible.store(false, Ordering::Relaxed);
  1452. }
  1453. WindowMessage::Show => window.set_visible(true),
  1454. WindowMessage::Hide => window.set_visible(false),
  1455. WindowMessage::Close => {
  1456. for handler in window_event_listeners
  1457. .lock()
  1458. .unwrap()
  1459. .get(&window.id())
  1460. .unwrap()
  1461. .lock()
  1462. .unwrap()
  1463. .values()
  1464. {
  1465. handler(&WindowEvent::CloseRequested);
  1466. }
  1467. on_window_close(
  1468. callback,
  1469. id,
  1470. &mut webviews,
  1471. control_flow,
  1472. #[cfg(feature = "menu")]
  1473. menu_event_listeners.clone(),
  1474. );
  1475. }
  1476. WindowMessage::SetDecorations(decorations) => window.set_decorations(decorations),
  1477. WindowMessage::SetAlwaysOnTop(always_on_top) => window.set_always_on_top(always_on_top),
  1478. WindowMessage::SetSize(size) => {
  1479. window.set_inner_size(SizeWrapper::from(size).0);
  1480. }
  1481. WindowMessage::SetMinSize(size) => {
  1482. window.set_min_inner_size(size.map(|s| SizeWrapper::from(s).0));
  1483. }
  1484. WindowMessage::SetMaxSize(size) => {
  1485. window.set_max_inner_size(size.map(|s| SizeWrapper::from(s).0));
  1486. }
  1487. WindowMessage::SetPosition(position) => {
  1488. window.set_outer_position(PositionWrapper::from(position).0)
  1489. }
  1490. WindowMessage::SetFullscreen(fullscreen) => {
  1491. if fullscreen {
  1492. window.set_fullscreen(Some(Fullscreen::Borderless(None)))
  1493. } else {
  1494. window.set_fullscreen(None)
  1495. }
  1496. }
  1497. WindowMessage::SetFocus => {
  1498. window.set_focus();
  1499. }
  1500. WindowMessage::SetIcon(icon) => {
  1501. window.set_window_icon(Some(icon));
  1502. }
  1503. WindowMessage::SetSkipTaskbar(skip) => {
  1504. window.set_skip_taskbar(skip);
  1505. }
  1506. WindowMessage::DragWindow => {
  1507. let _ = window.drag_window();
  1508. }
  1509. #[cfg(feature = "menu")]
  1510. WindowMessage::UpdateMenuItem(id, update) => {
  1511. let item = webview
  1512. .menu_items
  1513. .get_mut(&id)
  1514. .expect("menu item not found");
  1515. match update {
  1516. MenuUpdate::SetEnabled(enabled) => item.set_enabled(enabled),
  1517. MenuUpdate::SetTitle(title) => item.set_title(&title),
  1518. MenuUpdate::SetSelected(selected) => item.set_selected(selected),
  1519. #[cfg(target_os = "macos")]
  1520. MenuUpdate::SetNativeImage(image) => {
  1521. item.set_native_image(NativeImageWrapper::from(image).0)
  1522. }
  1523. }
  1524. }
  1525. }
  1526. }
  1527. }
  1528. Message::Webview(id, webview_message) => {
  1529. if let Some(webview) = webviews.get_mut(&id) {
  1530. match webview_message {
  1531. WebviewMessage::EvaluateScript(script) => {
  1532. if let Err(e) = webview.inner.evaluate_script(&script) {
  1533. eprintln!("{}", e);
  1534. }
  1535. }
  1536. WebviewMessage::Print => {
  1537. let _ = webview.inner.print();
  1538. }
  1539. }
  1540. }
  1541. }
  1542. Message::CreateWebview(handler, sender) => {
  1543. let handler = {
  1544. let mut lock = handler.lock().expect("poisoned create webview handler");
  1545. std::mem::take(&mut *lock).unwrap()
  1546. };
  1547. match handler(event_loop) {
  1548. Ok(webview) => {
  1549. let window_id = webview.inner.window().id();
  1550. webviews.insert(window_id, webview);
  1551. sender.send(window_id).unwrap();
  1552. }
  1553. Err(e) => {
  1554. eprintln!("{}", e);
  1555. }
  1556. }
  1557. }
  1558. #[cfg(feature = "system-tray")]
  1559. Message::Tray(tray_message) => match tray_message {
  1560. TrayMessage::UpdateItem(menu_id, update) => {
  1561. let mut tray = tray_context.items.as_ref().lock().unwrap();
  1562. let item = tray.get_mut(&menu_id).expect("menu item not found");
  1563. match update {
  1564. MenuUpdate::SetEnabled(enabled) => item.set_enabled(enabled),
  1565. MenuUpdate::SetTitle(title) => item.set_title(&title),
  1566. MenuUpdate::SetSelected(selected) => item.set_selected(selected),
  1567. #[cfg(target_os = "macos")]
  1568. MenuUpdate::SetNativeImage(image) => {
  1569. item.set_native_image(NativeImageWrapper::from(image).0)
  1570. }
  1571. }
  1572. }
  1573. TrayMessage::UpdateIcon(icon) => {
  1574. if let Some(tray) = &*tray_context.tray.lock().unwrap() {
  1575. tray.lock().unwrap().set_icon(icon.into_tray_icon());
  1576. }
  1577. }
  1578. #[cfg(windows)]
  1579. TrayMessage::Remove => {
  1580. if let Some(tray) = tray_context.tray.lock().unwrap().as_ref() {
  1581. use wry::application::platform::windows::SystemTrayExtWindows;
  1582. tray.lock().unwrap().remove();
  1583. }
  1584. }
  1585. },
  1586. Message::GlobalShortcut(message) => match message {
  1587. GlobalShortcutMessage::IsRegistered(accelerator, tx) => tx
  1588. .send(
  1589. global_shortcut_manager
  1590. .lock()
  1591. .unwrap()
  1592. .is_registered(&accelerator),
  1593. )
  1594. .unwrap(),
  1595. GlobalShortcutMessage::Register(accelerator, tx) => tx
  1596. .send(
  1597. global_shortcut_manager
  1598. .lock()
  1599. .unwrap()
  1600. .register(accelerator)
  1601. .map(GlobalShortcutWrapper)
  1602. .map_err(|e| Error::GlobalShortcut(Box::new(e))),
  1603. )
  1604. .unwrap(),
  1605. GlobalShortcutMessage::Unregister(shortcut, tx) => tx
  1606. .send(
  1607. global_shortcut_manager
  1608. .lock()
  1609. .unwrap()
  1610. .unregister(shortcut.0)
  1611. .map_err(|e| Error::GlobalShortcut(Box::new(e))),
  1612. )
  1613. .unwrap(),
  1614. GlobalShortcutMessage::UnregisterAll(tx) => tx
  1615. .send(
  1616. global_shortcut_manager
  1617. .lock()
  1618. .unwrap()
  1619. .unregister_all()
  1620. .map_err(|e| Error::GlobalShortcut(Box::new(e))),
  1621. )
  1622. .unwrap(),
  1623. },
  1624. Message::Clipboard(message) => match message {
  1625. ClipboardMessage::WriteText(text, tx) => {
  1626. clipboard_manager.lock().unwrap().write_text(text);
  1627. tx.send(()).unwrap();
  1628. }
  1629. ClipboardMessage::ReadText(tx) => tx
  1630. .send(clipboard_manager.lock().unwrap().read_text())
  1631. .unwrap(),
  1632. },
  1633. },
  1634. _ => (),
  1635. }
  1636. RunIteration {
  1637. webview_count: webviews.len(),
  1638. }
  1639. }
  1640. fn on_window_close<'a>(
  1641. callback: &'a (dyn Fn(RunEvent) + 'static),
  1642. window_id: WindowId,
  1643. webviews: &mut MutexGuard<'a, HashMap<WindowId, WebviewWrapper>>,
  1644. control_flow: &mut ControlFlow,
  1645. #[cfg(feature = "menu")] menu_event_listeners: MenuEventListeners,
  1646. ) {
  1647. if let Some(webview) = webviews.remove(&window_id) {
  1648. #[cfg(feature = "menu")]
  1649. menu_event_listeners.lock().unwrap().remove(&window_id);
  1650. callback(RunEvent::WindowClose(webview.label));
  1651. }
  1652. if webviews.is_empty() {
  1653. *control_flow = ControlFlow::Exit;
  1654. callback(RunEvent::Exit);
  1655. }
  1656. }
  1657. fn center_window(window: &Window) -> Result<()> {
  1658. if let Some(monitor) = window.current_monitor() {
  1659. let screen_size = monitor.size();
  1660. let window_size = window.inner_size();
  1661. let x = (screen_size.width - window_size.width) / 2;
  1662. let y = (screen_size.height - window_size.height) / 2;
  1663. window.set_outer_position(WryPhysicalPosition::new(x, y));
  1664. Ok(())
  1665. } else {
  1666. Err(Error::FailedToGetMonitor)
  1667. }
  1668. }
  1669. fn create_webview<P: Params<Runtime = Wry>>(
  1670. event_loop: &EventLoopWindowTarget<Message>,
  1671. context: DispatcherContext,
  1672. pending: PendingWindow<P>,
  1673. ) -> Result<WebviewWrapper> {
  1674. #[allow(unused_mut)]
  1675. let PendingWindow {
  1676. webview_attributes,
  1677. mut window_builder,
  1678. rpc_handler,
  1679. file_drop_handler,
  1680. label,
  1681. url,
  1682. ..
  1683. } = pending;
  1684. let is_window_transparent = window_builder.inner.window.transparent;
  1685. #[cfg(feature = "menu")]
  1686. let menu_items = {
  1687. let mut menu_items = HashMap::new();
  1688. let menu = to_wry_menu(&mut menu_items, window_builder.menu);
  1689. window_builder.inner = window_builder.inner.with_menu(menu);
  1690. menu_items
  1691. };
  1692. let window = window_builder.inner.build(event_loop).unwrap();
  1693. context
  1694. .window_event_listeners
  1695. .lock()
  1696. .unwrap()
  1697. .insert(window.id(), WindowEventListenersMap::default());
  1698. #[cfg(feature = "menu")]
  1699. context
  1700. .menu_event_listeners
  1701. .lock()
  1702. .unwrap()
  1703. .insert(window.id(), WindowMenuEventListeners::default());
  1704. if window_builder.center {
  1705. let _ = center_window(&window);
  1706. }
  1707. let mut webview_builder = WebViewBuilder::new(window)
  1708. .map_err(|e| Error::CreateWebview(Box::new(e)))?
  1709. .with_url(&url)
  1710. .unwrap() // safe to unwrap because we validate the URL beforehand
  1711. .with_transparent(is_window_transparent);
  1712. if let Some(handler) = rpc_handler {
  1713. webview_builder =
  1714. webview_builder.with_rpc_handler(create_rpc_handler(context.clone(), label.clone(), handler));
  1715. }
  1716. if let Some(handler) = file_drop_handler {
  1717. webview_builder = webview_builder.with_file_drop_handler(create_file_drop_handler(
  1718. context,
  1719. label.clone(),
  1720. handler,
  1721. ));
  1722. }
  1723. for (scheme, protocol) in webview_attributes.uri_scheme_protocols {
  1724. webview_builder = webview_builder.with_custom_protocol(scheme, move |_window, url| {
  1725. protocol(url)
  1726. .map(|data| {
  1727. let mime_type = MimeType::parse(&data, url);
  1728. (data, mime_type)
  1729. })
  1730. .map_err(|_| wry::Error::InitScriptError)
  1731. });
  1732. }
  1733. let context = WebContext::new(webview_attributes.data_directory);
  1734. webview_builder = webview_builder.with_web_context(&context);
  1735. for script in webview_attributes.initialization_scripts {
  1736. webview_builder = webview_builder.with_initialization_script(&script);
  1737. }
  1738. let webview = webview_builder
  1739. .build()
  1740. .map_err(|e| Error::CreateWebview(Box::new(e)))?;
  1741. Ok(WebviewWrapper {
  1742. label: format!("{}", label),
  1743. inner: webview,
  1744. #[cfg(feature = "menu")]
  1745. menu_items,
  1746. #[cfg(feature = "menu")]
  1747. is_menu_visible: AtomicBool::new(true),
  1748. })
  1749. }
  1750. /// Create a wry rpc handler from a tauri rpc handler.
  1751. fn create_rpc_handler<P: Params<Runtime = Wry>>(
  1752. context: DispatcherContext,
  1753. label: P::Label,
  1754. handler: WebviewRpcHandler<P>,
  1755. ) -> Box<dyn Fn(&Window, WryRpcRequest) -> Option<RpcResponse> + 'static> {
  1756. Box::new(move |window, request| {
  1757. handler(
  1758. DetachedWindow {
  1759. dispatcher: WryDispatcher {
  1760. window_id: window.id(),
  1761. context: context.clone(),
  1762. },
  1763. label: label.clone(),
  1764. },
  1765. RpcRequestWrapper(request).into(),
  1766. );
  1767. None
  1768. })
  1769. }
  1770. /// Create a wry file drop handler from a tauri file drop handler.
  1771. fn create_file_drop_handler<P: Params<Runtime = Wry>>(
  1772. context: DispatcherContext,
  1773. label: P::Label,
  1774. handler: FileDropHandler<P>,
  1775. ) -> Box<dyn Fn(&Window, WryFileDropEvent) -> bool + 'static> {
  1776. Box::new(move |window, event| {
  1777. handler(
  1778. FileDropEventWrapper(event).into(),
  1779. DetachedWindow {
  1780. dispatcher: WryDispatcher {
  1781. window_id: window.id(),
  1782. context: context.clone(),
  1783. },
  1784. label: label.clone(),
  1785. },
  1786. )
  1787. })
  1788. }