window.rs 12 KB

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