improve error handling

This commit is contained in:
Jonas Kruckenberg 2022-11-13 21:06:06 +01:00
parent c9fa93de72
commit 355febf927
12 changed files with 443 additions and 258 deletions

View file

@ -5,7 +5,7 @@
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use tauri::{State, Manager}; use tauri::{Manager, State};
struct Received(AtomicBool); struct Received(AtomicBool);
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command // Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
@ -28,7 +28,10 @@ fn main() {
let app_handle = app.handle(); let app_handle = app.handle();
app.listen_global("foo", move |_| { app.listen_global("foo", move |_| {
app_handle.state::<Received>().0.store(true, Ordering::Relaxed); app_handle
.state::<Received>()
.0
.store(true, Ordering::Relaxed);
}); });
Ok(()) Ok(())

View file

@ -4,7 +4,9 @@ use tauri_sys::{event, tauri};
pub async fn emit() -> anyhow::Result<()> { pub async fn emit() -> anyhow::Result<()> {
event::emit("foo", &"bar").await; event::emit("foo", &"bar").await;
ensure!(tauri::invoke::<_, bool>("verify_receive", &()).await.unwrap()); ensure!(tauri::invoke::<_, bool>("verify_receive", &())
.await
.unwrap());
Ok(()) Ok(())
} }

View file

@ -18,7 +18,9 @@ async fn exit_with_error(e: String) {
e: String, e: String,
} }
tauri_sys::tauri::invoke::<_, ()>("exit_with_error", &Args { e }).await.unwrap(); tauri_sys::tauri::invoke::<_, ()>("exit_with_error", &Args { e })
.await
.unwrap();
} }
#[derive(Props)] #[derive(Props)]

View file

