window.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. // Copyright 2019-2022 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. #![allow(unused_imports)]
  5. use super::{InvokeContext, InvokeResponse};
  6. #[cfg(window_create)]
  7. use crate::runtime::{webview::WindowBuilder, Dispatch};
  8. use crate::{
  9. runtime::{
  10. window::dpi::{Position, Size},
  11. UserAttentionType,
  12. },
  13. utils::config::WindowConfig,
  14. CursorIcon, Icon, Manager, Runtime,
  15. };
  16. use serde::Deserialize;
  17. use tauri_macros::{command_enum, module_command_handler, CommandModule};
  18. #[derive(Deserialize)]
  19. #[serde(untagged)]
  20. pub enum IconDto {
  21. #[cfg(any(feature = "icon-png", feature = "icon-ico"))]
  22. File(std::path::PathBuf),
  23. #[cfg(any(feature = "icon-png", feature = "icon-ico"))]
  24. Raw(Vec<u8>),
  25. Rgba {
  26. rgba: Vec<u8>,
  27. width: u32,
  28. height: u32,
  29. },
  30. }
  31. impl From<IconDto> for Icon {
  32. fn from(icon: IconDto) -> Self {
  33. match icon {
  34. #[cfg(any(feature = "icon-png", feature = "icon-ico"))]
  35. IconDto::File(path) => Self::File(path),
  36. #[cfg(any(feature = "icon-png", feature = "icon-ico"))]
  37. IconDto::Raw(raw) => Self::Raw(raw),
  38. IconDto::Rgba {
  39. rgba,
  40. width,
  41. height,
  42. } => Self::Rgba {
  43. rgba,
  44. width,
  45. height,
  46. },
  47. }
  48. }
  49. }
  50. /// Window management API descriptor.
  51. #[derive(Deserialize)]
  52. #[serde(tag = "type", content = "payload", rename_all = "camelCase")]
  53. pub enum WindowManagerCmd {
  54. // Getters
  55. ScaleFactor,
  56. InnerPosition,
  57. OuterPosition,
  58. InnerSize,
  59. OuterSize,
  60. IsFullscreen,
  61. IsMaximized,
  62. IsDecorated,
  63. IsResizable,
  64. IsVisible,
  65. CurrentMonitor,
  66. PrimaryMonitor,
  67. AvailableMonitors,
  68. Theme,
  69. // Setters
  70. #[cfg(window_center)]
  71. Center,
  72. #[cfg(window_request_user_attention)]
  73. RequestUserAttention(Option<UserAttentionType>),
  74. #[cfg(window_set_resizable)]
  75. SetResizable(bool),
  76. #[cfg(window_set_title)]
  77. SetTitle(String),
  78. #[cfg(window_maximize)]
  79. Maximize,
  80. #[cfg(window_unmaximize)]
  81. Unmaximize,
  82. #[cfg(all(window_maximize, window_unmaximize))]
  83. ToggleMaximize,
  84. #[cfg(window_minimize)]
  85. Minimize,
  86. #[cfg(window_unminimize)]
  87. Unminimize,
  88. #[cfg(window_show)]
  89. Show,
  90. #[cfg(window_hide)]
  91. Hide,
  92. #[cfg(window_close)]
  93. Close,
  94. #[cfg(window_set_decorations)]
  95. SetDecorations(bool),
  96. #[cfg(window_set_always_on_top)]
  97. #[serde(rename_all = "camelCase")]
  98. SetAlwaysOnTop(bool),
  99. #[cfg(window_set_size)]
  100. SetSize(Size),
  101. #[cfg(window_set_min_size)]
  102. SetMinSize(Option<Size>),
  103. #[cfg(window_set_max_size)]
  104. SetMaxSize(Option<Size>),
  105. #[cfg(window_set_position)]
  106. SetPosition(Position),
  107. #[cfg(window_set_fullscreen)]
  108. SetFullscreen(bool),
  109. #[cfg(window_set_focus)]
  110. SetFocus,
  111. #[cfg(window_set_icon)]
  112. SetIcon {
  113. icon: IconDto,
  114. },
  115. #[cfg(window_set_skip_taskbar)]
  116. SetSkipTaskbar(bool),
  117. #[cfg(window_set_cursor_grab)]
  118. SetCursorGrab(bool),
  119. #[cfg(window_set_cursor_visible)]
  120. SetCursorVisible(bool),
  121. #[cfg(window_set_cursor_icon)]
  122. SetCursorIcon(CursorIcon),
  123. #[cfg(window_set_cursor_position)]
  124. SetCursorPosition(Position),
  125. #[cfg(window_set_ignore_cursor_events)]
  126. SetIgnoreCursorEvents(bool),
  127. #[cfg(window_start_dragging)]
  128. StartDragging,
  129. #[cfg(window_print)]
  130. Print,
  131. // internals
  132. #[cfg(all(window_maximize, window_unmaximize))]
  133. #[serde(rename = "__toggleMaximize")]
  134. InternalToggleMaximize,
  135. #[cfg(any(debug_assertions, feature = "devtools"))]
  136. #[serde(rename = "__toggleDevtools")]
  137. InternalToggleDevtools,
  138. }
  139. pub fn into_allowlist_error(variant: &str) -> crate::Error {
  140. match variant {
  141. "center" => crate::Error::ApiNotAllowlisted("window > center".to_string()),
  142. "requestUserAttention" => {
  143. crate::Error::ApiNotAllowlisted("window > requestUserAttention".to_string())
  144. }
  145. "setResizable" => crate::Error::ApiNotAllowlisted("window > setResizable".to_string()),
  146. "setTitle" => crate::Error::ApiNotAllowlisted("window > setTitle".to_string()),
  147. "maximize" => crate::Error::ApiNotAllowlisted("window > maximize".to_string()),
  148. "unmaximize" => crate::Error::ApiNotAllowlisted("window > unmaximize".to_string()),
  149. "toggleMaximize" => {
  150. crate::Error::ApiNotAllowlisted("window > maximize and window > unmaximize".to_string())
  151. }
  152. "minimize" => crate::Error::ApiNotAllowlisted("window > minimize".to_string()),
  153. "unminimize" => crate::Error::ApiNotAllowlisted("window > unminimize".to_string()),
  154. "show" => crate::Error::ApiNotAllowlisted("window > show".to_string()),
  155. "hide" => crate::Error::ApiNotAllowlisted("window > hide".to_string()),
  156. "close" => crate::Error::ApiNotAllowlisted("window > close".to_string()),
  157. "setDecorations" => crate::Error::ApiNotAllowlisted("window > setDecorations".to_string()),
  158. "setAlwaysOnTop" => crate::Error::ApiNotAllowlisted("window > setAlwaysOnTop".to_string()),
  159. "setSize" => crate::Error::ApiNotAllowlisted("window > setSize".to_string()),
  160. "setMinSize" => crate::Error::ApiNotAllowlisted("window > setMinSize".to_string()),
  161. "setMaxSize" => crate::Error::ApiNotAllowlisted("window > setMaxSize".to_string()),
  162. "setPosition" => crate::Error::ApiNotAllowlisted("window > setPosition".to_string()),
  163. "setFullscreen" => crate::Error::ApiNotAllowlisted("window > setFullscreen".to_string()),
  164. "setIcon" => crate::Error::ApiNotAllowlisted("window > setIcon".to_string()),
  165. "setSkipTaskbar" => crate::Error::ApiNotAllowlisted("window > setSkipTaskbar".to_string()),
  166. "setCursorGrab" => crate::Error::ApiNotAllowlisted("window > setCursorGrab".to_string()),
  167. "setCursorVisible" => crate::Error::ApiNotAllowlisted("window > setCursorVisible".to_string()),
  168. "setCursorIcon" => crate::Error::ApiNotAllowlisted("window > setCursorIcon".to_string()),
  169. "setCursorPosition" => {
  170. crate::Error::ApiNotAllowlisted("window > setCursorPosition".to_string())
  171. }
  172. "setIgnoreCursorEvents" => {
  173. crate::Error::ApiNotAllowlisted("window > setIgnoreCursorEvents".to_string())
  174. }
  175. "startDragging" => crate::Error::ApiNotAllowlisted("window > startDragging".to_string()),
  176. "print" => crate::Error::ApiNotAllowlisted("window > print".to_string()),
  177. "internalToggleMaximize" => {
  178. crate::Error::ApiNotAllowlisted("window > maximize and window > unmaximize".to_string())
  179. }
  180. _ => crate::Error::ApiNotAllowlisted("window".to_string()),
  181. }
  182. }
  183. /// The API descriptor.
  184. #[command_enum]
  185. #[derive(Deserialize, CommandModule)]
  186. #[cmd(async)]
  187. #[serde(tag = "cmd", content = "data", rename_all = "camelCase")]
  188. pub enum Cmd {
  189. #[cmd(window_create, "window > create")]
  190. CreateWebview { options: Box<WindowConfig> },
  191. Manage {
  192. label: Option<String>,
  193. cmd: WindowManagerCmd,
  194. },
  195. }
  196. impl Cmd {
  197. #[module_command_handler(window_create)]
  198. async fn create_webview<R: Runtime>(
  199. context: InvokeContext<R>,
  200. options: Box<WindowConfig>,
  201. ) -> super::Result<()> {
  202. let label = options.label.clone();
  203. let url = options.url.clone();
  204. let file_drop_enabled = options.file_drop_enabled;
  205. let mut builder = crate::window::Window::builder(&context.window, label, url);
  206. if !file_drop_enabled {
  207. builder = builder.disable_file_drop_handler();
  208. }
  209. builder.window_builder =
  210. <<R::Dispatcher as Dispatch<crate::EventLoopMessage>>::WindowBuilder>::with_config(*options);
  211. builder.build().map_err(crate::error::into_anyhow)?;
  212. Ok(())
  213. }
  214. async fn manage<R: Runtime>(
  215. context: InvokeContext<R>,
  216. label: Option<String>,
  217. cmd: WindowManagerCmd,
  218. ) -> super::Result<InvokeResponse> {
  219. Self::_manage(context, label, cmd)
  220. .await
  221. .map_err(crate::error::into_anyhow)
  222. }
  223. async fn _manage<R: Runtime>(
  224. context: InvokeContext<R>,
  225. label: Option<String>,
  226. cmd: WindowManagerCmd,
  227. ) -> crate::Result<InvokeResponse> {
  228. let window = match label {
  229. Some(l) if !l.is_empty() => context
  230. .window
  231. .get_window(&l)
  232. .ok_or(crate::Error::WebviewNotFound)?,
  233. _ => context.window,
  234. };
  235. match cmd {
  236. // Getters
  237. WindowManagerCmd::ScaleFactor => return Ok(window.scale_factor()?.into()),
  238. WindowManagerCmd::InnerPosition => return Ok(window.inner_position()?.into()),
  239. WindowManagerCmd::OuterPosition => return Ok(window.outer_position()?.into()),
  240. WindowManagerCmd::InnerSize => return Ok(window.inner_size()?.into()),
  241. WindowManagerCmd::OuterSize => return Ok(window.outer_size()?.into()),
  242. WindowManagerCmd::IsFullscreen => return Ok(window.is_fullscreen()?.into()),
  243. WindowManagerCmd::IsMaximized => return Ok(window.is_maximized()?.into()),
  244. WindowManagerCmd::IsDecorated => return Ok(window.is_decorated()?.into()),
  245. WindowManagerCmd::IsResizable => return Ok(window.is_resizable()?.into()),
  246. WindowManagerCmd::IsVisible => return Ok(window.is_visible()?.into()),
  247. WindowManagerCmd::CurrentMonitor => return Ok(window.current_monitor()?.into()),
  248. WindowManagerCmd::PrimaryMonitor => return Ok(window.primary_monitor()?.into()),
  249. WindowManagerCmd::AvailableMonitors => return Ok(window.available_monitors()?.into()),
  250. WindowManagerCmd::Theme => return Ok(window.theme()?.into()),
  251. // Setters
  252. #[cfg(all(desktop, window_center))]
  253. WindowManagerCmd::Center => window.center()?,
  254. #[cfg(all(desktop, window_request_user_attention))]
  255. WindowManagerCmd::RequestUserAttention(request_type) => {
  256. window.request_user_attention(request_type)?
  257. }
  258. #[cfg(all(desktop, window_set_resizable))]
  259. WindowManagerCmd::SetResizable(resizable) => window.set_resizable(resizable)?,
  260. #[cfg(all(desktop, window_set_title))]
  261. WindowManagerCmd::SetTitle(title) => window.set_title(&title)?,
  262. #[cfg(all(desktop, window_maximize))]
  263. WindowManagerCmd::Maximize => window.maximize()?,
  264. #[cfg(all(desktop, window_unmaximize))]
  265. WindowManagerCmd::Unmaximize => window.unmaximize()?,
  266. #[cfg(all(desktop, window_maximize, window_unmaximize))]
  267. WindowManagerCmd::ToggleMaximize => match window.is_maximized()? {
  268. true => window.unmaximize()?,
  269. false => window.maximize()?,
  270. },
  271. #[cfg(all(desktop, window_minimize))]
  272. WindowManagerCmd::Minimize => window.minimize()?,
  273. #[cfg(all(desktop, window_unminimize))]
  274. WindowManagerCmd::Unminimize => window.unminimize()?,
  275. #[cfg(all(desktop, window_show))]
  276. WindowManagerCmd::Show => window.show()?,
  277. #[cfg(all(desktop, window_hide))]
  278. WindowManagerCmd::Hide => window.hide()?,
  279. #[cfg(all(desktop, window_close))]
  280. WindowManagerCmd::Close => window.close()?,
  281. #[cfg(all(desktop, window_set_decorations))]
  282. WindowManagerCmd::SetDecorations(decorations) => window.set_decorations(decorations)?,
  283. #[cfg(all(desktop, window_set_always_on_top))]
  284. WindowManagerCmd::SetAlwaysOnTop(always_on_top) => window.set_always_on_top(always_on_top)?,
  285. #[cfg(all(desktop, window_set_size))]
  286. WindowManagerCmd::SetSize(size) => window.set_size(size)?,
  287. #[cfg(all(desktop, window_set_min_size))]
  288. WindowManagerCmd::SetMinSize(size) => window.set_min_size(size)?,
  289. #[cfg(all(desktop, window_set_max_size))]
  290. WindowManagerCmd::SetMaxSize(size) => window.set_max_size(size)?,
  291. #[cfg(all(desktop, window_set_position))]
  292. WindowManagerCmd::SetPosition(position) => window.set_position(position)?,
  293. #[cfg(all(desktop, window_set_fullscreen))]
  294. WindowManagerCmd::SetFullscreen(fullscreen) => window.set_fullscreen(fullscreen)?,
  295. #[cfg(all(desktop, window_set_focus))]
  296. WindowManagerCmd::SetFocus => window.set_focus()?,
  297. #[cfg(all(desktop, window_set_icon))]
  298. WindowManagerCmd::SetIcon { icon } => window.set_icon(icon.into())?,
  299. #[cfg(all(desktop, window_set_skip_taskbar))]
  300. WindowManagerCmd::SetSkipTaskbar(skip) => window.set_skip_taskbar(skip)?,
  301. #[cfg(all(desktop, window_set_cursor_grab))]
  302. WindowManagerCmd::SetCursorGrab(grab) => window.set_cursor_grab(grab)?,
  303. #[cfg(all(desktop, window_set_cursor_visible))]
  304. WindowManagerCmd::SetCursorVisible(visible) => window.set_cursor_visible(visible)?,
  305. #[cfg(all(desktop, window_set_cursor_icon))]
  306. WindowManagerCmd::SetCursorIcon(icon) => window.set_cursor_icon(icon)?,
  307. #[cfg(all(desktop, window_set_cursor_position))]
  308. WindowManagerCmd::SetCursorPosition(position) => window.set_cursor_position(position)?,
  309. #[cfg(all(desktop, window_set_ignore_cursor_events))]
  310. WindowManagerCmd::SetIgnoreCursorEvents(ignore_cursor) => {
  311. window.set_ignore_cursor_events(ignore_cursor)?
  312. }
  313. #[cfg(all(desktop, window_start_dragging))]
  314. WindowManagerCmd::StartDragging => window.start_dragging()?,
  315. #[cfg(all(desktop, window_print))]
  316. WindowManagerCmd::Print => window.print()?,
  317. // internals
  318. #[cfg(all(desktop, window_maximize, window_unmaximize))]
  319. WindowManagerCmd::InternalToggleMaximize => {
  320. if window.is_resizable()? {
  321. match window.is_maximized()? {
  322. true => window.unmaximize()?,
  323. false => window.maximize()?,
  324. }
  325. }
  326. }
  327. #[cfg(all(desktop, any(debug_assertions, feature = "devtools")))]
  328. WindowManagerCmd::InternalToggleDevtools => {
  329. if window.is_devtools_open() {
  330. window.close_devtools();
  331. } else {
  332. window.open_devtools();
  333. }
  334. }
  335. _ => (),
  336. }
  337. #[allow(unreachable_code)]
  338. Ok(().into())
  339. }
  340. }