cleanup & polish

This commit is contained in:
Jonas Kruckenberg 2022-11-17 18:13:39 +01:00
parent ee68fe6b5b
commit d5fa1c0397
15 changed files with 657 additions and 470 deletions

View file

@ -23,7 +23,7 @@ pub async fn get_version() -> anyhow::Result<()> {
pub async fn get_tauri_version() -> anyhow::Result<()> {
let version = app::get_tauri_version().await?;
ensure!(version.major == 1);
ensure!(version.minor == 2);
ensure!(version.patch == 0);

View file

@ -1,10 +1,10 @@
use anyhow::ensure;
use tauri_sys::dialog::{FileDialogBuilder, MessageDialogBuilder, MessageDialogType};
use tauri_sys::dialog::{FileDialogBuilder, MessageDialogBuilder, MessageDialogKind};
pub async fn ask() -> anyhow::Result<()> {
let mut builder = MessageDialogBuilder::new();
builder.set_title("Tauri");
builder.set_type(MessageDialogType::Warning);
builder.set_type(MessageDialogKind::Warning);
let works = builder
.ask("Does this work? \n Click Yes to mark this test as passing")
@ -18,7 +18,7 @@ pub async fn ask() -> anyhow::Result<()> {
pub async fn confirm() -> anyhow::Result<()> {
let mut builder = MessageDialogBuilder::new();
builder.set_title("Tauri");
builder.set_type(MessageDialogType::Warning);
builder.set_type(MessageDialogKind::Warning);
let works = builder
.confirm("Does this work? \n Click Ok to mark this test as passing")
@ -32,7 +32,7 @@ pub async fn confirm() -> anyhow::Result<()> {
pub async fn message() -> anyhow::Result<()> {
let mut builder = MessageDialogBuilder::new();
builder.set_title("Tauri");
builder.set_type(MessageDialogType::Warning);
builder.set_type(MessageDialogKind::Warning);
builder.message("This is a message just for you!").await?;
@ -94,4 +94,4 @@ pub async fn save() -> anyhow::Result<()> {
ensure!(file.is_some());
Ok(())
}
}

View file

@ -19,10 +19,10 @@ pub async fn request_permission() -> anyhow::Result<()> {
pub async fn show_notification() -> anyhow::Result<()> {
let mut n = notification::Notification::default();
n.set_title("TAURI");
n.set_body("Tauri is awesome!");
n.set_title("TAURI");
n.set_body("Tauri is awesome!");
n.show()?;
Ok(())
}
}

View file

@ -38,4 +38,4 @@ pub async fn version() -> anyhow::Result<()> {
log::debug!("{:?}", version);
Ok(())
}
}

View file

@ -47,7 +47,7 @@ pub async fn get_tauri_version() -> crate::Result<Version> {
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 focus the apps windows.
///
/// # Example
///

View file

@ -1,13 +1,16 @@
use serde::Serialize;
use std::path::{Path, PathBuf};
#[derive(Debug, Serialize)]
#[derive(Debug, Clone, Copy, Hash, Serialize)]
struct DialogFilter<'a> {
extensions: &'a [&'a str],
name: &'a str,
}
#[derive(Debug, Default, Serialize)]
/// The file dialog builder.
///
/// Constructs file picker dialogs that can select single/multiple files or directories.
#[derive(Debug, Default, Clone, Hash, Serialize)]
#[serde(rename = "camelCase")]
pub struct FileDialogBuilder<'a> {
default_path: Option<&'a Path>,
@ -203,31 +206,24 @@ impl<'a> FileDialogBuilder<'a> {
}
}
#[derive(Debug, Default)]
pub enum MessageDialogType {
/// Types of message, ask and confirm dialogs.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub enum MessageDialogKind {
#[default]
#[serde(rename = "info")]
Info,
#[serde(rename = "warning")]
Warning,
#[serde(rename = "error")]
Error,
}
impl Serialize for MessageDialogType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
MessageDialogType::Info => serializer.serialize_str("info"),
MessageDialogType::Warning => serializer.serialize_str("warning"),
MessageDialogType::Error => serializer.serialize_str("error"),
}
}
}
#[derive(Debug, Default, Serialize)]
/// A builder for message dialogs.
#[derive(Debug, Default, Clone, Copy, Hash, Serialize)]
pub struct MessageDialogBuilder<'a> {
title: Option<&'a str>,
r#type: MessageDialogType,
#[serde(rename = "type")]
kind: MessageDialogKind,
}
impl<'a> MessageDialogBuilder<'a> {
@ -256,19 +252,19 @@ impl<'a> MessageDialogBuilder<'a> {
/// # Example
///
/// ```rust
/// use tauri_sys::dialog::{MessageDialogBuilder,MessageDialogType};
/// use tauri_sys::dialog::{MessageDialogBuilder,MessageDialogKind};
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let _builder = MessageDialogBuilder::new().set_type(MessageDialogType::Error);
/// let _builder = MessageDialogBuilder::new().set_kind(MessageDialogKind::Error);
/// # Ok(())
/// # }
/// ```
pub fn set_type(&mut self, r#type: MessageDialogType) {
self.r#type = r#type;
pub fn set_kind(&mut self, r#kind: MessageDialogKind) {
self.kind = r#kind;
}
/// Shows a message dialog with an `Ok` button.
///
///
/// # Example
///
/// ```rust,no_run
@ -284,7 +280,7 @@ impl<'a> MessageDialogBuilder<'a> {
}
/// Shows a question dialog with `Yes` and `No` buttons.
///
///
/// # Example
///
/// ```rust,no_run
@ -302,7 +298,7 @@ impl<'a> MessageDialogBuilder<'a> {
}
/// Shows a question dialog with `Ok` and `Cancel` buttons.
///
///
/// # Example
///
/// ```rust,no_run
@ -320,271 +316,6 @@ impl<'a> MessageDialogBuilder<'a> {
}
}
// //! User interaction with the file system using dialog boxes.
// //!
// //! # Example
// //!
// //! ```rust,no_run
// //! use tauri_api::dialog::open;
// //!
// //! let path = open(None).await;
// //! ```
// use serde::Serialize;
// use std::path::PathBuf;
// /// Extension filter for the file dialog.
// ///
// /// # Example
// ///
// /// ```rust,no_run
// /// let filter = DialogFilter {
// /// extension: vec![".jpg", ".jpeg", ".png", ".bmp"],
// /// name: "images",
// /// };
// /// ```
// #[derive(Serialize)]
// pub struct DialogFilter {
// /// Extensions to filter, without a `.` prefix.
// pub extensions: Vec<String>,
// /// Filter name
// pub name: String,
// }
// /// Types of a [`message`] dialog.
// #[derive(Serialize)]
// pub enum MessageDialogType {
// Error,
// Info,
// Warning,
// }
// /// Options for the [`message`] dialog.
// #[derive(Serialize)]
// pub struct MessageDialogOptions {
// /// The title of the dialog. Defaults to the app name.
// pub title: Option<String>,
// /// The type of the dialog. Defaults to MessageDialogType::Info.
// #[serde(rename(serialize = "type"))]
// pub kind: MessageDialogType,
// }
// impl MessageDialogOptions {
// /// Creates a new `MessageDialogOptions` with sensible default values.
// pub fn new() -> Self {
// Self {
// title: None,
// kind: MessageDialogType::Info,
// }
// }
// }
// /// Options for an [`open`] dialog.
// #[derive(Serialize)]
// pub struct OpenDialogOptions {
// /// Initial directory or file path.
// #[serde(rename(serialize = "defaultPath"))]
// pub default_path: Option<PathBuf>,
// /// Whether the dialog is a directory selection or not.
// pub directory: bool,
// /// The filters of the dialog.
// pub filters: Vec<DialogFilter>,
// /// Whether the dialog allows multiple selection or not.
// pub multiple: bool,
// /// If `directory` is `true`, indicatees that it will be read recursivley later.
// /// Defines whether subdirectories will be allowed on the scope or not.
// pub recursive: bool,
// /// The title of the dialog window.
// pub title: Option<String>,
// }
// impl OpenDialogOptions {
// /// Creates a new `OpenDialogOptions` with sensible default values.
// pub fn new() -> Self {
// Self {
// default_path: None,
// directory: false,
// filters: Vec::new(),
// multiple: false,
// recursive: false,
// title: None,
// }
// }
// }
// /// Options for the save dialog.
// #[derive(Serialize)]
// pub struct SaveDialogOptions {
// /// Initial directory of the file path.
// /// If it's not a directory path, the dialog interface will change to that folder.
// /// If it's not an existing directory, the file name will be set to the dialog's
// /// file name input and the dialog will be set to the parent folder.
// #[serde(rename(serialize = "defaultPath"))]
// pub default_path: Option<PathBuf>,
// /// The filters of the dialog.
// pub filters: Vec<DialogFilter>,
// /// The title of the dialog window.
// pub title: Option<String>,
// }
// impl SaveDialogOptions {
// /// Creates a new `SaveDialogOptions` with sensible default values.
// pub fn new() -> Self {
// Self {
// default_path: None,
// filters: Vec::new(),
// title: None,
// }
// }
// }
// /// Show a question dialog with `Yes` and `No` buttons.
// ///
// /// # Example
// ///
// /// ```rust,no_run
// /// use tauri_api::dialog::{ask, MessageDialogOptions};
// ///
// /// let yes = ask("Are you sure?", None).await;
// /// ```
// /// @param message Message to display.
// /// @param options Dialog options.
// /// @returns Whether the user selected `Yes` or `No`.
// #[inline(always)]
// pub async fn ask(message: &str, options: Option<MessageDialogOptions>) -> crate::Result<bool> {
// let js_val = inner::ask(message, serde_wasm_bindgen::to_value(&options)?).await?;
// Ok(serde_wasm_bindgen::from_value(js_val)?)
// }
// /// Shows a question dialog with `Ok` and `Cancel` buttons.
// ///
// /// # Example
// ///
// /// ```rust,no_run
// /// use tauri_api::dialog::{confirm, MessageDialogOptions};
// ///
// /// let confirmed = confirm("Are you sure?", None).await;
// /// ```
// /// @returns Whether the user selelced `Ok` or `Cancel`.
// pub async fn confirm(message: &str, options: Option<MessageDialogOptions>) -> crate::Result<bool> {
// let js_val = inner::confirm(message, serde_wasm_bindgen::to_value(&options)?).await?;
// Ok(serde_wasm_bindgen::from_value(js_val)?)
// }
// /// Shows a message dialog with an `Ok` button.
// ///
// /// # Example
// ///
// /// ```rust,no_run
// /// use tauri_api::dialog::{message, MessageDialogOptions};
// ///
// /// message("Tauri is awesome", None).await;
// /// ```
// /// @param message Message to display.
// /// @param options Dialog options.
// /// @returns Promise resolved when user closes the dialog.
// pub async fn message(message: &str, options: Option<MessageDialogOptions>) -> crate::Result<()> {
// Ok(inner::message(message, serde_wasm_bindgen::to_value(&options)?).await?)
// }
// /// Opens a file/directory selection dialog for a single file.
// /// `multiple` field of [`options`](OpenDialogOptions) must be `false`, if provided.
// ///
// /// The selected paths are added to the filesystem and asset protocol allowlist scopes.
// /// When security is mroe important than the ease of use of this API,
// /// prefer writing a dedicated command instead.
// ///
// /// Note that the allowlist scope change is not persisited,
// /// so the values are cleared when the applicaiton is restarted.
// /// You can save it to the filessytem using the [tauri-plugin-persisted-scope](https://github.com/tauri-apps/tauri-plugin-persisted-scope).
// ///
// /// # Example
// ///
// /// ```rust,no_run
// /// use tauri_api::dialog::{open, OpenDialogOptions};
// ///
// /// let file = open(None).await;
// ///
// /// let mut opts = OpenDialogOptions::new();
// /// opts.directory = true;
// /// let dir = open(Some(opts)).await;
// /// ```
// /// @param options Dialog options.
// /// @returns List of file paths, or `None` if user cancelled the dialog.
// pub async fn open(options: Option<OpenDialogOptions>) -> crate::Result<Option<PathBuf>> {
// let file = inner::open(serde_wasm_bindgen::to_value(&options)?).await?;
// Ok(serde_wasm_bindgen::from_value(file)?)
// }
// /// Opens a file/directory selection dialog for multiple files.
// /// `multiple` field of [`options`](OpenDialogOptions) must be `true`, if provided.
// ///
// /// The selected paths are added to the filesystem and asset protocol allowlist scopes.
// /// When security is mroe important than the ease of use of this API,
// /// prefer writing a dedicated command instead.
// ///
// /// Note that the allowlist scope change is not persisited,
// /// so the values are cleared when the applicaiton is restarted.
// /// You can save it to the filessytem using the [tauri-plugin-persisted-scope](https://github.com/tauri-apps/tauri-plugin-persisted-scope).
// ///
// /// # Example
// ///
// /// ```rust,no_run
// /// use tauri_api::dialog::{open, OpenDialogOptions};
// ///
// /// let files = open_multiple(None).await;
// ///
// /// let mut opts = OpenDialogOptions::new();
// /// opts.multiple = true;
// /// opts.directory = true;
// /// let dirs = open(Some(opts)).await;
// /// ```
// /// @param options Dialog options.
// /// @returns List of file paths, or `None` if user cancelled the dialog.
// pub async fn open_multiple(
// options: Option<OpenDialogOptions>,
// ) -> crate::Result<Option<Vec<PathBuf>>> {
// let files = inner::open_multiple(serde_wasm_bindgen::to_value(&options)?).await?;
// Ok(serde_wasm_bindgen::from_value(files)?)
// }
// /// Opens a file/directory save dialog.
// ///
// /// The selected paths are added to the filesystem and asset protocol allowlist scopes.
// /// When security is mroe important than the ease of use of this API,
// /// prefer writing a dedicated command instead.
// ///
// /// Note that the allowlist scope change is not persisited,
// /// so the values are cleared when the applicaiton is restarted.
// /// You can save it to the filessytem using the [tauri-plugin-persisted-scope](https://github.com/tauri-apps/tauri-plugin-persisted-scope).
// ///
// /// # Example
// ///
// /// ```rust,no_run
// /// use tauri_api::dialog::{save, SaveDialogOptions};
// ///
// /// let file = save(None).await;
// /// ```
// /// @param options Dialog options.
// /// @returns File path, or `None` if user cancelled the dialog.
// pub async fn save(options: Option<SaveDialogOptions>) -> crate::Result<Option<PathBuf>> {
// let path = inner::save(serde_wasm_bindgen::to_value(&options)?).await?;
// Ok(serde_wasm_bindgen::from_value(path)?)
// }
mod inner {
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};

View file

@ -2,7 +2,7 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::fmt::Debug;
use wasm_bindgen::{prelude::Closure, JsValue};
#[derive(Deserialize)]
#[derive(Debug, Clone, Hash, Deserialize)]
pub struct Event<T> {
/// Event name
pub event: String,
@ -14,17 +14,6 @@ pub struct Event<T> {
pub window_label: String,
}
impl<T: Debug> Debug for Event<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Event")
.field("event", &self.event)
.field("id", &self.id)
.field("payload", &self.payload)
.field("window_label", &self.window_label)
.finish()
}
}
/// Emits an event to the backend.
///
/// # Example
@ -56,9 +45,10 @@ pub async fn emit<T: Serialize>(event: &str, payload: &T) -> crate::Result<()> {
///
/// ```rust,no_run
/// use tauri_api::event::{emit, listen};
/// use web_sys::console;
///
/// const unlisten = listen::<String>("error", |event| {
/// println!("Got error in window {}, payload: {}", event.window_label, event.payload);
/// console::log_1(&format!("Got error in window {}, payload: {}", event.window_label, event.payload).into());
/// }).await;
///
/// // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
@ -96,6 +86,7 @@ where
/// ```rust,no_run
/// use tauri_api::event::once;
/// use serde::Deserialize;
/// use web_sys::console;
///
/// #[derive(Deserialize)]
/// interface LoadedPayload {
@ -103,7 +94,7 @@ where
/// token: String
/// }
/// const unlisten = once::<LoadedPayload>("loaded", |event| {
/// println!("App is loaded, loggedIn: {}, token: {}", event.payload.logged_in, event.payload.token);
/// console::log_1!(&format!("App is loaded, loggedIn: {}, token: {}", event.payload.logged_in, event.payload.token).into());
/// }).await;
///
/// // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted

View file

@ -10,6 +10,12 @@ pub mod dialog;
pub mod event;
#[cfg(feature = "mocks")]
pub mod mocks;
#[cfg(feature = "notification")]
pub mod notification;
#[cfg(feature = "os")]
pub mod os;
#[cfg(feature = "path")]
pub mod path;
#[cfg(feature = "process")]
pub mod process;
#[cfg(feature = "tauri")]
@ -18,12 +24,6 @@ pub mod tauri;
pub mod updater;
#[cfg(feature = "window")]
pub mod window;
#[cfg(feature = "notification")]
pub mod notification;
#[cfg(feature = "os")]
pub mod os;
#[cfg(feature = "path")]
pub mod path;
#[derive(Debug, thiserror::Error)]
pub enum Error {
@ -31,12 +31,14 @@ pub enum Error {
Serde(String),
#[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}")]
Other(String),
#[cfg(feature = "tauri")]
#[error("Invalid Url {0}")]
InvalidUrl(#[from] url::ParseError),
#[cfg(feature = "app")]
#[error("Invalid Version {0}")]
InvalidVersion(#[from] semver::Error),
}
impl From<serde_wasm_bindgen::Error> for Error {

View file

@ -1,5 +1,17 @@
use serde::{Deserialize, Serialize};
/// Checks if the permission to send notifications is granted.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::notification;
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let is_granted = notification::is_permission_granted().await?;
/// # Ok(())
/// # }
/// ```
#[inline(always)]
pub async fn is_permission_granted() -> crate::Result<bool> {
let raw = inner::isPermissionGranted().await?;
@ -7,6 +19,18 @@ pub async fn is_permission_granted() -> crate::Result<bool> {
Ok(serde_wasm_bindgen::from_value(raw)?)
}
/// Requests the permission to send notifications.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::notification;
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let perm = notification::request_permission().await?;
/// # Ok(())
/// # }
/// ```
#[inline(always)]
pub async fn request_permission() -> crate::Result<Permission> {
let raw = inner::requestPermission().await?;
@ -14,6 +38,7 @@ pub async fn request_permission() -> crate::Result<Permission> {
Ok(serde_wasm_bindgen::from_value(raw)?)
}
/// Possible permission values.
#[derive(Debug, Deserialize, Default, Clone, Copy, PartialEq, Eq)]
pub enum Permission {
#[default]
@ -25,34 +50,55 @@ pub enum Permission {
Denied,
}
/// The desktop notification definition.
///
/// Allows you to construct a Notification data and send it.
#[derive(Debug, Default, Serialize)]
pub struct Notification<'a> {
body: Option<&'a str>,
title: Option<&'a str>,
icon: Option<&'a str>
}
icon: Option<&'a str>,
}
impl<'a> Notification<'a> {
pub fn new() -> Self {
Self::default()
}
/// Sets the notification title.
pub fn set_title(&mut self, title: &'a str) {
self.title = Some(title);
}
/// Sets the notification body.
pub fn set_body(&mut self, body: &'a str) {
self.body = Some(body);
}
/// Sets the notification icon.
pub fn set_icon(&mut self, icon: &'a str) {
self.icon = Some(icon);
}
/// Shows the notification.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::notification::Notification;
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// Notification::new()
/// .set_title("Tauri")
/// .set_body("Tauri is awesome!")
/// .show()?;
/// # Ok(())
/// # }
/// ```
#[inline(always)]
pub fn show(&self) -> crate::Result<()> {
inner::sendNotification(serde_wasm_bindgen::to_value(&self)?)?;
Ok(())
}
}

View file

@ -58,7 +58,7 @@ pub enum OsKind {
#[serde(rename = "Darwin")]
Darwin,
#[serde(rename = "Windows_NT")]
WindowsNt,
WindowsNT,
}
/// Returns the operating system CPU architecture for which the tauri app was compiled.
@ -85,7 +85,7 @@ pub async fn tempdir() -> crate::Result<PathBuf> {
Ok(serde_wasm_bindgen::from_value(raw)?)
}
/// Returns 'OsKind::Linux' on Linux, 'OsKind::Darwin' on macOS, and 'OsKind::WindowsNT' on Windows.
/// Returns [`OsKind::Linux`] on Linux, [`OsKind::Darwin`] on macOS, and [`OsKind::WindowsNT`] on Windows.
#[inline(always)]
pub async fn kind() -> crate::Result<OsKind> {
let raw = inner::kind().await?;

View file

@ -2,13 +2,14 @@ use std::path::PathBuf;
use wasm_bindgen::JsValue;
/// Returns the path to the suggested directory for your app's config files.
///
/// Resolves to `${configDir}/${bundleIdentifier}`, where `bundleIdentifier` is the value [`tauri.bundle.identifier`](https://tauri.app/v1/api/config/#bundleconfig.identifier) is configured in `tauri.conf.json`.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::app_config_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let app_config_dir_path = app_config_dir().await?;
/// # Ok(())
@ -22,13 +23,14 @@ pub async fn app_config_dir() -> crate::Result<PathBuf> {
}
/// Returns the path to the suggested directory for your app's data files.
///
/// Resolves to `${dataDir}/${bundleIdentifier}`, where `bundleIdentifier` is the value [`tauri.bundle.identifier`](https://tauri.app/v1/api/config/#bundleconfig.identifier) is configured in `tauri.conf.json`.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::app_data_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let app_data_dir_path = app_data_dir().await?;
/// # Ok(())
@ -42,13 +44,14 @@ pub async fn app_data_dir() -> crate::Result<PathBuf> {
}
/// Returns the path to the suggested directory for your app's local data files.
///
/// Resolves to `${localDataDir}/${bundleIdentifier}`, where `bundleIdentifier` is the value [`tauri.bundle.identifier`](https://tauri.app/v1/api/config/#bundleconfig.identifier) is configured in `tauri.conf.json`.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::app_local_data_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let app_local_data_dir_path = app_local_data_dir().await?;
/// # Ok(())
@ -62,13 +65,14 @@ pub async fn app_local_data_dir() -> crate::Result<PathBuf> {
}
/// Returns the path to the suggested directory for your app's cache files.
///
/// Resolves to `${cacheDir}/${bundleIdentifier}`, where `bundleIdentifier` is the value [`tauri.bundle.identifier`](https://tauri.app/v1/api/config/#bundleconfig.identifier) is configured in `tauri.conf.json`.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::app_cache_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let app_cache_dir_path = app_cache_dir().await?;
/// # Ok(())
@ -85,15 +89,15 @@ pub async fn app_cache_dir() -> crate::Result<PathBuf> {
///
/// #### Platform-specific
///
/// -///*Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_MUSIC_DIR`.
/// -///*macOS:** Resolves to `$HOME/Music`.
/// -///*Windows:** Resolves to `{FOLDERID_Music}`.
/// - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_MUSIC_DIR`.
/// - **macOS:** Resolves to `$HOME/Music`.
/// - **Windows:** Resolves to `{FOLDERID_Music}`.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::audio_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let audio_dir_path = audio_dir().await?;
/// # Ok(())
@ -110,15 +114,15 @@ pub async fn audio_dir() -> crate::Result<PathBuf> {
///
/// #### Platform-specific
///
/// -///*Linux:** Resolves to `$XDG_CACHE_HOME` or `$HOME/.cache`.
/// -///*macOS:** Resolves to `$HOME/Library/Caches`.
/// -///*Windows:** Resolves to `{FOLDERID_LocalAppData}`.
/// - **Linux:** Resolves to `$XDG_CACHE_HOME` or `$HOME/.cache`.
/// - **macOS:** Resolves to `$HOME/Library/Caches`.
/// - **Windows:** Resolves to `{FOLDERID_LocalAppData}`.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::cache_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let cache_dir_path = cache_dir().await?;
/// # Ok(())
@ -135,15 +139,15 @@ pub async fn cache_dir() -> crate::Result<PathBuf> {
///
/// #### Platform-specific
///
/// -///*Linux:** Resolves to `$XDG_CONFIG_HOME` or `$HOME/.config`.
/// -///*macOS:** Resolves to `$HOME/Library/Application Support`.
/// -///*Windows:** Resolves to `{FOLDERID_RoamingAppData}`.
/// - **Linux:** Resolves to `$XDG_CONFIG_HOME` or `$HOME/.config`.
/// - **macOS:** Resolves to `$HOME/Library/Application Support`.
/// - **Windows:** Resolves to `{FOLDERID_RoamingAppData}`.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::config_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let config_dir_path = config_dir().await?;
/// # Ok(())
@ -160,15 +164,15 @@ pub async fn config_dir() -> crate::Result<PathBuf> {
///
/// #### Platform-specific
///
/// -///*Linux:** Resolves to `$XDG_DATA_HOME` or `$HOME/.local/share`.
/// -///*macOS:** Resolves to `$HOME/Library/Application Support`.
/// -///*Windows:** Resolves to `{FOLDERID_RoamingAppData}`.
/// - **Linux:** Resolves to `$XDG_DATA_HOME` or `$HOME/.local/share`.
/// - **macOS:** Resolves to `$HOME/Library/Application Support`.
/// - **Windows:** Resolves to `{FOLDERID_RoamingAppData}`.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::data_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let data_dir_path = data_dir().await?;
/// # Ok(())
@ -185,15 +189,15 @@ pub async fn data_dir() -> crate::Result<PathBuf> {
///
/// #### Platform-specific
///
/// -///*Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_DESKTOP_DIR`.
/// -///*macOS:** Resolves to `$HOME/Desktop`.
/// -///*Windows:** Resolves to `{FOLDERID_Desktop}`.
/// - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_DESKTOP_DIR`.
/// - **macOS:** Resolves to `$HOME/Desktop`.
/// - **Windows:** Resolves to `{FOLDERID_Desktop}`.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::desktop_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let desktop_dir_path = desktop_dir().await?;
/// # Ok(())
@ -213,12 +217,12 @@ pub async fn desktop_dir() -> crate::Result<PathBuf> {
/// - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_DOCUMENTS_DIR`.
/// - **macOS:** Resolves to `$HOME/Documents`.
/// - **Windows:** Resolves to `{FOLDERID_Documents}`.
///
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::document_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let document_dir_path = document_dir().await?;
/// # Ok(())
@ -243,7 +247,7 @@ pub async fn document_dir() -> crate::Result<PathBuf> {
///
/// ```rust,no_run
/// use tauri_sys::path::download_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let download_dir_path = download_dir().await?;
/// # Ok(())
@ -268,7 +272,7 @@ pub async fn download_dir() -> crate::Result<PathBuf> {
///
/// ```rust,no_run
/// use tauri_sys::path::executable_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let executable_dir_path = executable_dir().await?;
/// # Ok(())
@ -293,7 +297,7 @@ pub async fn executable_dir() -> crate::Result<PathBuf> {
///
/// ```rust,no_run
/// use tauri_sys::path::font_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let font_dir_path = font_dir().await?;
/// # Ok(())
@ -318,7 +322,7 @@ pub async fn font_dir() -> crate::Result<PathBuf> {
///
/// ```rust,no_run
/// use tauri_sys::path::home_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let home_dir_path = home_dir().await?;
/// # Ok(())
@ -343,7 +347,7 @@ pub async fn home_dir() -> crate::Result<PathBuf> {
///
/// ```rust,no_run
/// use tauri_sys::path::local_data_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let local_data_dir_path = local_data_dir().await?;
/// # Ok(())
@ -368,7 +372,7 @@ pub async fn local_data_dir() -> crate::Result<PathBuf> {
///
/// ```rust,no_run
/// use tauri_sys::path::picture_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let picture_dir_path = picture_dir().await?;
/// # Ok(())
@ -393,7 +397,7 @@ pub async fn picture_dir() -> crate::Result<PathBuf> {
///
/// ```rust,no_run
/// use tauri_sys::path::public_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let public_dir_path = public_dir().await?;
/// # Ok(())
@ -407,13 +411,14 @@ pub async fn public_dir() -> crate::Result<PathBuf> {
}
/// Returns the path to the application's resource directory.
/// To resolve a resource path, see the [[resolveResource | `resolveResource API`]].
///
/// To resolve a resource path, see the [`resolve_resource`] function.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::resource_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let resource_dir_path = resource_dir().await?;
/// # Ok(())
@ -431,10 +436,10 @@ pub async fn resource_dir() -> crate::Result<PathBuf> {
/// @param resourcePath The path to the resource.
/// Must follow the same syntax as defined in `tauri.conf.json > tauri > bundle > resources`, i.e. keeping subfolders and parent dir components (`../`).
/// @returns The full path to the resource.
///
///
/// ```rust,no_run
/// use tauri_sys::path::resolve_resource;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let resource_path = resolve_resource("script.sh").await?;
/// # Ok(())
@ -451,15 +456,15 @@ pub async fn resolve_resource(resource_path: &str) -> crate::Result<PathBuf> {
///
/// #### Platform-specific
///
/// -///*Linux:** Resolves to `$XDG_RUNTIME_DIR`.
/// -///*macOS:** Not supported.
/// -///*Windows:** Not supported.
/// - **Linux:** Resolves to `$XDG_RUNTIME_DIR`.
/// - **macOS:** Not supported.
/// - **Windows:** Not supported.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::runtime_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let runtime_dir_path = runtime_dir().await?;
/// # Ok(())
@ -476,15 +481,15 @@ pub async fn runtime_dir() -> crate::Result<PathBuf> {
///
/// #### Platform-specific
///
/// -///*Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_TEMPLATES_DIR`.
/// -///*macOS:** Not supported.
/// -///*Windows:** Resolves to `{FOLDERID_Templates}`.
/// - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_TEMPLATES_DIR`.
/// - **macOS:** Not supported.
/// - **Windows:** Resolves to `{FOLDERID_Templates}`.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::template_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let template_dir_path = template_dir().await?;
/// # Ok(())
@ -501,15 +506,15 @@ pub async fn template_dir() -> crate::Result<PathBuf> {
///
/// #### Platform-specific
///
/// -///*Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_VIDEOS_DIR`.
/// -///*macOS:** Resolves to `$HOME/Movies`.
/// -///*Windows:** Resolves to `{FOLDERID_Videos}`.
/// - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_VIDEOS_DIR`.
/// - **macOS:** Resolves to `$HOME/Movies`.
/// - **Windows:** Resolves to `{FOLDERID_Videos}`.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::video_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let video_dir_path = video_dir().await?;
/// # Ok(())
@ -534,7 +539,7 @@ pub async fn video_dir() -> crate::Result<PathBuf> {
///
/// ```rust,no_run
/// use tauri_sys::path::app_log_dir;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let app_log_dir_path = app_log_dir().await?;
/// # Ok(())
@ -553,10 +558,10 @@ pub async fn app_log_dir() -> crate::Result<PathBuf> {
///
/// ```rust,no_run
/// use tauri_sys::path::{resolve, app_data_dir};
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let app_data_dir_path = app_data_dir().await?;
///
///
/// let path = resolve([app_data_dir_path, "..", "users", "tauri", "avatar.png"]).await?;
/// # Ok(())
/// # }
@ -575,10 +580,10 @@ pub async fn resolve(paths: impl IntoIterator<Item = &str>) -> crate::Result<Pat
///
/// ```rust,no_run
/// use tauri_sys::path::{normalize, app_data_dir};
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let app_data_dir_path = app_data_dir().await?;
///
///
/// let path = normalize([app_data_dir_path, "..", "users", "tauri", "avatar.png"]).await?;
/// # Ok(())
/// # }
@ -596,10 +601,10 @@ pub async fn normalize(path: &str) -> crate::Result<PathBuf> {
///
/// ```rust,no_run
/// use tauri_sys::path::{join, app_data_dir};
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let app_data_dir_path = app_data_dir().await?;
///
///
/// let path = join([app_data_dir_path, "..", "users", "tauri", "avatar.png"]).await?;
/// # Ok(())
/// # }
@ -618,10 +623,10 @@ pub async fn join(paths: impl IntoIterator<Item = &str>) -> crate::Result<PathBu
///
/// ```rust,no_run
/// use tauri_sys::path::{dirname, app_data_dir};
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let app_data_dir_path = app_data_dir().await?;
///
///
/// let dir = dirname(app_data_dir_path).await?;
/// # Ok(())
/// # }
@ -639,7 +644,7 @@ pub async fn dirname(path: &str) -> crate::Result<PathBuf> {
///
/// ```rust,no_run
/// use tauri_sys::path::{extname, resolve_resource};
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let resource_path = await resolve_resource("app.conf").await?;
/// let ext = extname(resource_path).await?;
@ -657,12 +662,12 @@ pub async fn extname(path: &str) -> crate::Result<PathBuf> {
/// Returns the last portion of a `path`. Trailing directory separators are ignored.
///
/// @param ext An optional file extension to be removed from the returned path.
///
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::path::{basename, resolve_resource};
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let resource_path = await resolve_resource("app.conf").await?;
/// let ext = basename(resource_path).await?;
@ -687,7 +692,7 @@ pub async fn basename(path: &str, ext: Option<&str>) -> crate::Result<PathBuf> {
///
/// ```rust,no_run
/// use tauri_sys::path::is_absolute;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// assert!(is_absolute("/home/tauri").await?);
/// # Ok(())

View file

@ -1,9 +1,11 @@
/// Exits immediately with the given `exit_code`.
#[inline(always)]
pub async fn exit(exit_code: u32) -> ! {
pub async fn exit(exit_code: i32) -> ! {
inner::exit(exit_code).await;
unreachable!()
}
/// Exits the current instance of the app then relaunches it.
#[inline(always)]
pub fn relaunch() {
inner::relaunch();
@ -14,7 +16,7 @@ mod inner {
#[wasm_bindgen(module = "/src/process.js")]
extern "C" {
pub async fn exit(exitCode: u32);
pub async fn exit(exitCode: i32);
pub fn relaunch();
}
}

View file

@ -2,6 +2,7 @@ use serde::{de::DeserializeOwned, Serialize};
use url::Url;
/// 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`.
/// Example CSP value: `"csp": "default-src 'self'; img-src 'self' asset: https://asset.localhost"` to use the asset protocol on image sources.
///
@ -68,6 +69,7 @@ pub async fn invoke<A: Serialize, R: DeserializeOwned>(cmd: &str, args: &A) -> c
}
/// Transforms a callback function to a string identifier that can be passed to the backend.
///
/// The backend uses the identifier to `eval()` the callback.
///
/// @return A unique identifier associated with the callback function.

View file

@ -5,19 +5,19 @@ use wasm_bindgen::{prelude::Closure, JsValue};
pub struct UpdateManifest {
pub body: String,
pub date: String,
pub version: String
pub version: String,
}
#[derive(Deserialize, Debug, Clone)]
pub struct UpdateResult {
pub manifest: Option<UpdateManifest>,
pub should_update: bool
pub should_update: bool,
}
#[derive(Deserialize)]
struct UpdateStatusResult {
error: Option<String>,
status: UpdateStatus
status: UpdateStatus,
}
#[derive(Deserialize)]
@ -27,16 +27,16 @@ pub enum UpdateStatus {
#[serde(rename = "DONE")]
Done,
#[serde(rename = "UPTODATE")]
UpToDate
UpToDate,
}
/// Checks if an update is available.
///
///
/// # Example
///
///
/// ```rust,no_run
/// use tauri_sys::updater::check_update;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let update = check_update().await?;
/// // now run installUpdate() if needed
@ -51,15 +51,15 @@ pub async fn check_update() -> crate::Result<UpdateResult> {
}
/// Install the update if there's one available.
///
///
/// # Example
///
///
/// ```rust,no_run
/// use tauri_sys::updater::{check_update, install_update};
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let update = check_update().await?;
///
///
/// if update.should_update {
/// log::info("Installing update {:?}", update.manifest);
/// install_update().await?;
@ -74,17 +74,17 @@ pub async fn install_update() -> crate::Result<()> {
}
/// Listen to an updater event.
///
///
/// # Example
///
///
/// ```rust,no_run
/// use tauri_sys::updater::on_updater_event;
///
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let unlisten = on_updater_event(|event| {
/// log::debug!("Updater event {:?}", event);
/// }).await?;
///
///
/// // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
/// unlisten();
/// # Ok(())

View file

@ -1,24 +1,37 @@
use crate::{event::Event, Error};
use serde::{de::DeserializeOwned, Serialize};
use crate::event::Event;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::fmt::Display;
use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Theme {
#[serde(rename = "light")]
Light,
#[serde(rename = "dark")]
Dark,
}
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
pub enum TitleBarStyle {
#[default]
#[serde(rename = "visible")]
Visible,
#[serde(rename = "transparent")]
Transparent,
#[serde(rename = "overlay")]
Overlay,
}
#[derive(Debug, Clone, PartialEq)]
/// Attention type to request on a window.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum UserAttentionType {
/// #### Platform-specific
/// - macOS: Bounces the dock icon until the application is in focus.
/// - Windows: Flashes both the window and the taskbar button until the application is in focus.
Critical = 1,
/// #### Platform-specific
/// - macOS: Bounces the dock icon once.
/// - Windows: Flashes the taskbar button until the application is in focus.
Informational,
}
@ -119,94 +132,299 @@ impl Display for CursorIcon {
}
}
#[derive(Debug, Default, Clone, Serialize)]
struct WebviewWindowOptions<'a> {
url: Option<&'a str>,
center: bool,
x: Option<i32>,
y: Option<i32>,
width: Option<u32>,
height: Option<u32>,
min_width: Option<u32>,
min_height: Option<u32>,
max_width: Option<u32>,
max_height: Option<u32>,
resizable: bool,
title: Option<&'a str>,
fullscreen: bool,
focus: bool,
transparent: bool,
maximized: bool,
visible: bool,
decorations: bool,
always_on_top: bool,
skip_taskbar: bool,
file_drop_enabled: bool,
theme: Option<Theme>,
title_bar_style: Option<TitleBarStyle>,
hidden_title: bool,
accept_first_mouse: bool,
tabbing_identifier: Option<&'a str>,
user_agent: Option<&'a str>,
}
#[derive(Debug, Default, Clone, Serialize)]
pub struct WebviewWindowBuilder<'a> {
label: &'a str,
inner: WebviewWindowOptions<'a>,
}
impl<'a> WebviewWindowBuilder<'a> {
pub fn new(label: &'a str) -> Self {
Self {
label,
..Default::default()
}
}
/// Remote URL or local file path to open.
///
/// - URL such as `https://github.com/tauri-apps` is opened directly on a Tauri window.
/// - data: URL such as `data:text/html,<html>...` is only supported with the `window-data-url` Cargo feature for the `tauri` dependency.
/// - local file path or route such as `/path/to/page.html` or `/users` is appended to the application URL (the devServer URL on development, or `tauri://localhost/` and `https://tauri.localhost/` on production).
pub fn set_url(&mut self, url: &'a str) {
self.inner.url = Some(url);
}
/// Show window in the center of the screen.
pub fn set_center(&mut self, center: bool) {
self.inner.center = center;
}
/// The initial position.
pub fn set_position(&mut self, position: PhysicalPosition) {
self.inner.x = Some(position.x());
self.inner.y = Some(position.y());
}
/// The initial size.
pub fn set_size(&mut self, size: PhysicalSize) {
self.inner.width = Some(size.width());
self.inner.height = Some(size.height());
}
/// Minimum window size.
pub fn set_min_size(&mut self, min_size: PhysicalSize) {
self.inner.min_width = Some(min_size.width());
self.inner.min_height = Some(min_size.height());
}
/// Maximum window size.
pub fn set_max_size(&mut self, max_size: PhysicalSize) {
self.inner.max_width = Some(max_size.width());
self.inner.max_height = Some(max_size.height());
}
/// Whether the window is resizable or not.
pub fn set_resizable(&mut self, resizable: bool) {
self.inner.resizable = resizable;
}
/// Window title.
pub fn set_title(&mut self, title: &'a str) {
self.inner.title = Some(title);
}
/// Whether the window is in fullscreen mode or not.
pub fn set_fullscreen(&mut self, fullscreen: bool) {
self.inner.fullscreen = fullscreen;
}
/// Whether the window will be initially focused or not.
pub fn set_focus(&mut self, focus: bool) {
self.inner.focus = focus;
}
/// Whether the window is transparent or not.
///
/// Note that on `macOS` this requires the `macos-private-api` feature flag, enabled under `tauri.conf.json > tauri > macOSPrivateApi`.
/// WARNING: Using private APIs on `macOS` prevents your application from being accepted to the `App Store`.
pub fn set_transparent(&mut self, transparent: bool) {
self.inner.transparent = transparent;
}
/// Whether the window should be maximized upon creation or not.
pub fn set_maximized(&mut self, maximized: bool) {
self.inner.maximized = maximized;
}
/// Whether the window should be immediately visible upon creation or not.
pub fn set_visible(&mut self, visible: bool) {
self.inner.visible = visible;
}
/// Whether the window should have borders and bars or not.
pub fn set_decorations(&mut self, decorations: bool) {
self.inner.decorations = decorations;
}
/// Whether the window should always be on top of other windows or not.
pub fn set_always_on_top(&mut self, always_on_top: bool) {
self.inner.always_on_top = always_on_top;
}
/// Whether or not the window icon should be added to the taskbar.
pub fn set_skip_taskbar(&mut self, skip_taskbar: bool) {
self.inner.skip_taskbar = skip_taskbar;
}
/// Whether the file drop is enabled or not on the webview. By default it is enabled.
///
/// Disabling it is required to use drag and drop on the frontend on Windows.
pub fn set_file_drop_enabled(&mut self, file_drop_enabled: bool) {
self.inner.file_drop_enabled = file_drop_enabled;
}
/// The initial window theme. Defaults to the system theme.
///
/// Only implemented on Windows and macOS 10.14+.
pub fn set_theme(&mut self, theme: Theme) {
self.inner.theme = Some(theme);
}
/// The style of the macOS title bar.
pub fn set_title_bar_style(&mut self, title_bar_style: TitleBarStyle) {
self.inner.title_bar_style = Some(title_bar_style);
}
/// If `true`, sets the window title to be hidden on macOS.
pub fn set_hidden_title(&mut self, hidden_title: bool) {
self.inner.hidden_title = hidden_title;
}
/// Whether clicking an inactive window also clicks through to the webview.
pub fn set_accept_first_mouse(&mut self, accept_first_mouse: bool) {
self.inner.accept_first_mouse = accept_first_mouse;
}
/// Defines the window [tabbing identifier](https://developer.apple.com/documentation/appkit/nswindow/1644704-tabbingidentifier) on macOS.
///
/// Windows with the same tabbing identifier will be grouped together.
/// If the tabbing identifier is not set, automatic tabbing will be disabled.
pub fn set_tabbing_identifier(&mut self, tabbing_identifier: &'a str) {
self.inner.tabbing_identifier = Some(tabbing_identifier);
}
/// The user agent for the webview.
pub fn set_user_agent(&mut self, user_agent: &'a str) {
self.inner.user_agent = Some(user_agent);
}
pub fn build(self) -> crate::Result<WebviewWindow> {
let opts = serde_wasm_bindgen::to_value(&self.inner)?;
Ok(WebviewWindow(inner::WebviewWindow::new(self.label, opts)))
}
}
/// Create new webview windows and get a handle to existing ones.
///
/// Windows are identified by a label a unique identifier that can be used to reference it later. It may only contain alphanumeric characters a-zA-Z plus the following special characters -, /, : and _.
#[derive(Debug, Clone, PartialEq)]
pub struct WebviewWindow(inner::WebviewWindow);
impl WebviewWindow {
pub fn new(label: &str, options: ()) -> Self {
Self(inner::WebviewWindow::new(label, options))
}
pub fn get_by_label(label: &str) -> Option<Self> {
inner::WebviewWindow::getByLabel(label).map(Self)
}
/// The label of this window.
pub fn label(&self) -> String {
self.0.label()
}
/// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
pub async fn scale_factor(&self) -> crate::Result<f64> {
let js_val = self.0.scaleFactor().await?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
}
/// Returns the position of the top-left hand corner of the windows client area relative to the top-left hand corner of the desktop.
pub async fn inner_position(&self) -> crate::Result<PhysicalPosition> {
Ok(PhysicalPosition(
self.0.innerPosition().await?.unchecked_into(),
))
}
/// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop.
pub async fn outer_position(&self) -> crate::Result<PhysicalPosition> {
Ok(PhysicalPosition(
self.0.outerPosition().await?.unchecked_into(),
))
}
/// Returns the physical size of the windows client area.
///
/// The client area is the content of the window, excluding the title bar and borders.
pub async fn inner_size(&self) -> crate::Result<PhysicalSize> {
Ok(PhysicalSize(self.0.innerSize().await?.unchecked_into()))
}
/// Returns the physical size of the entire window.
///
/// These dimensions include the title bar and borders. If you dont want that (and you usually dont), use inner_size instead.
pub async fn outer_size(&self) -> crate::Result<PhysicalSize> {
Ok(PhysicalSize(self.0.outerSize().await?.unchecked_into()))
}
/// Gets the windows current fullscreen state.
pub async fn is_fullscreen(&self) -> crate::Result<bool> {
let js_val = self.0.isFullscreen().await?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
}
/// Gets the windows current maximized state.
pub async fn is_maximized(&self) -> crate::Result<bool> {
let js_val = self.0.isMaximized().await?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
}
/// Gets the windows current decoration state.
pub async fn is_decorated(&self) -> crate::Result<bool> {
let js_val = self.0.isDecorated().await?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
}
/// Gets the windows current resizable state.
pub async fn is_resizable(&self) -> crate::Result<bool> {
let js_val = self.0.isResizable().await?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
}
/// Gets the windows current visibility state.
pub async fn is_visible(&self) -> crate::Result<bool> {
let js_val = self.0.isVisible().await?;
Ok(serde_wasm_bindgen::from_value(js_val)?)
}
/// Returns the current window theme.
///
/// #### Platform-specific
/// - macOS: Only supported on macOS 10.14+.
pub async fn theme(&self) -> crate::Result<Theme> {
let js_val = self.0.theme().await?;
let str = serde_wasm_bindgen::from_value::<String>(js_val)?;
match str.as_str() {
"light" => Ok(Theme::Light),
"dark" => Ok(Theme::Dark),
_ => Err(Error::UnknownTheme(str)),
}
Ok(serde_wasm_bindgen::from_value(js_val)?)
}
/// Centers the window.
pub async fn center(&self) -> crate::Result<()> {
Ok(self.0.center().await?)
}
/// Requests user attention to the window, this has no effect if the application is already focused. How requesting for user attention manifests is platform dependent, see UserAttentionType for details.
///
/// Providing None will unset the request for user attention. Unsetting the request for user attention might not be done automatically by the WM when the window receives input.
///
/// #### Platform-specific
/// - macOS: None has no effect.
/// - Linux: Urgency levels have the same effect.
pub async fn request_user_attention(
&self,
request_type: UserAttentionType,
@ -214,18 +432,27 @@ impl WebviewWindow {
Ok(self.0.requestUserAttention(request_type as u32).await?)
}
/// Opens the dialog to prints the contents of the webview. Currently only supported on macOS on wry. window.print() works on all platforms.
pub fn print(&self) -> crate::Result<()> {
todo!()
}
/// Determines if this window should be resizable.
pub async fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
Ok(self.0.setResizable(resizable).await?)
}
/// Set this windows title.
pub async fn set_title(&self, title: impl AsRef<str>) -> crate::Result<()> {
Ok(self.0.setTitle(title.as_ref()).await?)
}
/// Maximizes this window.
pub async fn maximize(&self) -> crate::Result<()> {
Ok(self.0.maximize().await?)
}
/// Un-maximizes this window.
pub async fn unmaximize(&self) -> crate::Result<()> {
Ok(self.0.unmaximize().await?)
}
@ -234,36 +461,44 @@ impl WebviewWindow {
Ok(self.0.toggleMaximize().await?)
}
/// Minimizes this window.
pub async fn minimize(&self) -> crate::Result<()> {
Ok(self.0.minimize().await?)
}
/// Un-minimizes this window.
pub async fn unminimize(&self) -> crate::Result<()> {
Ok(self.0.unminimize().await?)
}
/// Show this window.
pub async fn show(&self) -> crate::Result<()> {
Ok(self.0.show().await?)
}
/// Hide this window.
pub async fn hide(&self) -> crate::Result<()> {
Ok(self.0.hide().await?)
}
/// Closes this window.
pub async fn close(&self) -> crate::Result<()> {
Ok(self.0.close().await?)
}
/// Determines if this window should be [decorated](https://en.wikipedia.org/wiki/Window_(computing)#Window_decoration).
pub async fn set_decorations(&self, decorations: bool) -> crate::Result<()> {
Ok(self.0.setDecorations(decorations).await?)
}
/// Determines if this window should always be on top of other windows.
pub async fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> {
Ok(self.0.setAlwaysOnTop(always_on_top).await?)
}
pub async fn set_size(&self, size: Size) -> crate::Result<()> {
match size {
/// Resizes this window.
pub async fn set_size(&self, size: impl Into<Size>) -> crate::Result<()> {
match size.into() {
Size::Physical(size) => self.0.setSizePhysical(size.0).await?,
Size::Logical(size) => self.0.setSizeLogical(size.0).await?,
}
@ -271,8 +506,9 @@ impl WebviewWindow {
Ok(())
}
pub async fn set_min_size(&self, size: Option<Size>) -> crate::Result<()> {
match size {
/// Sets this windows minimum size.
pub async fn set_min_size(&self, size: Option<impl Into<Size>>) -> crate::Result<()> {
match size.map(Into::into) {
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?,
@ -281,8 +517,9 @@ impl WebviewWindow {
Ok(())
}
pub async fn set_max_size(&self, size: Option<Size>) -> crate::Result<()> {
match size {
/// Sets this windows maximum size.
pub async fn set_max_size(&self, size: Option<impl Into<Size>>) -> crate::Result<()> {
match size.map(Into::into) {
None => self.0.setMaxSizePhysical(None).await?,
Some(Size::Physical(size)) => self.0.setMaxSizePhysical(Some(size.0)).await?,
Some(Size::Logical(size)) => self.0.setMaxSizeLogical(Some(size.0)).await?,
@ -291,8 +528,9 @@ impl WebviewWindow {
Ok(())
}
pub async fn set_position(&self, position: Position) -> crate::Result<()> {
match position {
/// Sets this windows position.
pub async fn set_position(&self, position: impl Into<Position>) -> crate::Result<()> {
match position.into() {
Position::Physical(pos) => self.0.setPositionPhysical(pos.0).await?,
Position::Logical(pos) => self.0.setPositionLogical(pos.0).await?,
}
@ -300,34 +538,54 @@ impl WebviewWindow {
Ok(())
}
/// Determines if this window should be fullscreen.
pub async fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
Ok(self.0.setFullscreen(fullscreen).await?)
}
/// Bring the window to front and focus.
pub async fn set_focus(&self) -> crate::Result<()> {
Ok(self.0.setFocus().await?)
}
/// Sets this window icon.
pub async fn set_icon(&self, icon: &[u8]) -> crate::Result<()> {
Ok(self.0.setIcon(icon).await?)
}
/// Whether to show the window icon in the task bar or not.
pub async fn set_skip_taskbar(&self, skip: bool) -> crate::Result<()> {
Ok(self.0.setSkipTaskbar(skip).await?)
}
/// Grabs the cursor, preventing it from leaving the window.
///
/// Theres no guarantee that the cursor will be hidden. You should hide it by yourself if you want so.
///
/// #### Platform-specific
/// - Linux: Unsupported.
/// - macOS: This locks the cursor in a fixed location, which looks visually awkward.
pub async fn set_cursor_grab(&self, grab: bool) -> crate::Result<()> {
Ok(self.0.setCursorGrab(grab).await?)
}
/// Modifies the cursors visibility.
///
/// If false, this will hide the cursor. If true, this will show the cursor.
///
/// #### Platform-specific
/// - Windows: The cursor is only hidden within the confines of the window.
/// - macOS: The cursor is hidden as long as the window has input focus, even if the cursor is outside of the window.
pub async fn set_cursor_visible(&self, visible: bool) -> crate::Result<()> {
Ok(self.0.setCursorVisible(visible).await?)
}
/// Modifies the cursor icon of the window.
pub async fn set_cursor_icon(&self, icon: CursorIcon) -> crate::Result<()> {
Ok(self.0.setCursorIcon(&icon.to_string()).await?)
}
/// Changes the position of the cursor in window coordinates.
pub async fn set_cursor_position(&self, position: Position) -> crate::Result<()> {
match position {
Position::Physical(pos) => self.0.setCursorPositionPhysical(pos.0).await?,
@ -337,14 +595,17 @@ impl WebviewWindow {
Ok(())
}
/// Ignores the window cursor events.
pub async fn set_ignore_cursor_events(&self, ignore: bool) -> crate::Result<()> {
Ok(self.0.setIgnoreCursorEvents(ignore).await?)
}
/// Starts dragging the window.
pub async fn start_dragging(&self) -> crate::Result<()> {
Ok(self.0.startDragging().await?)
}
/// Emits an event to the backend, tied to the webview window.
#[inline(always)]
pub async fn emit<T: Serialize>(&self, event: &str, payload: &T) -> crate::Result<()> {
self.0
@ -354,6 +615,7 @@ impl WebviewWindow {
Ok(())
}
/// Listen to an event emitted by the backend that is tied to the webview window.
#[inline(always)]
pub async fn listen<T, H>(&self, event: &str, mut handler: H) -> crate::Result<impl FnOnce()>
where
@ -374,6 +636,7 @@ impl WebviewWindow {
})
}
/// Listen to an one-off event emitted by the backend that is tied to the webview window.
#[inline(always)]
pub async fn once<T, H>(&self, event: &str, mut handler: H) -> crate::Result<impl FnOnce()>
where
@ -395,54 +658,89 @@ impl WebviewWindow {
}
}
/// A position represented in logical pixels.
#[derive(Debug, Clone, PartialEq)]
pub struct LogicalPosition(inner::LogicalPosition);
impl LogicalPosition {
pub fn new(x: u32, y: u32) -> Self {
pub fn new(x: i32, y: i32) -> Self {
Self(inner::LogicalPosition::new(x, y))
}
pub fn x(&self) -> u32 {
pub fn from_physical(physical: impl Into<PhysicalPosition>, scale_factor: f64) -> Self {
physical.into().to_logical(scale_factor)
}
pub fn to_physical(self, scale_factor: f64) -> PhysicalPosition {
let x = self.x() as f64 * scale_factor;
let y = self.y() as f64 * scale_factor;
PhysicalPosition::new(x as i32, y as i32)
}
pub fn x(&self) -> i32 {
self.0.x()
}
pub fn set_x(&self, x: u32) {
pub fn set_x(&self, x: i32) {
self.0.set_x(x)
}
pub fn y(&self) -> u32 {
pub fn y(&self) -> i32 {
self.0.y()
}
pub fn set_y(&self, y: u32) {
pub fn set_y(&self, y: i32) {
self.0.set_y(y)
}
}
impl From<LogicalPosition> for Position {
fn from(pos: LogicalPosition) -> Self {
Position::Logical(pos)
}
}
/// A position represented in physical pixels.
#[derive(Debug, Clone, PartialEq)]
pub struct PhysicalPosition(inner::PhysicalPosition);
impl PhysicalPosition {
pub fn new(x: u32, y: u32) -> Self {
pub fn new(x: i32, y: i32) -> Self {
Self(inner::PhysicalPosition::new(x, y))
}
pub fn to_logical(self, scale_factor: u32) -> LogicalPosition {
LogicalPosition(self.0.toLogical(scale_factor))
#[inline]
pub fn from_logical(logical: impl Into<LogicalPosition>, scale_factor: f64) -> Self {
logical.into().to_physical(scale_factor)
}
pub fn x(&self) -> u32 {
#[inline]
pub fn to_logical(&self, scale_factor: f64) -> LogicalPosition {
let x = self.x() as f64 / scale_factor;
let y = self.y() as f64 / scale_factor;
LogicalPosition::new(x as i32, y as i32)
}
pub fn x(&self) -> i32 {
self.0.x()
}
pub fn set_x(&self, x: u32) {
pub fn set_x(&self, x: i32) {
self.0.set_x(x)
}
pub fn y(&self) -> u32 {
pub fn y(&self) -> i32 {
self.0.y()
}
pub fn set_y(&self, y: u32) {
pub fn set_y(&self, y: i32) {
self.0.set_y(y)
}
}
impl From<PhysicalPosition> for Position {
fn from(pos: PhysicalPosition) -> Self {
Position::Physical(pos)
}
}
/// A size represented in logical pixels.
#[derive(Debug, Clone, PartialEq)]
pub struct LogicalSize(inner::LogicalSize);
@ -465,6 +763,13 @@ impl LogicalSize {
}
}
impl From<LogicalSize> for Size {
fn from(size: LogicalSize) -> Self {
Size::Logical(size)
}
}
/// A size represented in physical pixels.
#[derive(Debug, Clone, PartialEq)]
pub struct PhysicalSize(inner::PhysicalSize);
@ -491,28 +796,39 @@ impl PhysicalSize {
}
}
impl From<PhysicalSize> for Size {
fn from(size: PhysicalSize) -> Self {
Size::Physical(size)
}
}
/// Allows you to retrieve information about a given monitor.
#[derive(Debug, Clone, PartialEq)]
pub struct Monitor(JsValue);
impl Monitor {
/// Human-readable name of the monitor
pub fn name(&self) -> Option<String> {
let raw = js_sys::Reflect::get(&self.0, &JsValue::from_str("name")).unwrap();
raw.as_string()
}
/// The monitor's resolution.
pub fn size(&self) -> PhysicalSize {
let raw = js_sys::Reflect::get(&self.0, &JsValue::from_str("size")).unwrap();
PhysicalSize(raw.unchecked_into())
}
/// The Top-left corner position of the monitor relative to the larger full screen area.
pub fn position(&self) -> PhysicalPosition {
let raw = js_sys::Reflect::get(&self.0, &JsValue::from_str("position")).unwrap();
PhysicalPosition(raw.unchecked_into())
}
/// The scale factor that can be used to map physical pixels to logical pixels.
pub fn scale_factor(&self) -> u32 {
let raw = js_sys::Reflect::get(&self.0, &JsValue::from_str("size"))
.unwrap()
@ -523,19 +839,89 @@ impl Monitor {
}
}
/// Get an instance of [`WebviewWindow`] for the current webview window.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::window::current_window;
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let win = current_window().await?;
/// # Ok(())
/// # }
/// ```
pub fn current_window() -> WebviewWindow {
WebviewWindow(inner::getCurrent())
}
/// Gets a list of instances of [`WebviewWindow`] for all available webview windows.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::window::all_windows;
/// use web_sys::console;
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let windows = all_windows().await?;
///
/// for win in windows {
/// console::log_1(&format!("{:?}", win).into());
/// }
/// # Ok(())
/// # }
/// ```
pub fn all_windows() -> Vec<WebviewWindow> {
inner::getAll().into_iter().map(WebviewWindow).collect()
}
pub async fn current_monitor() -> Monitor {
Monitor(inner::currentMonitor().await)
/// Returns the monitor on which the window currently resides.
///
/// Returns `None` if current monitor can't be detected.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::window::current_monitor;
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let monitor = current_monitor().await?;
/// # Ok(())
/// # }
/// ```
pub async fn current_monitor() -> crate::Result<Option<Monitor>> {
let raw = inner::currentMonitor().await?;
if raw.is_null() {
Ok(None)
} else {
Ok(Some(Monitor(raw)))
}
}
pub async fn primary_monitor() -> Monitor {
Monitor(inner::primaryMonitor().await)
/// Returns the primary monitor of the system.
///
/// Returns `None` if it can't identify any monitor as a primary one.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::window::primary_monitor;
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let monitor = primary_monitor().await?;
/// # Ok(())
/// # }
/// ```
pub async fn primary_monitor() -> crate::Result<Option<Monitor>> {
let raw = inner::primaryMonitor().await?;
if raw.is_null() {
Ok(None)
} else {
Ok(Some(Monitor(raw)))
}
}
#[derive(Debug, Clone)]
@ -561,11 +947,30 @@ impl Iterator for AvailableMonitors {
}
}
pub async fn available_monitors() -> AvailableMonitors {
AvailableMonitors {
/// Returns the list of all the monitors available on the system.
///
/// # Example
///
/// ```rust,no_run
/// use tauri_sys::window::available_monitors;
/// use web_sys::console;
///
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let monitors = available_monitors().await?;
///
/// for monitor in monitors {
/// console::log_1(&format!("{:?}", monitor).into());
/// }
/// # Ok(())
/// # }
/// ```
pub async fn available_monitors() -> crate::Result<AvailableMonitors> {
let raw = inner::availableMonitors().await?;
Ok(AvailableMonitors {
idx: 0,
array: inner::availableMonitors().await.unchecked_into(),
}
array: raw.unchecked_into(),
})
}
mod inner {
@ -579,15 +984,15 @@ mod inner {
#[derive(Debug, Clone, PartialEq)]
pub type LogicalPosition;
#[wasm_bindgen(constructor)]
pub fn new(x: u32, y: u32) -> LogicalPosition;
pub fn new(x: i32, y: i32) -> LogicalPosition;
#[wasm_bindgen(method, getter)]
pub fn x(this: &LogicalPosition) -> u32;
pub fn x(this: &LogicalPosition) -> i32;
#[wasm_bindgen(method, setter)]
pub fn set_x(this: &LogicalPosition, x: u32);
pub fn set_x(this: &LogicalPosition, x: i32);
#[wasm_bindgen(method, getter)]
pub fn y(this: &LogicalPosition) -> u32;
pub fn y(this: &LogicalPosition) -> i32;
#[wasm_bindgen(method, setter)]
pub fn set_y(this: &LogicalPosition, y: u32);
pub fn set_y(this: &LogicalPosition, y: i32);
}
#[wasm_bindgen(module = "/src/window.js")]
@ -595,17 +1000,17 @@ mod inner {
#[derive(Debug, Clone, PartialEq)]
pub type PhysicalPosition;
#[wasm_bindgen(constructor)]
pub fn new(x: u32, y: u32) -> PhysicalPosition;
pub fn new(x: i32, y: i32) -> PhysicalPosition;
#[wasm_bindgen(method)]
pub fn toLogical(this: &PhysicalPosition, scaleFactor: u32) -> LogicalPosition;
pub fn toLogical(this: &PhysicalPosition, scaleFactor: i32) -> LogicalPosition;
#[wasm_bindgen(method, getter)]
pub fn x(this: &PhysicalPosition) -> u32;
pub fn x(this: &PhysicalPosition) -> i32;
#[wasm_bindgen(method, setter)]
pub fn set_x(this: &PhysicalPosition, x: u32);
pub fn set_x(this: &PhysicalPosition, x: i32);
#[wasm_bindgen(method, getter)]
pub fn y(this: &PhysicalPosition) -> u32;
pub fn y(this: &PhysicalPosition) -> i32;
#[wasm_bindgen(method, setter)]
pub fn set_y(this: &PhysicalPosition, y: u32);
pub fn set_y(this: &PhysicalPosition, y: i32);
}
#[wasm_bindgen(module = "/src/window.js")]
@ -809,7 +1214,7 @@ mod inner {
#[derive(Debug, Clone, PartialEq)]
pub type WebviewWindow;
#[wasm_bindgen(constructor)]
pub fn new(label: &str, options: ()) -> WebviewWindow;
pub fn new(label: &str, options: JsValue) -> WebviewWindow;
#[wasm_bindgen(static_method_of = WebviewWindow)]
pub fn getByLabel(label: &str) -> Option<WebviewWindow>;
}
@ -818,8 +1223,11 @@ mod inner {
extern "C" {
pub fn getCurrent() -> WebviewWindow;
pub fn getAll() -> Vec<WebviewWindow>;
pub async fn currentMonitor() -> JsValue;
pub async fn primaryMonitor() -> JsValue;
pub async fn availableMonitors() -> JsValue;
#[wasm_bindgen(catch)]
pub async fn currentMonitor() -> Result<JsValue, JsValue>;
#[wasm_bindgen(catch)]
pub async fn primaryMonitor() -> Result<JsValue, JsValue>;
#[wasm_bindgen(catch)]
pub async fn availableMonitors() -> Result<JsValue, JsValue>;
}
}