@ -1,5 +1,7 @@
use semver::Version; use semver::Version;
use crate::Error;
/// Gets the application name. /// Gets the application name.
/// ///
/// # Example /// # Example
@ -9,8 +11,10 @@ use semver::Version;
/// const appName = await getName(); /// const appName = await getName();
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub async fn get_name() -> String { pub async fn get_name() -> crate::Result<String> {
inner::getName().await.as_string().unwrap() let js_val = inner::getName().await.map_err(Error::Other)?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
} }
/// Gets the application version. /// Gets the application version.
@ -23,8 +27,10 @@ pub async fn get_name() -> String {
/// let version = get_version().await; /// let version = get_version().await;
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub async fn get_version() -> Version { pub async fn get_version() -> crate::Result<Version> {
Version::parse(&inner::getVersion().await.as_string().unwrap()).unwrap() let js_val = inner::getVersion().await.map_err(Error::Other)?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
} }
/// Gets the Tauri version. /// Gets the Tauri version.
@ -37,8 +43,10 @@ pub async fn get_version() -> Version {
/// let version = get_tauri_version().await; /// let version = get_tauri_version().await;
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub async fn get_tauri_version() -> Version { pub async fn get_tauri_version() -> crate::Result<Version> {
Version::parse(&inner::getTauriVersion().await.as_string().unwrap()).unwrap() let js_val = inner::getTauriVersion().await.map_err(Error::Other)?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
} }
/// Shows the application on macOS. This function does not automatically focuses any app window. /// Shows the application on macOS. This function does not automatically focuses any app window.
@ -51,8 +59,8 @@ pub async fn get_tauri_version() -> Version {
/// show().await; /// show().await;
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub async fn show() { pub async fn show() -> crate::Result<()> {
inner::show().await; inner::show().await.map_err(Error::Other)
} }
/// Hides the application on macOS. /// Hides the application on macOS.
@ -65,8 +73,8 @@ pub async fn show() {
/// hide().await; /// hide().await;
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub async fn hide() { pub async fn hide() -> crate::Result<()> {
inner::hide().await; inner::hide().await.map_err(Error::Other)
} }
mod inner { mod inner {
@ -74,10 +82,15 @@ mod inner {
#[wasm_bindgen(module = "/dist/app.js")] #[wasm_bindgen(module = "/dist/app.js")]
extern "C" { extern "C" {
pub async fn getName() -> JsValue; #[wasm_bindgen(catch)]
pub async fn getTauriVersion() -> JsValue; pub async fn getName() -> Result<JsValue, JsValue>;
pub async fn getVersion() -> JsValue; #[wasm_bindgen(catch)]
pub async fn hide(); pub async fn getTauriVersion() -> Result<JsValue, JsValue>;
pub async fn show(); #[wasm_bindgen(catch)]
pub async fn getVersion() -> Result<JsValue, JsValue>;
#[wasm_bindgen(catch)]
pub async fn hide() -> Result<(), JsValue>;
#[wasm_bindgen(catch)]
pub async fn show() -> Result<(), JsValue>;
} }
} }

View file

@ -1,3 +1,5 @@
use crate::Error;
/// Gets the clipboard content as plain text. /// Gets the clipboard content as plain text.
/// ///
/// # Example /// # Example
@ -8,8 +10,10 @@
/// let clipboard_text = read_text().await; /// let clipboard_text = read_text().await;
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub async fn read_text() -> Option<String> { pub async fn read_text() -> crate::Result<String> {
inner::readText().await.as_string() let js_val = inner::readText().await.map_err(Error::Other)?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
} }
/// Writes plain text to the clipboard. /// Writes plain text to the clipboard.
@ -25,8 +29,8 @@ pub async fn read_text() -> Option<String> {
/// ///
/// @returns A promise indicating the success or failure of the operation. /// @returns A promise indicating the success or failure of the operation.
#[inline(always)] #[inline(always)]
pub async fn write_text(text: &str) { pub async fn write_text(text: &str) -> crate::Result<()> {
inner::writeText(text).await inner::writeText(text).await.map_err(Error::Other)
} }
mod inner { mod inner {
@ -34,7 +38,9 @@ mod inner {
#[wasm_bindgen(module = "/dist/clipboard.js")] #[wasm_bindgen(module = "/dist/clipboard.js")]
extern "C" { extern "C" {
pub async fn readText() -> JsValue; #[wasm_bindgen(catch)]
pub async fn writeText(text: &str); pub async fn readText() -> Result<JsValue, JsValue>;
#[wasm_bindgen(catch)]
pub async fn writeText(text: &str) -> Result<(), JsValue>;
} }
} }

View file

@ -3,6 +3,8 @@ use std::fmt::Debug;
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use wasm_bindgen::{prelude::Closure, JsValue}; use wasm_bindgen::{prelude::Closure, JsValue};
use crate::Error;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Event<T> { pub struct Event<T> {
/// Event name /// Event name
@ -45,8 +47,10 @@ impl<T: Debug> Debug for Event<T> {
/// ///
/// @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`. /// @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
#[inline(always)] #[inline(always)]
pub async fn emit<T: Serialize>(event: &str, payload: &T) { pub async fn emit<T: Serialize>(event: &str, payload: &T) -> crate::Result<()> {
inner::emit(event, serde_wasm_bindgen::to_value(payload).unwrap()).await inner::emit(event, serde_wasm_bindgen::to_value(payload)?)
.await
.map_err(Error::Other)
} }
/// Listen to an event from the backend. /// Listen to an event from the backend.
@ -70,7 +74,7 @@ pub async fn emit<T: Serialize>(event: &str, payload: &T) {
/// ///
/// Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted. /// Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
#[inline(always)] #[inline(always)]
pub async fn listen<T, H>(event: &str, mut handler: H) -> impl FnOnce() pub async fn listen<T, H>(event: &str, mut handler: H) -> crate::Result<impl FnOnce()>
where where
T: DeserializeOwned, T: DeserializeOwned,
H: FnMut(Event<T>) + 'static, H: FnMut(Event<T>) + 'static,
@ -79,14 +83,14 @@ where
(handler)(serde_wasm_bindgen::from_value(raw).unwrap()) (handler)(serde_wasm_bindgen::from_value(raw).unwrap())
}); });
let unlisten = inner::listen(event, &closure).await; let unlisten = inner::listen(event, &closure).await.map_err(Error::Other)?;
closure.forget(); closure.forget();
let unlisten = js_sys::Function::from(unlisten); let unlisten = js_sys::Function::from(unlisten);
move || { Ok(move || {
unlisten.call0(&wasm_bindgen::JsValue::NULL).unwrap(); unlisten.call0(&wasm_bindgen::JsValue::NULL).unwrap();
} })
} }
/// Listen to an one-off event from the backend. /// Listen to an one-off event from the backend.
@ -115,7 +119,7 @@ where
/// ///
/// Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted. /// Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
#[inline(always)] #[inline(always)]
pub async fn once<T, H>(event: &str, mut handler: H) -> impl FnOnce() pub async fn once<T, H>(event: &str, mut handler: H) -> crate::Result<impl FnOnce()>
where where
T: DeserializeOwned, T: DeserializeOwned,
H: FnMut(Event<T>) + 'static, H: FnMut(Event<T>) + 'static,
@ -124,14 +128,14 @@ where
(handler)(serde_wasm_bindgen::from_value(raw).unwrap()) (handler)(serde_wasm_bindgen::from_value(raw).unwrap())
}); });
let unlisten = inner::once(event, &closure).await; let unlisten = inner::once(event, &closure).await.map_err(Error::Other)?;
closure.forget(); closure.forget();
let unlisten = js_sys::Function::from(unlisten); let unlisten = js_sys::Function::from(unlisten);
move || { Ok(move || {
unlisten.call0(&wasm_bindgen::JsValue::NULL).unwrap(); unlisten.call0(&wasm_bindgen::JsValue::NULL).unwrap();
} })
} }
mod inner { mod inner {
@ -142,8 +146,17 @@ mod inner {
#[wasm_bindgen(module = "/dist/event.js")] #[wasm_bindgen(module = "/dist/event.js")]
extern "C" { extern "C" {
pub async fn emit(event: &str, payload: JsValue); #[wasm_bindgen(catch)]
pub async fn listen(event: &str, handler: &Closure<dyn FnMut(JsValue)>) -> JsValue; pub async fn emit(event: &str, payload: JsValue) -> Result<(), JsValue>;
pub async fn once(event: &str, handler: &Closure<dyn FnMut(JsValue)>) -> JsValue; #[wasm_bindgen(catch)]
pub async fn listen(
event: &str,
handler: &Closure<dyn FnMut(JsValue)>,
) -> Result<JsValue, JsValue>;
#[wasm_bindgen(catch)]
pub async fn once(
event: &str,
handler: &Closure<dyn FnMut(JsValue)>,
) -> Result<JsValue, JsValue>;
} }
} }

View file

@ -8,17 +8,23 @@ pub mod clipboard;
pub mod event; pub mod event;
#[cfg(feature = "mocks")] #[cfg(feature = "mocks")]
pub mod mocks; pub mod mocks;
#[cfg(feature = "process")]
pub mod process;
#[cfg(feature = "tauri")] #[cfg(feature = "tauri")]
pub mod tauri; pub mod tauri;
#[cfg(feature = "window")] #[cfg(feature = "window")]
pub mod window; pub mod window;
#[cfg(feature = "process")]
pub mod process;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum Error { pub enum Error {
#[error(transparent)] #[error(transparent)]
Serde(#[from] serde_wasm_bindgen::Error), Serde(#[from] serde_wasm_bindgen::Error),
#[error("Unknown Theme \"{0}\". Expected one of \"light\",\"dark\"")]
UnknownTheme(String),
#[error("Invalid Url {0}")]
InvalidUrl(#[from] url::ParseError),
#[error("Invalid Version {0}")]
InvalidVersion(#[from] semver::Error),
#[error("{0:?}")] #[error("{0:?}")]
Other(JsValue), Other(JsValue),
} }

View file

@ -1,6 +1,8 @@
use serde::{de::DeserializeOwned, Serialize}; use serde::{de::DeserializeOwned, Serialize};
use url::Url; use url::Url;
use crate::Error;
/// Convert a device file path to an URL that can be loaded by the webview. /// Convert a device file path to an URL that can be loaded by the webview.
/// Note that `asset:` and `https://asset.localhost` must be added to [`tauri.security.csp`](https://tauri.app/v1/api/config/#securityconfig.csp) in `tauri.conf.json`. /// Note that `asset:` and `https://asset.localhost` must be added to [`tauri.security.csp`](https://tauri.app/v1/api/config/#securityconfig.csp) in `tauri.conf.json`.
/// Example CSP value: `"csp": "default-src 'self'; img-src 'self' asset: https://asset.localhost"` to use the asset protocol on image sources. /// Example CSP value: `"csp": "default-src 'self'; img-src 'self' asset: https://asset.localhost"` to use the asset protocol on image sources.
@ -36,14 +38,12 @@ use url::Url;
/// ///
/// @return the URL that can be used as source on the webview. /// @return the URL that can be used as source on the webview.
#[inline(always)] #[inline(always)]
pub async fn convert_file_src(file_path: &str, protocol: Option<&str>) -> Url { pub async fn convert_file_src(file_path: &str, protocol: Option<&str>) -> crate::Result<Url> {
Url::parse( let js_val = inner::convertFileSrc(file_path, protocol)
&inner::convertFileSrc(file_path, protocol) .await
.await .map_err(Error::Other)?;
.as_string()
.unwrap(), Ok(serde_wasm_bindgen::from_value(js_val)?)
)
.unwrap()
} }
/// Sends a message to the backend. /// Sends a message to the backend.
@ -66,9 +66,10 @@ pub async fn convert_file_src(file_path: &str, protocol: Option<&str>) -> Url {
/// @return A promise resolving or rejecting to the backend response. /// @return A promise resolving or rejecting to the backend response.
#[inline(always)] #[inline(always)]
pub async fn invoke<A: Serialize, R: DeserializeOwned>(cmd: &str, args: &A) -> crate::Result<R> { pub async fn invoke<A: Serialize, R: DeserializeOwned>(cmd: &str, args: &A) -> crate::Result<R> {
let res = inner::invoke(cmd, serde_wasm_bindgen::to_value(args).unwrap()).await; let raw = inner::invoke(cmd, serde_wasm_bindgen::to_value(args)?)
.await
.map_err(crate::Error::Other)?;
let raw = res.map_err(crate::Error::Other)?;
serde_wasm_bindgen::from_value(raw).map_err(Into::into) serde_wasm_bindgen::from_value(raw).map_err(Into::into)
} }
@ -77,14 +78,18 @@ pub async fn invoke<A: Serialize, R: DeserializeOwned>(cmd: &str, args: &A) -> c
/// ///
/// @return A unique identifier associated with the callback function. /// @return A unique identifier associated with the callback function.
#[inline(always)] #[inline(always)]
pub async fn transform_callback<T: DeserializeOwned>(callback: &dyn Fn(T), once: bool) -> f64 { pub async fn transform_callback<T: DeserializeOwned>(
inner::transformCallback( callback: &dyn Fn(T),
once: bool,
) -> crate::Result<f64> {
let js_val = inner::transformCallback(
&|raw| callback(serde_wasm_bindgen::from_value(raw).unwrap()), &|raw| callback(serde_wasm_bindgen::from_value(raw).unwrap()),
once, once,
) )
.await .await
.as_f64() .map_err(Error::Other)?;
.unwrap()
Ok(serde_wasm_bindgen::from_value(js_val)?)
} }
mod inner { mod inner {
@ -92,9 +97,17 @@ mod inner {
#[wasm_bindgen(module = "/dist/tauri.js")] #[wasm_bindgen(module = "/dist/tauri.js")]
extern "C" { extern "C" {
pub async fn convertFileSrc(filePath: &str, protocol: Option<&str>) -> JsValue; #[wasm_bindgen(catch)]
pub async fn convertFileSrc(
filePath: &str,
protocol: Option<&str>,
) -> Result<JsValue, JsValue>;
#[wasm_bindgen(catch)] #[wasm_bindgen(catch)]
pub async fn invoke(cmd: &str, args: JsValue) -> Result<JsValue, JsValue>; pub async fn invoke(cmd: &str, args: JsValue) -> Result<JsValue, JsValue>;
pub async fn transformCallback(callback: &dyn Fn(JsValue), once: bool) -> JsValue; #[wasm_bindgen(catch)]
pub async fn transformCallback(
callback: &dyn Fn(JsValue),
once: bool,
) -> Result<JsValue, JsValue>;
} }
} }

View file

@ -1,4 +1,4 @@
use crate::event::Event; use crate::{event::Event, Error};
use serde::{de::DeserializeOwned, Serialize}; use serde::{de::DeserializeOwned, Serialize};
use std::fmt::Display; use std::fmt::Display;
use wasm_bindgen::{prelude::Closure, JsCast, JsValue}; use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
@ -135,192 +135,279 @@ impl WebviewWindow {
self.0.label() self.0.label()
} }
pub async fn scale_factor(&self) -> f64 { pub async fn scale_factor(&self) -> crate::Result<f64> {
self.0.scaleFactor().await.as_f64().unwrap() let js_val = self.0.scaleFactor().await.map_err(Error::Other)?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
} }
pub async fn inner_position(&self) -> PhysicalPosition { pub async fn inner_position(&self) -> crate::Result<PhysicalPosition> {
PhysicalPosition(self.0.innerPosition().await.unchecked_into()) Ok(PhysicalPosition(
self.0
.innerPosition()
.await
.map_err(Error::Other)?
.unchecked_into(),
))
} }
pub async fn outer_position(&self) -> PhysicalPosition { pub async fn outer_position(&self) -> crate::Result<PhysicalPosition> {
PhysicalPosition(self.0.outerPosition().await.unchecked_into()) Ok(PhysicalPosition(
self.0
.outerPosition()
.await
.map_err(Error::Other)?
.unchecked_into(),
))
} }
pub async fn inner_size(&self) -> PhysicalSize { pub async fn inner_size(&self) -> crate::Result<PhysicalSize> {
PhysicalSize(self.0.innerSize().await.unchecked_into()) Ok(PhysicalSize(
self.0
.innerSize()
.await
.map_err(Error::Other)?
.unchecked_into(),
))
} }
pub async fn outer_size(&self) -> PhysicalSize { pub async fn outer_size(&self) -> crate::Result<PhysicalSize> {
PhysicalSize(self.0.outerSize().await.unchecked_into()) Ok(PhysicalSize(
self.0
.outerSize()
.await
.map_err(Error::Other)?
.unchecked_into(),
))
} }
pub async fn is_fullscreen(&self) -> bool { pub async fn is_fullscreen(&self) -> crate::Result<bool> {
self.0.isFullscreen().await.as_bool().unwrap() let js_val = self.0.isFullscreen().await.map_err(Error::Other)?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
} }
pub async fn is_maximized(&self) -> bool { pub async fn is_maximized(&self) -> crate::Result<bool> {
self.0.isMaximized().await.as_bool().unwrap() let js_val = self.0.isMaximized().await.map_err(Error::Other)?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
} }
pub async fn is_decorated(&self) -> bool { pub async fn is_decorated(&self) -> crate::Result<bool> {
self.0.isDecorated().await.as_bool().unwrap() let js_val = self.0.isDecorated().await.map_err(Error::Other)?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
} }
pub async fn is_resizable(&self) -> bool { pub async fn is_resizable(&self) -> crate::Result<bool> {
self.0.isResizable().await.as_bool().unwrap() let js_val = self.0.isResizable().await.map_err(Error::Other)?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
} }
pub async fn is_visible(&self) -> bool { pub async fn is_visible(&self) -> crate::Result<bool> {
self.0.isVisible().await.as_bool().unwrap() let js_val = self.0.isVisible().await.map_err(Error::Other)?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
} }
pub async fn theme(&self) -> Theme { pub async fn theme(&self) -> crate::Result<Theme> {
match self.0.theme().await.as_string().unwrap().as_str() { let js_val = self.0.theme().await.map_err(Error::Other)?;
"light" => Theme::Light,
"dark" => Theme::Dark, let str = serde_wasm_bindgen::from_value::<String>(js_val)?;
_ => panic!("Unknown theme"),
match str.as_str() {
"light" => Ok(Theme::Light),
"dark" => Ok(Theme::Dark),
_ => Err(Error::UnknownTheme(str)),
} }
} }
pub async fn center(&self) { pub async fn center(&self) -> crate::Result<()> {
self.0.center().await; self.0.center().await.map_err(Error::Other)
} }
pub async fn request_user_attention(&self, request_type: UserAttentionType) { pub async fn request_user_attention(
self.0.requestUserAttention(request_type as u32).await; &self,
request_type: UserAttentionType,
) -> crate::Result<()> {
self.0
.requestUserAttention(request_type as u32)
.await
.map_err(Error::Other)
} }
pub async fn set_resizable(&self, resizable: bool) { pub async fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
self.0.setResizable(resizable).await; self.0.setResizable(resizable).await.map_err(Error::Other)
} }
pub async fn set_title(&self, title: impl AsRef<str>) { pub async fn set_title(&self, title: impl AsRef<str>) -> crate::Result<()> {
self.0.setTitle(title.as_ref()).await; self.0.setTitle(title.as_ref()).await.map_err(Error::Other)
} }
pub async fn maximize(&self) { pub async fn maximize(&self) -> crate::Result<()> {
self.0.maximize().await; self.0.maximize().await.map_err(Error::Other)
} }
pub async fn unmaximize(&self) { pub async fn unmaximize(&self) -> crate::Result<()> {
self.0.unmaximize().await; self.0.unmaximize().await.map_err(Error::Other)
} }
pub async fn toggle_maximize(&self) { pub async fn toggle_maximize(&self) -> crate::Result<()> {
self.0.toggleMaximize().await; self.0.toggleMaximize().await.map_err(Error::Other)
} }
pub async fn minimize(&self) { pub async fn minimize(&self) -> crate::Result<()> {
self.0.minimize().await; self.0.minimize().await.map_err(Error::Other)
} }
pub async fn unminimize(&self) { pub async fn unminimize(&self) -> crate::Result<()> {
self.0.unminimize().await; self.0.unminimize().await.map_err(Error::Other)
} }
pub async fn show(&self) { pub async fn show(&self) -> crate::Result<()> {
self.0.show().await; self.0.show().await.map_err(Error::Other)
} }
pub async fn hide(&self) { pub async fn hide(&self) -> crate::Result<()> {
self.0.hide().await; self.0.hide().await.map_err(Error::Other)
} }
pub async fn close(&self) { pub async fn close(&self) -> crate::Result<()> {
self.0.close().await; self.0.close().await.map_err(Error::Other)
} }
pub async fn set_decorations(&self, decorations: bool) { pub async fn set_decorations(&self, decorations: bool) -> crate::Result<()> {
self.0.setDecorations(decorations).await; self.0
.setDecorations(decorations)
.await
.map_err(Error::Other)
} }
pub async fn set_always_on_top(&self, always_on_top: bool) { pub async fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> {
self.0.setAlwaysOnTop(always_on_top).await; self.0
.setAlwaysOnTop(always_on_top)
.await
.map_err(Error::Other)
} }
pub async fn set_size(&self, size: Size) { pub async fn set_size(&self, size: Size) -> crate::Result<()> {
match size { match size {
Size::Physical(size) => self.0.setSizePhysical(size.0).await, Size::Physical(size) => self.0.setSizePhysical(size.0).await.map_err(Error::Other),
Size::Logical(size) => self.0.setSizeLogical(size.0).await, Size::Logical(size) => self.0.setSizeLogical(size.0).await.map_err(Error::Other),
};
}
pub async fn set_min_size(&self, size: Option<Size>) {
match size {
None => self.0.setMinSizePhysical(None).await,
Some(Size::Physical(size)) => self.0.setMinSizePhysical(Some(size.0)).await,
Some(Size::Logical(size)) => self.0.setMinSizeLogical(Some(size.0)).await,
} }
} }
pub async fn set_max_size(&self, size: Option<Size>) { pub async fn set_min_size(&self, size: Option<Size>) -> crate::Result<()> {
match size { match size {
None => self.0.setMaxSizePhysical(None).await, None => self.0.setMinSizePhysical(None).await.map_err(Error::Other),
Some(Size::Physical(size)) => self.0.setMaxSizePhysical(Some(size.0)).await, Some(Size::Physical(size)) => self
Some(Size::Logical(size)) => self.0.setMaxSizeLogical(Some(size.0)).await, .0
.setMinSizePhysical(Some(size.0))
.await
.map_err(Error::Other),
Some(Size::Logical(size)) => self
.0
.setMinSizeLogical(Some(size.0))
.await
.map_err(Error::Other),
} }
} }
pub async fn set_position(&self, position: Position) { pub async fn set_max_size(&self, size: Option<Size>) -> crate::Result<()> {
match size {
None => self.0.setMaxSizePhysical(None).await.map_err(Error::Other),
Some(Size::Physical(size)) => self
.0
.setMaxSizePhysical(Some(size.0))
.await
.map_err(Error::Other),
Some(Size::Logical(size)) => self
.0
.setMaxSizeLogical(Some(size.0))
.await
.map_err(Error::Other),
}
}
pub async fn set_position(&self, position: Position) -> crate::Result<()> {
match position { match position {
Position::Physical(pos) => self.0.setPositionPhysical(pos.0).await, Position::Physical(pos) => self
Position::Logical(pos) => self.0.setPositionLogical(pos.0).await, .0
.setPositionPhysical(pos.0)
.await
.map_err(Error::Other),
Position::Logical(pos) => self.0.setPositionLogical(pos.0).await.map_err(Error::Other),
} }
} }
pub async fn set_fullscreen(&self, fullscreen: bool) { pub async fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
self.0.setFullscreen(fullscreen).await; self.0.setFullscreen(fullscreen).await.map_err(Error::Other)
} }
pub async fn set_focus(&self) { pub async fn set_focus(&self) -> crate::Result<()> {
self.0.setFocus().await; self.0.setFocus().await.map_err(Error::Other)
} }
pub async fn set_icon(&self, icon: &[u8]) { pub async fn set_icon(&self, icon: &[u8]) -> crate::Result<()> {
self.0.setIcon(icon).await; self.0.setIcon(icon).await.map_err(Error::Other)
} }
pub async fn set_skip_taskbar(&self, skip: bool) { pub async fn set_skip_taskbar(&self, skip: bool) -> crate::Result<()> {
self.0.setSkipTaskbar(skip).await; self.0.setSkipTaskbar(skip).await.map_err(Error::Other)
} }
pub async fn set_cursor_grab(&self, grab: bool) { pub async fn set_cursor_grab(&self, grab: bool) -> crate::Result<()> {
self.0.setCursorGrab(grab).await; self.0.setCursorGrab(grab).await.map_err(Error::Other)
} }
pub async fn set_cursor_visible(&self, visible: bool) { pub async fn set_cursor_visible(&self, visible: bool) -> crate::Result<()> {
self.0.setCursorVisible(visible).await; self.0.setCursorVisible(visible).await.map_err(Error::Other)
} }
pub async fn set_cursor_icon(&self, icon: CursorIcon) { pub async fn set_cursor_icon(&self, icon: CursorIcon) -> crate::Result<()> {
self.0.setCursorIcon(&icon.to_string()).await; self.0
.setCursorIcon(&icon.to_string())
.await
.map_err(Error::Other)
} }
pub async fn set_cursor_position(&self, position: Position) { pub async fn set_cursor_position(&self, position: Position) -> crate::Result<()> {
match position { match position {
Position::Physical(pos) => self.0.setCursorPositionPhysical(pos.0).await, Position::Physical(pos) => self
Position::Logical(pos) => self.0.setCursorPositionLogical(pos.0).await, .0
.setCursorPositionPhysical(pos.0)
.await
.map_err(Error::Other),
Position::Logical(pos) => self
.0
.setCursorPositionLogical(pos.0)
.await
.map_err(Error::Other),
} }
} }
pub async fn set_ignore_cursor_events(&self, ignore: bool) { pub async fn set_ignore_cursor_events(&self, ignore: bool) -> crate::Result<()> {
self.0.setIgnoreCursorEvents(ignore).await; self.0
.setIgnoreCursorEvents(ignore)
.await
.map_err(Error::Other)
} }
pub async fn start_dragging(&self) { pub async fn start_dragging(&self) -> crate::Result<()> {
self.0.startDragging().await; self.0.startDragging().await.map_err(Error::Other)
} }
#[inline(always)] #[inline(always)]
pub async fn emit<T: Serialize>(&self, event: &str, payload: &T) { pub async fn emit<T: Serialize>(&self, event: &str, payload: &T) -> crate::Result<()> {
self.0 self.0
.emit(event, serde_wasm_bindgen::to_value(payload).unwrap()) .emit(event, serde_wasm_bindgen::to_value(payload).unwrap())
.await; .await
.map_err(Error::Other)
} }
#[inline(always)] #[inline(always)]
pub async fn listen<T, H>(&self, event: &str, mut handler: H) -> impl FnOnce() pub async fn listen<T, H>(&self, event: &str, mut handler: H) -> crate::Result<impl FnOnce()>
where where
T: DeserializeOwned, T: DeserializeOwned,
H: FnMut(Event<T>) + 'static, H: FnMut(Event<T>) + 'static,
@ -329,18 +416,18 @@ impl WebviewWindow {
(handler)(serde_wasm_bindgen::from_value(raw).unwrap()) (handler)(serde_wasm_bindgen::from_value(raw).unwrap())
}); });
let unlisten = self.0.listen(event, &closure).await; let unlisten = self.0.listen(event, &closure).await.map_err(Error::Other)?;
closure.forget(); closure.forget();
let unlisten = js_sys::Function::from(unlisten); let unlisten = js_sys::Function::from(unlisten);
move || { Ok(move || {
unlisten.call0(&wasm_bindgen::JsValue::NULL).unwrap(); unlisten.call0(&wasm_bindgen::JsValue::NULL).unwrap();
} })
} }
#[inline(always)] #[inline(always)]
pub async fn once<T, H>(&self, event: &str, mut handler: H) -> impl FnOnce() pub async fn once<T, H>(&self, event: &str, mut handler: H) -> crate::Result<impl FnOnce()>
where where
T: DeserializeOwned, T: DeserializeOwned,
H: FnMut(Event<T>) + 'static, H: FnMut(Event<T>) + 'static,
@ -349,14 +436,14 @@ impl WebviewWindow {
(handler)(serde_wasm_bindgen::from_value(raw).unwrap()) (handler)(serde_wasm_bindgen::from_value(raw).unwrap())
}); });
let unlisten = self.0.once(event, &closure).await; let unlisten = self.0.once(event, &closure).await.map_err(Error::Other)?;
closure.forget(); closure.forget();
let unlisten = js_sys::Function::from(unlisten); let unlisten = js_sys::Function::from(unlisten);
move || { Ok(move || {
unlisten.call0(&wasm_bindgen::JsValue::NULL).unwrap(); unlisten.call0(&wasm_bindgen::JsValue::NULL).unwrap();
} })
} }
} }
@ -529,7 +616,7 @@ impl Iterator for AvailableMonitors {
pub async fn available_monitors() -> AvailableMonitors { pub async fn available_monitors() -> AvailableMonitors {
AvailableMonitors { AvailableMonitors {
idx: 0, idx: 0,
array: inner::availableMonitors().await.unchecked_into() array: inner::availableMonitors().await.unchecked_into(),
} }
} }
@ -613,20 +700,24 @@ mod inner {
pub type WebviewWindowHandle; pub type WebviewWindowHandle;
#[wasm_bindgen(constructor)] #[wasm_bindgen(constructor)]
pub fn new(label: &str) -> WebviewWindowHandle; pub fn new(label: &str) -> WebviewWindowHandle;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn listen( pub async fn listen(
this: &WebviewWindowHandle, this: &WebviewWindowHandle,
event: &str, event: &str,
handler: &Closure<dyn FnMut(JsValue)>, handler: &Closure<dyn FnMut(JsValue)>,
) -> JsValue; ) -> Result<JsValue, JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn once( pub async fn once(
this: &WebviewWindowHandle, this: &WebviewWindowHandle,
event: &str, event: &str,
handler: &Closure<dyn FnMut(JsValue)>, handler: &Closure<dyn FnMut(JsValue)>,
) -> JsValue; ) -> Result<JsValue, JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn emit(this: &WebviewWindowHandle, event: &str, payload: JsValue); pub async fn emit(
this: &WebviewWindowHandle,
event: &str,
payload: JsValue,
) -> Result<(), JsValue>;
} }
#[wasm_bindgen(module = "/dist/window.js")] #[wasm_bindgen(module = "/dist/window.js")]
@ -638,94 +729,130 @@ mod inner {
pub fn new(label: &str) -> WindowManager; pub fn new(label: &str) -> WindowManager;
#[wasm_bindgen(method, getter)] #[wasm_bindgen(method, getter)]
pub fn label(this: &WindowManager) -> String; pub fn label(this: &WindowManager) -> String;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn scaleFactor(this: &WindowManager) -> JsValue; pub async fn scaleFactor(this: &WindowManager) -> Result<JsValue, JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn innerPosition(this: &WindowManager) -> JsValue; pub async fn innerPosition(this: &WindowManager) -> Result<JsValue, JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn outerPosition(this: &WindowManager) -> JsValue; pub async fn outerPosition(this: &WindowManager) -> Result<JsValue, JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn innerSize(this: &WindowManager) -> JsValue; pub async fn innerSize(this: &WindowManager) -> Result<JsValue, JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn outerSize(this: &WindowManager) -> JsValue; pub async fn outerSize(this: &WindowManager) -> Result<JsValue, JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn isFullscreen(this: &WindowManager) -> JsValue; pub async fn isFullscreen(this: &WindowManager) -> Result<JsValue, JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn isMaximized(this: &WindowManager) -> JsValue; pub async fn isMaximized(this: &WindowManager) -> Result<JsValue, JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn isDecorated(this: &WindowManager) -> JsValue; pub async fn isDecorated(this: &WindowManager) -> Result<JsValue, JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn isResizable(this: &WindowManager) -> JsValue; pub async fn isResizable(this: &WindowManager) -> Result<JsValue, JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn isVisible(this: &WindowManager) -> JsValue; pub async fn isVisible(this: &WindowManager) -> Result<JsValue, JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn theme(this: &WindowManager) -> JsValue; pub async fn theme(this: &WindowManager) -> Result<JsValue, JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn center(this: &WindowManager); pub async fn center(this: &WindowManager) -> Result<(), JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, catch)]
pub async fn requestUserAttention(this: &WindowManager, requestType: u32); pub async fn requestUserAttention(
#[wasm_bindgen(method)] this: &WindowManager,
pub async fn setResizable(this: &WindowManager, resizable: bool); requestType: u32,
#[wasm_bindgen(method)] ) -> Result<(), JsValue>;
pub async fn setTitle(this: &WindowManager, title: &str); #[wasm_bindgen(method, catch)]
#[wasm_bindgen(method)] pub async fn setResizable(this: &WindowManager, resizable: bool) -> Result<(), JsValue>;
pub async fn maximize(this: &WindowManager); #[wasm_bindgen(method, catch)]
#[wasm_bindgen(method)] pub async fn setTitle(this: &WindowManager, title: &str) -> Result<(), JsValue>;
pub async fn unmaximize(this: &WindowManager); #[wasm_bindgen(method, catch)]
#[wasm_bindgen(method)] pub async fn maximize(this: &WindowManager) -> Result<(), JsValue>;
pub async fn toggleMaximize(this: &WindowManager); #[wasm_bindgen(method, catch)]
#[wasm_bindgen(method)] pub async fn unmaximize(this: &WindowManager) -> Result<(), JsValue>;
pub async fn minimize(this: &WindowManager); #[wasm_bindgen(method, catch)]
#[wasm_bindgen(method)] pub async fn toggleMaximize(this: &WindowManager) -> Result<(), JsValue>;
pub async fn unminimize(this: &WindowManager); #[wasm_bindgen(method, catch)]
#[wasm_bindgen(method)] pub async fn minimize(this: &WindowManager) -> Result<(), JsValue>;
pub async fn show(this: &WindowManager); #[wasm_bindgen(method, catch)]
#[wasm_bindgen(method)] pub async fn unminimize(this: &WindowManager) -> Result<(), JsValue>;
pub async fn hide(this: &WindowManager); #[wasm_bindgen(method, catch)]
#[wasm_bindgen(method)] pub async fn show(this: &WindowManager) -> Result<(), JsValue>;
pub async fn close(this: &WindowManager); #[wasm_bindgen(method, catch)]
#[wasm_bindgen(method)] pub async fn hide(this: &WindowManager) -> Result<(), JsValue>;
pub async fn setDecorations(this: &WindowManager, decorations: bool); #[wasm_bindgen(method, catch)]
#[wasm_bindgen(method)] pub async fn close(this: &WindowManager) -> Result<(), JsValue>;
pub async fn setAlwaysOnTop(this: &WindowManager, alwaysOnTop: bool); #[wasm_bindgen(method, catch)]
#[wasm_bindgen(method, js_name = setSize)] pub async fn setDecorations(this: &WindowManager, decorations: bool)
pub async fn setSizePhysical(this: &WindowManager, size: PhysicalSize); -> Result<(), JsValue>;
#[wasm_bindgen(method, js_name = setSize)] #[wasm_bindgen(method, catch)]
pub async fn setSizeLogical(this: &WindowManager, size: LogicalSize); pub async fn setAlwaysOnTop(this: &WindowManager, alwaysOnTop: bool)
#[wasm_bindgen(method, js_name = setMinSize)] -> Result<(), JsValue>;
pub async fn setMinSizePhysical(this: &WindowManager, size: Option<PhysicalSize>); #[wasm_bindgen(method, js_name = setSize, catch)]
#[wasm_bindgen(method, js_name = setMinSize)] pub async fn setSizePhysical(
pub async fn setMinSizeLogical(this: &WindowManager, size: Option<LogicalSize>); this: &WindowManager,
#[wasm_bindgen(method, js_name = setMaxSize)] size: PhysicalSize,
pub async fn setMaxSizePhysical(this: &WindowManager, size: Option<PhysicalSize>); ) -> Result<(), JsValue>;
#[wasm_bindgen(method, js_name = setMinSize)] #[wasm_bindgen(method, js_name = setSize, catch)]
pub async fn setMaxSizeLogical(this: &WindowManager, size: Option<LogicalSize>); pub async fn setSizeLogical(this: &WindowManager, size: LogicalSize)
#[wasm_bindgen(method, js_name = setPosition)] -> Result<(), JsValue>;
pub async fn setPositionPhysical(this: &WindowManager, position: PhysicalPosition); #[wasm_bindgen(method, js_name = setMinSize, catch)]
#[wasm_bindgen(method, js_name = setPosition)] pub async fn setMinSizePhysical(
pub async fn setPositionLogical(this: &WindowManager, position: LogicalPosition); this: &WindowManager,
#[wasm_bindgen(method)] size: Option<PhysicalSize>,
pub async fn setFullscreen(this: &WindowManager, fullscreen: bool); ) -> Result<(), JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, js_name = setMinSize, catch)]
pub async fn setFocus(this: &WindowManager); pub async fn setMinSizeLogical(
#[wasm_bindgen(method)] this: &WindowManager,
pub async fn setIcon(this: &WindowManager, icon: &[u8]); size: Option<LogicalSize>,
#[wasm_bindgen(method)] ) -> Result<(), JsValue>;
pub async fn setSkipTaskbar(this: &WindowManager, skip: bool); #[wasm_bindgen(method, js_name = setMaxSize, catch)]
#[wasm_bindgen(method)] pub async fn setMaxSizePhysical(
pub async fn setCursorGrab(this: &WindowManager, grab: bool); this: &WindowManager,
#[wasm_bindgen(method)] size: Option<PhysicalSize>,
pub async fn setCursorVisible(this: &WindowManager, visible: bool); ) -> Result<(), JsValue>;
#[wasm_bindgen(method)] #[wasm_bindgen(method, js_name = setMinSize, catch)]
pub async fn setCursorIcon(this: &WindowManager, icon: &str); pub async fn setMaxSizeLogical(
#[wasm_bindgen(method, js_name = setCursorPosition)] this: &WindowManager,
pub async fn setCursorPositionPhysical(this: &WindowManager, position: PhysicalPosition); size: Option<LogicalSize>,
#[wasm_bindgen(method, js_name = setCursorPosition)] ) -> Result<(), JsValue>;
pub async fn setCursorPositionLogical(this: &WindowManager, position: LogicalPosition); #[wasm_bindgen(method, js_name = setPosition, catch)]
#[wasm_bindgen(method)] pub async fn setPositionPhysical(
pub async fn setIgnoreCursorEvents(this: &WindowManager, ignore: bool); this: &WindowManager,
#[wasm_bindgen(method)] position: PhysicalPosition,
pub async fn startDragging(this: &WindowManager); ) -> Result<(), JsValue>;
#[wasm_bindgen(method, js_name = setPosition, catch)]
pub async fn setPositionLogical(
this: &WindowManager,
position: LogicalPosition,
) -> Result<(), JsValue>;
#[wasm_bindgen(method, catch)]
pub async fn setFullscreen(this: &WindowManager, fullscreen: bool) -> Result<(), JsValue>;
#[wasm_bindgen(method, catch)]
pub async fn setFocus(this: &WindowManager) -> Result<(), JsValue>;
#[wasm_bindgen(method, catch)]
pub async fn setIcon(this: &WindowManager, icon: &[u8]) -> Result<(), JsValue>;
#[wasm_bindgen(method, catch)]
pub async fn setSkipTaskbar(this: &WindowManager, skip: bool) -> Result<(), JsValue>;
#[wasm_bindgen(method, catch)]
pub async fn setCursorGrab(this: &WindowManager, grab: bool) -> Result<(), JsValue>;
#[wasm_bindgen(method, catch)]
pub async fn setCursorVisible(this: &WindowManager, visible: bool) -> Result<(), JsValue>;
#[wasm_bindgen(method, catch)]
pub async fn setCursorIcon(this: &WindowManager, icon: &str) -> Result<(), JsValue>;
#[wasm_bindgen(method, js_name = setCursorPosition, catch)]
pub async fn setCursorPositionPhysical(
this: &WindowManager,
position: PhysicalPosition,
) -> Result<(), JsValue>;
#[wasm_bindgen(method, js_name = setCursorPosition, catch)]
pub async fn setCursorPositionLogical(
this: &WindowManager,
position: LogicalPosition,
) -> Result<(), JsValue>;
#[wasm_bindgen(method, catch)]
pub async fn setIgnoreCursorEvents(
this: &WindowManager,
ignore: bool,
) -> Result<(), JsValue>;
#[wasm_bindgen(method, catch)]
pub async fn startDragging(this: &WindowManager) -> Result<(), JsValue>;
} }
#[wasm_bindgen(module = "/dist/window.js")] #[wasm_bindgen(module = "/dist/window.js")]