pub(crate) mod menu;
pub use menu::{MenuEvent, MenuHandle};
#[cfg(target_os = "macos")]
use crate::TitleBarStyle;
use crate::{
app::AppHandle,
command::{CommandArg, CommandItem},
event::{Event, EventHandler},
hooks::{InvokePayload, InvokeResponder},
manager::WindowManager,
runtime::{
http::{Request as HttpRequest, Response as HttpResponse},
monitor::Monitor as RuntimeMonitor,
webview::{WebviewAttributes, WindowBuilder as _},
window::{
dpi::{PhysicalPosition, PhysicalSize},
DetachedWindow, JsEventListenerKey, PendingWindow,
},
Dispatch, RuntimeHandle,
},
sealed::ManagerBase,
sealed::RuntimeOrDispatch,
utils::config::WindowUrl,
EventLoopMessage, Invoke, InvokeError, InvokeMessage, InvokeResolver, Manager, PageLoadPayload,
Runtime, Theme, WindowEvent,
};
#[cfg(desktop)]
use crate::{
runtime::{
menu::Menu,
window::dpi::{Position, Size},
UserAttentionType,
},
CursorIcon, Icon,
};
use serde::Serialize;
#[cfg(windows)]
use windows::Win32::Foundation::HWND;
use tauri_macros::default_runtime;
use std::{
fmt,
hash::{Hash, Hasher},
path::PathBuf,
sync::Arc,
};
pub(crate) type WebResourceRequestHandler = dyn Fn(&HttpRequest, &mut HttpResponse) + Send + Sync;
#[derive(Clone, Serialize)]
struct WindowCreatedEvent {
label: String,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Monitor {
pub(crate) name: Option<String>,
pub(crate) size: PhysicalSize<u32>,
pub(crate) position: PhysicalPosition<i32>,
pub(crate) scale_factor: f64,
}
impl From<RuntimeMonitor> for Monitor {
fn from(monitor: RuntimeMonitor) -> Self {
Self {
name: monitor.name,
size: monitor.size,
position: monitor.position,
scale_factor: monitor.scale_factor,
}
}
}
impl Monitor {
pub fn name(&self) -> Option<&String> {
self.name.as_ref()
}
pub fn size(&self) -> &PhysicalSize<u32> {
&self.size
}
pub fn position(&self) -> &PhysicalPosition<i32> {
&self.position
}
pub fn scale_factor(&self) -> f64 {
self.scale_factor
}
}
#[default_runtime(crate::Wry, wry)]
pub struct WindowBuilder<'a, R: Runtime> {
manager: WindowManager<R>,
runtime: RuntimeOrDispatch<'a, R>,
app_handle: AppHandle<R>,
label: String,
pub(crate) window_builder: <R::Dispatcher as Dispatch<EventLoopMessage>>::WindowBuilder,
pub(crate) webview_attributes: WebviewAttributes,
web_resource_request_handler: Option<Box<WebResourceRequestHandler>>,
}
impl<'a, R: Runtime> fmt::Debug for WindowBuilder<'a, R> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WindowBuilder")
.field("manager", &self.manager)
.field("app_handle", &self.app_handle)
.field("label", &self.label)
.field("window_builder", &self.window_builder)
.field("webview_attributes", &self.webview_attributes)
.finish()
}
}
impl<'a, R: Runtime> WindowBuilder<'a, R> {
pub fn new<M: Manager<R>, L: Into<String>>(manager: &'a M, label: L, url: WindowUrl) -> Self {
let runtime = manager.runtime();
let app_handle = manager.app_handle();
Self {
manager: manager.manager().clone(),
runtime,
app_handle,
label: label.into(),
window_builder: <R::Dispatcher as Dispatch<EventLoopMessage>>::WindowBuilder::new(),
webview_attributes: WebviewAttributes::new(url),
web_resource_request_handler: None,
}
}
pub fn on_web_resource_request<F: Fn(&HttpRequest, &mut HttpResponse) + Send + Sync + 'static>(
mut self,
f: F,
) -> Self {
self.web_resource_request_handler.replace(Box::new(f));
self
}
pub fn build(mut self) -> crate::Result<Window<R>> {
let web_resource_request_handler = self.web_resource_request_handler.take();
let pending = PendingWindow::new(
self.window_builder.clone(),
self.webview_attributes.clone(),
self.label.clone(),
)?;
let labels = self.manager.labels().into_iter().collect::<Vec<_>>();
let pending = self.manager.prepare_window(
self.app_handle.clone(),
pending,
&labels,
web_resource_request_handler,
)?;
let window = match &mut self.runtime {
RuntimeOrDispatch::Runtime(runtime) => runtime.create_window(pending),
RuntimeOrDispatch::RuntimeHandle(handle) => handle.create_window(pending),
RuntimeOrDispatch::Dispatch(dispatcher) => dispatcher.create_window(pending),
}
.map(|window| self.manager.attach_window(self.app_handle.clone(), window))?;
self.manager.emit_filter(
"tauri://window-created",
None,
Some(WindowCreatedEvent {
label: window.label().into(),
}),
|w| w != &window,
)?;
Ok(window)
}
}
#[cfg(desktop)]
impl<'a, R: Runtime> WindowBuilder<'a, R> {
#[must_use]
pub fn menu(mut self, menu: Menu) -> Self {
self.window_builder = self.window_builder.menu(menu);
self
}
#[must_use]
pub fn center(mut self) -> Self {
self.window_builder = self.window_builder.center();
self
}
#[must_use]
pub fn position(mut self, x: f64, y: f64) -> Self {
self.window_builder = self.window_builder.position(x, y);
self
}
#[must_use]
pub fn inner_size(mut self, width: f64, height: f64) -> Self {
self.window_builder = self.window_builder.inner_size(width, height);
self
}
#[must_use]
pub fn min_inner_size(mut self, min_width: f64, min_height: f64) -> Self {
self.window_builder = self.window_builder.min_inner_size(min_width, min_height);
self
}
#[must_use]
pub fn max_inner_size(mut self, max_width: f64, max_height: f64) -> Self {
self.window_builder = self.window_builder.max_inner_size(max_width, max_height);
self
}
#[must_use]
pub fn resizable(mut self, resizable: bool) -> Self {
self.window_builder = self.window_builder.resizable(resizable);
self
}
#[must_use]
pub fn title<S: Into<String>>(mut self, title: S) -> Self {
self.window_builder = self.window_builder.title(title);
self
}
#[must_use]
pub fn fullscreen(mut self, fullscreen: bool) -> Self {
self.window_builder = self.window_builder.fullscreen(fullscreen);
self
}
#[must_use]
#[deprecated(
since = "1.2.0",
note = "The window is automatically focused by default. This function Will be removed in 2.0.0. Use `focused` instead."
)]
pub fn focus(mut self) -> Self {
self.window_builder = self.window_builder.focused(true);
self
}
#[must_use]
pub fn focused(mut self, focused: bool) -> Self {
self.window_builder = self.window_builder.focused(focused);
self
}
#[must_use]
pub fn maximized(mut self, maximized: bool) -> Self {
self.window_builder = self.window_builder.maximized(maximized);
self
}
#[must_use]
pub fn visible(mut self, visible: bool) -> Self {
self.window_builder = self.window_builder.visible(visible);
self
}
#[must_use]
pub fn theme(mut self, theme: Option<Theme>) -> Self {
self.window_builder = self.window_builder.theme(theme);
self
}
#[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
#[cfg_attr(
doc_cfg,
doc(cfg(any(not(target_os = "macos"), feature = "macos-private-api")))
)]
#[must_use]
pub fn transparent(mut self, transparent: bool) -> Self {
self.window_builder = self.window_builder.transparent(transparent);
self
}
#[must_use]
pub fn decorations(mut self, decorations: bool) -> Self {
self.window_builder = self.window_builder.decorations(decorations);
self
}
#[must_use]
pub fn always_on_top(mut self, always_on_top: bool) -> Self {
self.window_builder = self.window_builder.always_on_top(always_on_top);
self
}
pub fn icon(mut self, icon: Icon) -> crate::Result<Self> {
self.window_builder = self.window_builder.icon(icon.try_into()?)?;
Ok(self)
}
#[must_use]
pub fn skip_taskbar(mut self, skip: bool) -> Self {
self.window_builder = self.window_builder.skip_taskbar(skip);
self
}
#[cfg(windows)]
#[must_use]
pub fn parent_window(mut self, parent: HWND) -> Self {
self.window_builder = self.window_builder.parent_window(parent);
self
}
#[cfg(target_os = "macos")]
#[must_use]
pub fn parent_window(mut self, parent: *mut std::ffi::c_void) -> Self {
self.window_builder = self.window_builder.parent_window(parent);
self
}
#[cfg(windows)]
#[must_use]
pub fn owner_window(mut self, owner: HWND) -> Self {
self.window_builder = self.window_builder.owner_window(owner);
self
}
#[cfg(target_os = "macos")]
#[must_use]
pub fn title_bar_style(mut self, style: TitleBarStyle) -> Self {
self.window_builder = self.window_builder.title_bar_style(style);
self
}
#[cfg(target_os = "macos")]
#[must_use]
pub fn hidden_title(mut self, hidden: bool) -> Self {
self.window_builder = self.window_builder.hidden_title(hidden);
self
}
#[cfg(target_os = "macos")]
#[must_use]
pub fn tabbing_identifier(mut self, identifier: &str) -> Self {
self.window_builder = self.window_builder.tabbing_identifier(identifier);
self
}
#[must_use]
pub fn accept_first_mouse(mut self, accept: bool) -> Self {
self.webview_attributes.accept_first_mouse = accept;
self
}
}
impl<'a, R: Runtime> WindowBuilder<'a, R> {
#[must_use]
pub fn initialization_script(mut self, script: &str) -> Self {
self
.webview_attributes
.initialization_scripts
.push(script.to_string());
self
}
#[must_use]
pub fn user_agent(mut self, user_agent: &str) -> Self {
self.webview_attributes.user_agent = Some(user_agent.to_string());
self
}
#[must_use]
pub fn data_directory(mut self, data_directory: PathBuf) -> Self {
self
.webview_attributes
.data_directory
.replace(data_directory);
self
}
#[must_use]
pub fn disable_file_drop_handler(mut self) -> Self {
self.webview_attributes.file_drop_handler_enabled = false;
self
}
#[must_use]
pub fn enable_clipboard_access(mut self) -> Self {
self.webview_attributes.clipboard = true;
self
}
}
#[default_runtime(crate::Wry, wry)]
#[derive(Debug)]
pub struct Window<R: Runtime> {
window: DetachedWindow<EventLoopMessage, R>,
manager: WindowManager<R>,
pub(crate) app_handle: AppHandle<R>,
}
unsafe impl<R: Runtime> raw_window_handle::HasRawWindowHandle for Window<R> {
fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
self.window.dispatcher.raw_window_handle().unwrap()
}
}
impl<R: Runtime> Clone for Window<R> {
fn clone(&self) -> Self {
Self {
window: self.window.clone(),
manager: self.manager.clone(),
app_handle: self.app_handle.clone(),
}
}
}
impl<R: Runtime> Hash for Window<R> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.window.label.hash(state)
}
}
impl<R: Runtime> Eq for Window<R> {}
impl<R: Runtime> PartialEq for Window<R> {
fn eq(&self, other: &Self) -> bool {
self.window.label.eq(&other.window.label)
}
}
impl<R: Runtime> Manager<R> for Window<R> {
fn emit_to<S: Serialize + Clone>(
&self,
label: &str,
event: &str,
payload: S,
) -> crate::Result<()> {
self
.manager()
.emit_filter(event, Some(self.label()), payload, |w| label == w.label())
}
fn emit_all<S: Serialize + Clone>(&self, event: &str, payload: S) -> crate::Result<()> {
self
.manager()
.emit_filter(event, Some(self.label()), payload, |_| true)
}
}
impl<R: Runtime> ManagerBase<R> for Window<R> {
fn manager(&self) -> &WindowManager<R> {
&self.manager
}
fn runtime(&self) -> RuntimeOrDispatch<'_, R> {
RuntimeOrDispatch::Dispatch(self.dispatcher())
}
fn managed_app_handle(&self) -> AppHandle<R> {
self.app_handle.clone()
}
}
impl<'de, R: Runtime> CommandArg<'de, R> for Window<R> {
fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
Ok(command.message.window())
}
}
#[cfg(all(any(desktop, target_os = "android"), feature = "wry"))]
#[cfg_attr(
doc_cfg,
doc(cfg(all(any(desktop, target_os = "android"), feature = "wry")))
)]
pub struct PlatformWebview(tauri_runtime_wry::Webview);
#[cfg(all(any(desktop, target_os = "android"), feature = "wry"))]
impl PlatformWebview {
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
#[cfg_attr(
doc_cfg,
doc(cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
)))
)]
pub fn inner(&self) -> std::rc::Rc<webkit2gtk::WebView> {
self.0.clone()
}
#[cfg(windows)]
#[cfg_attr(doc_cfg, doc(cfg(windows)))]
pub fn controller(
&self,
) -> webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Controller {
self.0.controller.clone()
}
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
pub fn inner(&self) -> cocoa::base::id {
self.0.webview
}
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
pub fn controller(&self) -> cocoa::base::id {
self.0.manager
}
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
pub fn ns_window(&self) -> cocoa::base::id {
self.0.ns_window
}
#[cfg(target_os = "android")]
pub fn jni_handle(&self) -> tauri_runtime_wry::wry::webview::JniHandle {
self.0
}
}
#[cfg(feature = "wry")]
impl Window<crate::Wry> {
#[cfg(any(desktop, target_os = "android"))]
#[cfg_attr(
doc_cfg,
doc(cfg(all(feature = "wry", any(desktop, target_os = "android"))))
)]
pub fn with_webview<F: FnOnce(PlatformWebview) + Send + 'static>(
&self,
f: F,
) -> crate::Result<()> {
self
.window
.dispatcher
.with_webview(|w| f(PlatformWebview(w)))
.map_err(Into::into)
}
}
impl<R: Runtime> Window<R> {
pub(crate) fn new(
manager: WindowManager<R>,
window: DetachedWindow<EventLoopMessage, R>,
app_handle: AppHandle<R>,
) -> Self {
Self {
window,
manager,
app_handle,
}
}
pub fn builder<'a, M: Manager<R>, L: Into<String>>(
manager: &'a M,
label: L,
url: WindowUrl,
) -> WindowBuilder<'a, R> {
WindowBuilder::<'a, R>::new(manager, label.into(), url)
}
pub(crate) fn invoke_responder(&self) -> Arc<InvokeResponder<R>> {
self.manager.invoke_responder()
}
pub(crate) fn dispatcher(&self) -> R::Dispatcher {
self.window.dispatcher.clone()
}
pub fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> crate::Result<()> {
self
.window
.dispatcher
.run_on_main_thread(f)
.map_err(Into::into)
}
pub fn label(&self) -> &str {
&self.window.label
}
pub fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) {
self
.window
.dispatcher
.on_window_event(move |event| f(&event.clone().into()));
}
pub fn on_menu_event<F: Fn(MenuEvent) + Send + 'static>(&self, f: F) -> uuid::Uuid {
let menu_ids = self.window.menu_ids.clone();
self.window.dispatcher.on_menu_event(move |event| {
let id = menu_ids
.lock()
.unwrap()
.get(&event.menu_item_id)
.unwrap()
.clone();
f(MenuEvent { menu_item_id: id })
})
}
}
impl<R: Runtime> Window<R> {
pub fn menu_handle(&self) -> MenuHandle<R> {
MenuHandle {
ids: self.window.menu_ids.clone(),
dispatcher: self.dispatcher(),
}
}
pub fn scale_factor(&self) -> crate::Result<f64> {
self.window.dispatcher.scale_factor().map_err(Into::into)
}
pub fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>> {
self.window.dispatcher.inner_position().map_err(Into::into)
}
pub fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>> {
self.window.dispatcher.outer_position().map_err(Into::into)
}
pub fn inner_size(&self) -> crate::Result<PhysicalSize<u32>> {
self.window.dispatcher.inner_size().map_err(Into::into)
}
pub fn outer_size(&self) -> crate::Result<PhysicalSize<u32>> {
self.window.dispatcher.outer_size().map_err(Into::into)
}
pub fn is_fullscreen(&self) -> crate::Result<bool> {
self.window.dispatcher.is_fullscreen().map_err(Into::into)
}
pub fn is_maximized(&self) -> crate::Result<bool> {
self.window.dispatcher.is_maximized().map_err(Into::into)
}
pub fn is_decorated(&self) -> crate::Result<bool> {
self.window.dispatcher.is_decorated().map_err(Into::into)
}
pub fn is_resizable(&self) -> crate::Result<bool> {
self.window.dispatcher.is_resizable().map_err(Into::into)
}
pub fn is_visible(&self) -> crate::Result<bool> {
self.window.dispatcher.is_visible().map_err(Into::into)
}
pub fn current_monitor(&self) -> crate::Result<Option<Monitor>> {
self
.window
.dispatcher
.current_monitor()
.map(|m| m.map(Into::into))
.map_err(Into::into)
}
pub fn primary_monitor(&self) -> crate::Result<Option<Monitor>> {
self
.window
.dispatcher
.primary_monitor()
.map(|m| m.map(Into::into))
.map_err(Into::into)
}
pub fn available_monitors(&self) -> crate::Result<Vec<Monitor>> {
self
.window
.dispatcher
.available_monitors()
.map(|m| m.into_iter().map(Into::into).collect())
.map_err(Into::into)
}
#[cfg(target_os = "macos")]
pub fn ns_window(&self) -> crate::Result<*mut std::ffi::c_void> {
self
.window
.dispatcher
.raw_window_handle()
.map_err(Into::into)
.and_then(|handle| {
if let raw_window_handle::RawWindowHandle::AppKit(h) = handle {
Ok(h.ns_window)
} else {
Err(crate::Error::InvalidWindowHandle)
}
})
}
#[cfg(windows)]
pub fn hwnd(&self) -> crate::Result<HWND> {
self
.window
.dispatcher
.raw_window_handle()
.map_err(Into::into)
.and_then(|handle| {
if let raw_window_handle::RawWindowHandle::Win32(h) = handle {
Ok(HWND(h.hwnd as _))
} else {
Err(crate::Error::InvalidWindowHandle)
}
})
}
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
pub fn gtk_window(&self) -> crate::Result<gtk::ApplicationWindow> {
self.window.dispatcher.gtk_window().map_err(Into::into)
}
pub fn theme(&self) -> crate::Result<Theme> {
self.window.dispatcher.theme().map_err(Into::into)
}
}
#[cfg(desktop)]
impl<R: Runtime> Window<R> {
pub fn center(&self) -> crate::Result<()> {
self.window.dispatcher.center().map_err(Into::into)
}
pub fn request_user_attention(
&self,
request_type: Option<UserAttentionType>,
) -> crate::Result<()> {
self
.window
.dispatcher
.request_user_attention(request_type)
.map_err(Into::into)
}
pub fn print(&self) -> crate::Result<()> {
self.window.dispatcher.print().map_err(Into::into)
}
pub fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
self
.window
.dispatcher
.set_resizable(resizable)
.map_err(Into::into)
}
pub fn set_title(&self, title: &str) -> crate::Result<()> {
self
.window
.dispatcher
.set_title(title.to_string())
.map_err(Into::into)
}
pub fn maximize(&self) -> crate::Result<()> {
self.window.dispatcher.maximize().map_err(Into::into)
}
pub fn unmaximize(&self) -> crate::Result<()> {
self.window.dispatcher.unmaximize().map_err(Into::into)
}
pub fn minimize(&self) -> crate::Result<()> {
self.window.dispatcher.minimize().map_err(Into::into)
}
pub fn unminimize(&self) -> crate::Result<()> {
self.window.dispatcher.unminimize().map_err(Into::into)
}
pub fn show(&self) -> crate::Result<()> {
self.window.dispatcher.show().map_err(Into::into)
}
pub fn hide(&self) -> crate::Result<()> {
self.window.dispatcher.hide().map_err(Into::into)
}
pub fn close(&self) -> crate::Result<()> {
self.window.dispatcher.close().map_err(Into::into)
}
pub fn set_decorations(&self, decorations: bool) -> crate::Result<()> {
self
.window
.dispatcher
.set_decorations(decorations)
.map_err(Into::into)
}
pub fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> {
self
.window
.dispatcher
.set_always_on_top(always_on_top)
.map_err(Into::into)
}
pub fn set_size<S: Into<Size>>(&self, size: S) -> crate::Result<()> {
self
.window
.dispatcher
.set_size(size.into())
.map_err(Into::into)
}
pub fn set_min_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
self
.window
.dispatcher
.set_min_size(size.map(|s| s.into()))
.map_err(Into::into)
}
pub fn set_max_size<S: Into<Size>>(&self, size: Option<S>) -> crate::Result<()> {
self
.window
.dispatcher
.set_max_size(size.map(|s| s.into()))
.map_err(Into::into)
}
pub fn set_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
self
.window
.dispatcher
.set_position(position.into())
.map_err(Into::into)
}
pub fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
self
.window
.dispatcher
.set_fullscreen(fullscreen)
.map_err(Into::into)
}
pub fn set_focus(&self) -> crate::Result<()> {
self.window.dispatcher.set_focus().map_err(Into::into)
}
pub fn set_icon(&self, icon: Icon) -> crate::Result<()> {
self
.window
.dispatcher
.set_icon(icon.try_into()?)
.map_err(Into::into)
}
pub fn set_skip_taskbar(&self, skip: bool) -> crate::Result<()> {
self
.window
.dispatcher
.set_skip_taskbar(skip)
.map_err(Into::into)
}
pub fn set_cursor_grab(&self, grab: bool) -> crate::Result<()> {
self
.window
.dispatcher
.set_cursor_grab(grab)
.map_err(Into::into)
}
pub fn set_cursor_visible(&self, visible: bool) -> crate::Result<()> {
self
.window
.dispatcher
.set_cursor_visible(visible)
.map_err(Into::into)
}
pub fn set_cursor_icon(&self, icon: CursorIcon) -> crate::Result<()> {
self
.window
.dispatcher
.set_cursor_icon(icon)
.map_err(Into::into)
}
pub fn set_cursor_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
self
.window
.dispatcher
.set_cursor_position(position)
.map_err(Into::into)
}
pub fn set_ignore_cursor_events(&self, ignore: bool) -> crate::Result<()> {
self
.window
.dispatcher
.set_ignore_cursor_events(ignore)
.map_err(Into::into)
}
pub fn start_dragging(&self) -> crate::Result<()> {
self.window.dispatcher.start_dragging().map_err(Into::into)
}
}
impl<R: Runtime> Window<R> {
pub fn on_message(self, payload: InvokePayload) -> crate::Result<()> {
let manager = self.manager.clone();
match payload.cmd.as_str() {
"__initialized" => {
let payload: PageLoadPayload = serde_json::from_value(payload.inner)?;
manager.run_on_page_load(self, payload);
}
_ => {
let message = InvokeMessage::new(
self.clone(),
manager.state(),
payload.cmd.to_string(),
payload.inner,
);
let resolver = InvokeResolver::new(self, payload.callback, payload.error);
let invoke = Invoke { message, resolver };
if let Some(module) = &payload.tauri_module {
crate::endpoints::handle(
module.to_string(),
invoke,
manager.config(),
manager.package_info(),
);
} else if payload.cmd.starts_with("plugin:") {
manager.extend_api(invoke);
} else {
manager.run_invoke_handler(invoke);
}
}
}
Ok(())
}
pub fn eval(&self, js: &str) -> crate::Result<()> {
self.window.dispatcher.eval_script(js).map_err(Into::into)
}
pub(crate) fn register_js_listener(&self, window_label: Option<String>, event: String, id: u64) {
self
.window
.js_event_listeners
.lock()
.unwrap()
.entry(JsEventListenerKey {
window_label,
event,
})
.or_insert_with(Default::default)
.insert(id);
}
pub(crate) fn unregister_js_listener(&self, id: u64) {
let mut empty = None;
let mut js_listeners = self.window.js_event_listeners.lock().unwrap();
let iter = js_listeners.iter_mut();
for (key, ids) in iter {
if ids.contains(&id) {
ids.remove(&id);
if ids.is_empty() {
empty.replace(key.clone());
}
break;
}
}
if let Some(key) = empty {
js_listeners.remove(&key);
}
}
pub(crate) fn has_js_listener(&self, window_label: Option<String>, event: &str) -> bool {
self
.window
.js_event_listeners
.lock()
.unwrap()
.contains_key(&JsEventListenerKey {
window_label,
event: event.into(),
})
}
#[cfg(any(debug_assertions, feature = "devtools"))]
#[cfg_attr(doc_cfg, doc(cfg(any(debug_assertions, feature = "devtools"))))]
pub fn open_devtools(&self) {
self.window.dispatcher.open_devtools();
}
#[cfg(any(debug_assertions, feature = "devtools"))]
#[cfg_attr(doc_cfg, doc(cfg(any(debug_assertions, feature = "devtools"))))]
pub fn close_devtools(&self) {
self.window.dispatcher.close_devtools();
}
#[cfg(any(debug_assertions, feature = "devtools"))]
#[cfg_attr(doc_cfg, doc(cfg(any(debug_assertions, feature = "devtools"))))]
pub fn is_devtools_open(&self) -> bool {
self
.window
.dispatcher
.is_devtools_open()
.unwrap_or_default()
}
}
impl<R: Runtime> Window<R> {
pub fn emit_and_trigger<S: Serialize + Clone>(
&self,
event: &str,
payload: S,
) -> crate::Result<()> {
self.trigger(event, Some(serde_json::to_string(&payload)?));
self.emit(event, payload)
}
pub(crate) fn emit_internal<S: Serialize>(
&self,
event: &str,
source_window_label: Option<&str>,
payload: S,
) -> crate::Result<()> {
self.eval(&format!(
"(function () {{ const fn = window['{}']; fn && fn({{event: {}, windowLabel: {}, payload: {}}}) }})()",
self.manager.event_emit_function_name(),
serde_json::to_string(event)?,
serde_json::to_string(&source_window_label)?,
serde_json::to_value(payload)?,
))?;
Ok(())
}
pub fn emit<S: Serialize + Clone>(&self, event: &str, payload: S) -> crate::Result<()> {
self
.manager
.emit_filter(event, Some(self.label()), payload, |w| {
w.has_js_listener(None, event) || w.has_js_listener(Some(self.label().into()), event)
})?;
Ok(())
}
pub fn listen<F>(&self, event: impl Into<String>, handler: F) -> EventHandler
where
F: Fn(Event) + Send + 'static,
{
let label = self.window.label.clone();
self.manager.listen(event.into(), Some(label), handler)
}
pub fn unlisten(&self, handler_id: EventHandler) {
self.manager.unlisten(handler_id)
}
pub fn once<F>(&self, event: impl Into<String>, handler: F) -> EventHandler
where
F: FnOnce(Event) + Send + 'static,
{
let label = self.window.label.clone();
self.manager.once(event.into(), Some(label), handler)
}
pub fn trigger(&self, event: &str, data: Option<String>) {
let label = self.window.label.clone();
self.manager.trigger(event, Some(label), data)
}
}
#[cfg(test)]
mod tests {
#[test]
fn window_is_send_sync() {
crate::test_utils::assert_send::<super::Window>();
crate::test_utils::assert_sync::<super::Window>();
}
}