#![cfg_attr(doc_cfg, feature(doc_cfg))]
use raw_window_handle::RawDisplayHandle;
use serde::Deserialize;
use std::{fmt::Debug, sync::mpsc::Sender};
use tauri_utils::Theme;
use url::Url;
use uuid::Uuid;
pub mod http;
pub mod menu;
pub mod monitor;
pub mod webview;
pub mod window;
use monitor::Monitor;
use webview::WindowBuilder;
use window::{
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
CursorIcon, DetachedWindow, PendingWindow, WindowEvent,
};
use crate::http::{
header::{InvalidHeaderName, InvalidHeaderValue},
method::InvalidMethod,
status::InvalidStatusCode,
InvalidUri,
};
#[cfg(all(desktop, feature = "system-tray"))]
use std::fmt;
pub type TrayId = u16;
pub type TrayEventHandler = dyn Fn(&SystemTrayEvent) + Send + 'static;
#[cfg(all(desktop, feature = "system-tray"))]
#[non_exhaustive]
pub struct SystemTray {
pub id: TrayId,
pub icon: Option<Icon>,
pub menu: Option<menu::SystemTrayMenu>,
#[cfg(target_os = "macos")]
pub icon_as_template: bool,
#[cfg(target_os = "macos")]
pub menu_on_left_click: bool,
#[cfg(target_os = "macos")]
pub title: Option<String>,
pub on_event: Option<Box<TrayEventHandler>>,
pub tooltip: Option<String>,
}
#[cfg(all(desktop, feature = "system-tray"))]
impl fmt::Debug for SystemTray {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("SystemTray");
d.field("id", &self.id)
.field("icon", &self.icon)
.field("menu", &self.menu);
#[cfg(target_os = "macos")]
{
d.field("icon_as_template", &self.icon_as_template)
.field("menu_on_left_click", &self.menu_on_left_click)
.field("title", &self.title);
}
d.finish()
}
}
#[cfg(all(desktop, feature = "system-tray"))]
impl Clone for SystemTray {
fn clone(&self) -> Self {
Self {
id: self.id,
icon: self.icon.clone(),
menu: self.menu.clone(),
on_event: None,
#[cfg(target_os = "macos")]
icon_as_template: self.icon_as_template,
#[cfg(target_os = "macos")]
menu_on_left_click: self.menu_on_left_click,
#[cfg(target_os = "macos")]
title: self.title.clone(),
tooltip: self.tooltip.clone(),
}
}
}
#[cfg(all(desktop, feature = "system-tray"))]
impl Default for SystemTray {
fn default() -> Self {
Self {
id: rand::random(),
icon: None,
menu: None,
#[cfg(target_os = "macos")]
icon_as_template: false,
#[cfg(target_os = "macos")]
menu_on_left_click: false,
#[cfg(target_os = "macos")]
title: None,
on_event: None,
tooltip: None,
}
}
}
#[cfg(all(desktop, feature = "system-tray"))]
impl SystemTray {
pub fn new() -> Self {
Default::default()
}
pub fn menu(&self) -> Option<&menu::SystemTrayMenu> {
self.menu.as_ref()
}
#[must_use]
pub fn with_id(mut self, id: TrayId) -> Self {
self.id = id;
self
}
#[must_use]
pub fn with_icon(mut self, icon: Icon) -> Self {
self.icon.replace(icon);
self
}
#[cfg(target_os = "macos")]
#[must_use]
pub fn with_icon_as_template(mut self, is_template: bool) -> Self {
self.icon_as_template = is_template;
self
}
#[cfg(target_os = "macos")]
#[must_use]
pub fn with_menu_on_left_click(mut self, menu_on_left_click: bool) -> Self {
self.menu_on_left_click = menu_on_left_click;
self
}
#[cfg(target_os = "macos")]
#[must_use]
pub fn with_title(mut self, title: &str) -> Self {
self.title = Some(title.to_owned());
self
}
#[must_use]
pub fn with_tooltip(mut self, tooltip: &str) -> Self {
self.tooltip = Some(tooltip.to_owned());
self
}
#[must_use]
pub fn with_menu(mut self, menu: menu::SystemTrayMenu) -> Self {
self.menu.replace(menu);
self
}
#[must_use]
pub fn on_event<F: Fn(&SystemTrayEvent) + Send + 'static>(mut self, f: F) -> Self {
self.on_event.replace(Box::new(f));
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[serde(tag = "type")]
pub enum UserAttentionType {
Critical,
Informational,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[serde(tag = "type")]
pub enum DeviceEventFilter {
Always,
Unfocused,
Never,
}
impl Default for DeviceEventFilter {
fn default() -> Self {
Self::Unfocused
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("failed to create webview: {0}")]
CreateWebview(Box<dyn std::error::Error + Send + Sync>),
#[error("failed to create window")]
CreateWindow,
#[error("Window labels must only include alphanumeric characters, `-`, `/`, `:` and `_`.")]
InvalidWindowLabel,
#[error("failed to send message to the webview")]
FailedToSendMessage,
#[error("failed to receive message from webview")]
FailedToReceiveMessage,
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[cfg(all(desktop, feature = "system-tray"))]
#[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
#[error("error encountered during tray setup: {0}")]
SystemTray(Box<dyn std::error::Error + Send + Sync>),
#[error("invalid icon: {0}")]
InvalidIcon(Box<dyn std::error::Error + Send + Sync>),
#[error("failed to get monitor")]
FailedToGetMonitor,
#[cfg(all(desktop, feature = "global-shortcut"))]
#[error(transparent)]
GlobalShortcut(Box<dyn std::error::Error + Send + Sync>),
#[error("Invalid header name: {0}")]
InvalidHeaderName(#[from] InvalidHeaderName),
#[error("Invalid header value: {0}")]
InvalidHeaderValue(#[from] InvalidHeaderValue),
#[error("Invalid uri: {0}")]
InvalidUri(#[from] InvalidUri),
#[error("Invalid status code: {0}")]
InvalidStatusCode(#[from] InvalidStatusCode),
#[error("Invalid method: {0}")]
InvalidMethod(#[from] InvalidMethod),
#[error("Infallible error, something went really wrong: {0}")]
Infallible(#[from] std::convert::Infallible),
#[error("the event loop has been closed")]
EventLoopClosed,
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub struct Icon {
pub rgba: Vec<u8>,
pub width: u32,
pub height: u32,
}
pub trait UserEvent: Debug + Clone + Send + 'static {}
impl<T: Debug + Clone + Send + 'static> UserEvent for T {}
#[non_exhaustive]
pub enum RunEvent<T: UserEvent> {
Exit,
ExitRequested {
tx: Sender<ExitRequestedEventAction>,
},
WindowEvent {
label: String,
event: WindowEvent,
},
Ready,
Resumed,
MainEventsCleared,
UserEvent(T),
}
#[derive(Debug)]
pub enum ExitRequestedEventAction {
Prevent,
}
#[derive(Debug)]
pub enum SystemTrayEvent {
MenuItemClick(u16),
LeftClick {
position: PhysicalPosition<f64>,
size: PhysicalSize<f64>,
},
RightClick {
position: PhysicalPosition<f64>,
size: PhysicalSize<f64>,
},
DoubleClick {
position: PhysicalPosition<f64>,
size: PhysicalSize<f64>,
},
}
#[derive(Debug, Clone, Default)]
pub struct RunIteration {
pub window_count: usize,
}
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
#[non_exhaustive]
pub enum ActivationPolicy {
Regular,
Accessory,
Prohibited,
}
pub trait RuntimeHandle<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'static {
type Runtime: Runtime<T, Handle = Self>;
fn create_proxy(&self) -> <Self::Runtime as Runtime<T>>::EventLoopProxy;
fn create_window(
&self,
pending: PendingWindow<T, Self::Runtime>,
) -> Result<DetachedWindow<T, Self::Runtime>>;
fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()>;
#[cfg(all(desktop, feature = "system-tray"))]
#[cfg_attr(doc_cfg, doc(cfg(all(desktop, feature = "system-tray"))))]
fn system_tray(
&self,
system_tray: SystemTray,
) -> Result<<Self::Runtime as Runtime<T>>::TrayHandler>;
fn raw_display_handle(&self) -> RawDisplayHandle;
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn show(&self) -> Result<()>;
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn hide(&self) -> Result<()>;
#[cfg(target_os = "android")]
fn find_class<'a>(
&'a self,
env: jni::JNIEnv<'a>,
activity: jni::objects::JObject<'a>,
name: impl Into<String>,
) -> std::result::Result<jni::objects::JClass<'a>, jni::errors::Error>;
#[cfg(target_os = "android")]
fn run_on_android_context<F>(&self, f: F)
where
F: FnOnce(jni::JNIEnv<'_>, jni::objects::JObject<'_>, jni::objects::JObject<'_>)
+ Send
+ 'static;
}
#[cfg(all(desktop, feature = "global-shortcut"))]
pub trait GlobalShortcutManager: Debug + Clone + Send + Sync {
fn is_registered(&self, accelerator: &str) -> Result<bool>;
fn register<F: Fn() + Send + 'static>(&mut self, accelerator: &str, handler: F) -> Result<()>;
fn unregister_all(&mut self) -> Result<()>;
fn unregister(&mut self, accelerator: &str) -> Result<()>;
}
#[cfg(feature = "clipboard")]
pub trait ClipboardManager: Debug + Clone + Send + Sync {
fn write_text<T: Into<String>>(&mut self, text: T) -> Result<()>;
fn read_text(&self) -> Result<Option<String>>;
}
pub trait EventLoopProxy<T: UserEvent>: Debug + Clone + Send + Sync {
fn send_event(&self, event: T) -> Result<()>;
}
pub trait Runtime<T: UserEvent>: Debug + Sized + 'static {
type Dispatcher: Dispatch<T, Runtime = Self>;
type Handle: RuntimeHandle<T, Runtime = Self>;
#[cfg(all(desktop, feature = "global-shortcut"))]
type GlobalShortcutManager: GlobalShortcutManager;
#[cfg(feature = "clipboard")]
type ClipboardManager: ClipboardManager;
#[cfg(all(desktop, feature = "system-tray"))]
type TrayHandler: menu::TrayHandle;
type EventLoopProxy: EventLoopProxy<T>;
fn new() -> Result<Self>;
#[cfg(any(windows, target_os = "linux"))]
#[cfg_attr(doc_cfg, doc(cfg(any(windows, target_os = "linux"))))]
fn new_any_thread() -> Result<Self>;
fn create_proxy(&self) -> Self::EventLoopProxy;
fn handle(&self) -> Self::Handle;
#[cfg(all(desktop, feature = "global-shortcut"))]
fn global_shortcut_manager(&self) -> Self::GlobalShortcutManager;
#[cfg(feature = "clipboard")]
fn clipboard_manager(&self) -> Self::ClipboardManager;
fn create_window(&self, pending: PendingWindow<T, Self>) -> Result<DetachedWindow<T, Self>>;
#[cfg(all(desktop, feature = "system-tray"))]
#[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
fn system_tray(&self, system_tray: SystemTray) -> Result<Self::TrayHandler>;
#[cfg(all(desktop, feature = "system-tray"))]
#[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
fn on_system_tray_event<F: Fn(TrayId, &SystemTrayEvent) + Send + 'static>(&mut self, f: F);
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy);
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn show(&self);
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn hide(&self);
fn set_device_event_filter(&mut self, filter: DeviceEventFilter);
#[cfg(desktop)]
fn run_iteration<F: Fn(RunEvent<T>) + 'static>(&mut self, callback: F) -> RunIteration;
fn run<F: FnMut(RunEvent<T>) + 'static>(self, callback: F);
}
pub trait Dispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'static {
type Runtime: Runtime<T>;
type WindowBuilder: WindowBuilder;
fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()>;
fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) -> Uuid;
fn on_menu_event<F: Fn(&window::MenuEvent) + Send + 'static>(&self, f: F) -> Uuid;
fn with_webview<F: FnOnce(Box<dyn std::any::Any>) + Send + 'static>(&self, f: F) -> Result<()>;
#[cfg(any(debug_assertions, feature = "devtools"))]
fn open_devtools(&self);
#[cfg(any(debug_assertions, feature = "devtools"))]
fn close_devtools(&self);
#[cfg(any(debug_assertions, feature = "devtools"))]
fn is_devtools_open(&self) -> Result<bool>;
fn url(&self) -> Result<Url>;
fn scale_factor(&self) -> Result<f64>;
fn inner_position(&self) -> Result<PhysicalPosition<i32>>;
fn outer_position(&self) -> Result<PhysicalPosition<i32>>;
fn inner_size(&self) -> Result<PhysicalSize<u32>>;
fn outer_size(&self) -> Result<PhysicalSize<u32>>;
fn is_fullscreen(&self) -> Result<bool>;
fn is_minimized(&self) -> Result<bool>;
fn is_maximized(&self) -> Result<bool>;
fn is_decorated(&self) -> Result<bool>;
fn is_resizable(&self) -> Result<bool>;
fn is_visible(&self) -> Result<bool>;
fn title(&self) -> Result<String>;
fn is_menu_visible(&self) -> Result<bool>;
fn current_monitor(&self) -> Result<Option<Monitor>>;
fn primary_monitor(&self) -> Result<Option<Monitor>>;
fn available_monitors(&self) -> Result<Vec<Monitor>>;
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
fn gtk_window(&self) -> Result<gtk::ApplicationWindow>;
fn raw_window_handle(&self) -> Result<raw_window_handle::RawWindowHandle>;
fn theme(&self) -> Result<Theme>;
fn center(&self) -> Result<()>;
fn print(&self) -> Result<()>;
fn request_user_attention(&self, request_type: Option<UserAttentionType>) -> Result<()>;
fn create_window(
&mut self,
pending: PendingWindow<T, Self::Runtime>,
) -> Result<DetachedWindow<T, Self::Runtime>>;
fn set_resizable(&self, resizable: bool) -> Result<()>;
fn set_title<S: Into<String>>(&self, title: S) -> Result<()>;
fn maximize(&self) -> Result<()>;
fn unmaximize(&self) -> Result<()>;
fn minimize(&self) -> Result<()>;
fn unminimize(&self) -> Result<()>;
fn show_menu(&self) -> Result<()>;
fn hide_menu(&self) -> Result<()>;
fn show(&self) -> Result<()>;
fn hide(&self) -> Result<()>;
fn close(&self) -> Result<()>;
fn set_decorations(&self, decorations: bool) -> Result<()>;
fn set_shadow(&self, enable: bool) -> Result<()>;
fn set_always_on_top(&self, always_on_top: bool) -> Result<()>;
fn set_content_protected(&self, protected: bool) -> Result<()>;
fn set_size(&self, size: Size) -> Result<()>;
fn set_min_size(&self, size: Option<Size>) -> Result<()>;
fn set_max_size(&self, size: Option<Size>) -> Result<()>;
fn set_position(&self, position: Position) -> Result<()>;
fn set_fullscreen(&self, fullscreen: bool) -> Result<()>;
fn set_focus(&self) -> Result<()>;
fn set_icon(&self, icon: Icon) -> Result<()>;
fn set_skip_taskbar(&self, skip: bool) -> Result<()>;
fn set_cursor_grab(&self, grab: bool) -> Result<()>;
fn set_cursor_visible(&self, visible: bool) -> Result<()>;
fn set_cursor_icon(&self, icon: CursorIcon) -> Result<()>;
fn set_cursor_position<Pos: Into<Position>>(&self, position: Pos) -> Result<()>;
fn set_ignore_cursor_events(&self, ignore: bool) -> Result<()>;
fn start_dragging(&self) -> Result<()>;
fn eval_script<S: Into<String>>(&self, script: S) -> Result<()>;
fn update_menu_item(&self, id: u16, update: menu::MenuUpdate) -> Result<()>;
}