mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-04-03 10:11:15 +02:00
refactor: move runtime to tauri-runtime crate (#1751)
This commit is contained in:
committed by
GitHub
parent
e84949524c
commit
665ec1d4a1
@@ -214,6 +214,14 @@
|
||||
"path": "./core/tauri-utils",
|
||||
"manager": "rust"
|
||||
},
|
||||
"tauri-runtime": {
|
||||
"path": "./core/tauri-runtime",
|
||||
"manager": "rust",
|
||||
"dependencies": [
|
||||
"tauri-utils"
|
||||
],
|
||||
"postversion": "node ../../.scripts/sync-prerelease.js ${ release.type }"
|
||||
},
|
||||
"tauri-codegen": {
|
||||
"path": "./core/tauri-codegen",
|
||||
"manager": "rust",
|
||||
@@ -241,7 +249,8 @@
|
||||
"manager": "rust",
|
||||
"dependencies": [
|
||||
"tauri-macros",
|
||||
"tauri-utils"
|
||||
"tauri-utils",
|
||||
"tauri-runtime"
|
||||
],
|
||||
"postversion": "node ../../.scripts/sync-cli-metadata.js ${ pkg.pkg } ${ release.type }"
|
||||
},
|
||||
@@ -276,4 +285,4 @@
|
||||
"manager": "javascript"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
.changes/runtime-crate.md
Normal file
6
.changes/runtime-crate.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"tauri-runtime": patch
|
||||
"tauri": patch
|
||||
---
|
||||
|
||||
`tauri-runtime` crate initial release.
|
||||
31
.scripts/sync-prerelease.js
Normal file
31
.scripts/sync-prerelease.js
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env node
|
||||
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/*
|
||||
This script is solely intended to be run as part of the `covector version` step to
|
||||
keep the `tauri-release` crate version without the `beta` or `beta-rc` suffix.
|
||||
*/
|
||||
|
||||
const { readFileSync, writeFileSync } = require("fs")
|
||||
|
||||
const runtimeManifestPath = '../../core/tauri-runtime/Cargo.toml'
|
||||
const dependencyManifestPaths = ['../../core/tauri/Cargo.toml']
|
||||
const changelogPath = '../../core/tauri-runtime/CHANGELOG.md'
|
||||
|
||||
const bump = process.argv[2]
|
||||
|
||||
let runtimeManifest = readFileSync(runtimeManifestPath, "utf-8")
|
||||
runtimeManifest = runtimeManifest.replace(/version = "(\d+\.\d+\.\d+)-[^0-9\.]+\.0"/, 'version = "$1"')
|
||||
writeFileSync(runtimeManifestPath, runtimeManifest)
|
||||
|
||||
let changelog = readFileSync(changelogPath, "utf-8")
|
||||
changelog = changelog.replace(/(\d+\.\d+\.\d+)-[^0-9\.]+\.0/, '$1')
|
||||
writeFileSync(changelogPath, changelog)
|
||||
|
||||
for (const dependencyManifestPath of dependencyManifestPaths) {
|
||||
let dependencyManifest = readFileSync(dependencyManifestPath, "utf-8")
|
||||
dependencyManifest = dependencyManifest.replace(/tauri-runtime = { version = "(\d+\.\d+\.\d+)-[^0-9\.]+\.0"/, 'tauri-runtime = { version = "$1"')
|
||||
writeFileSync(dependencyManifestPath, dependencyManifest)
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
members = [
|
||||
# core
|
||||
"core/tauri",
|
||||
"core/tauri-runtime",
|
||||
"core/tauri-macros",
|
||||
"core/tauri-utils",
|
||||
"core/tauri-build",
|
||||
|
||||
19
core/tauri-runtime/Cargo.toml
Normal file
19
core/tauri-runtime/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "tauri-runtime"
|
||||
version = "0.0.0"
|
||||
authors = [ "Tauri Programme within The Commons Conservancy" ]
|
||||
categories = [ "gui", "web-programming" ]
|
||||
license = "Apache-2.0 OR MIT"
|
||||
homepage = "https://tauri.studio"
|
||||
repository = "https://github.com/tauri-apps/tauri"
|
||||
description = "Runtime for Tauri applications"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
serde_json = "1.0"
|
||||
thiserror = "1.0"
|
||||
uuid = { version = "0.8.2", features = [ "v4" ] }
|
||||
tauri-utils = { version = "1.0.0-beta-rc.1", path = "../tauri-utils" }
|
||||
wry = { git = "https://github.com/tauri-apps/wry", rev = "6bc97aff525644b83a3a00537316c46d7afb985b" }
|
||||
image = "0.23"
|
||||
@@ -5,23 +5,19 @@
|
||||
//! The [`wry`] Tauri [`Runtime`].
|
||||
|
||||
use crate::{
|
||||
api::config::WindowConfig,
|
||||
runtime::{
|
||||
menu::{CustomMenuItem, Menu, MenuId, MenuItem, SystemTrayMenuItem},
|
||||
webview::{
|
||||
FileDropEvent, FileDropHandler, RpcRequest, WebviewRpcHandler, WindowBuilder,
|
||||
WindowBuilderBase,
|
||||
},
|
||||
window::{
|
||||
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
|
||||
DetachedWindow, MenuEvent, PendingWindow, WindowEvent,
|
||||
},
|
||||
Dispatch, Monitor, Params, Runtime, SystemTrayEvent,
|
||||
menu::{CustomMenuItem, Menu, MenuId, MenuItem, SystemTrayMenuItem},
|
||||
webview::{
|
||||
FileDropEvent, FileDropHandler, RpcRequest, WebviewRpcHandler, WindowBuilder, WindowBuilderBase,
|
||||
},
|
||||
Icon,
|
||||
window::{
|
||||
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
|
||||
DetachedWindow, MenuEvent, PendingWindow, WindowEvent,
|
||||
},
|
||||
Dispatch, Icon, Monitor, Params, Runtime, SystemTrayEvent,
|
||||
};
|
||||
|
||||
use image::{GenericImageView, Pixel};
|
||||
use tauri_utils::config::WindowConfig;
|
||||
use uuid::Uuid;
|
||||
use wry::{
|
||||
application::{
|
||||
@@ -1043,7 +1039,7 @@ fn create_webview<M: Params<Runtime = Wry>>(
|
||||
) -> crate::Result<WebView> {
|
||||
let PendingWindow {
|
||||
webview_attributes,
|
||||
window_attributes,
|
||||
window_builder,
|
||||
rpc_handler,
|
||||
file_drop_handler,
|
||||
label,
|
||||
@@ -1051,7 +1047,7 @@ fn create_webview<M: Params<Runtime = Wry>>(
|
||||
..
|
||||
} = pending;
|
||||
|
||||
let window = window_attributes.build(event_loop).unwrap();
|
||||
let window = window_builder.build(event_loop).unwrap();
|
||||
let mut webview_builder = WebViewBuilder::new(window)
|
||||
.map_err(|e| crate::Error::CreateWebview(Box::new(e)))?
|
||||
.with_url(&url)
|
||||
@@ -4,15 +4,12 @@
|
||||
|
||||
//! Internal runtime between Tauri and the underlying webview runtime.
|
||||
|
||||
use crate::{
|
||||
runtime::window::{DetachedWindow, PendingWindow},
|
||||
Icon, Params, WindowBuilder,
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use tauri_utils::assets::Assets;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub(crate) mod app;
|
||||
pub mod flavors;
|
||||
pub(crate) mod manager;
|
||||
/// Create window and system tray menus.
|
||||
pub mod menu;
|
||||
/// Types useful for interacting with a user's monitors.
|
||||
@@ -23,14 +20,78 @@ pub mod window;
|
||||
|
||||
use menu::{MenuId, SystemTrayMenuItem};
|
||||
use monitor::Monitor;
|
||||
use tag::Tag;
|
||||
use webview::WindowBuilder;
|
||||
use window::{
|
||||
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||
MenuEvent, WindowEvent,
|
||||
DetachedWindow, MenuEvent, PendingWindow, WindowEvent,
|
||||
};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum Error {
|
||||
/// Failed to create webview.
|
||||
#[error("failed to create webview: {0}")]
|
||||
CreateWebview(Box<dyn std::error::Error + Send>),
|
||||
/// Failed to create window.
|
||||
#[error("failed to create window")]
|
||||
CreateWindow,
|
||||
/// Failed to send message to webview.
|
||||
#[error("failed to send message to the webview")]
|
||||
FailedToSendMessage,
|
||||
/// Failed to serialize/deserialize.
|
||||
#[error("JSON error: {0}")]
|
||||
Json(#[from] serde_json::Error),
|
||||
/// Encountered an error creating the app system tray,
|
||||
#[error("error encountered during tray setup: {0}")]
|
||||
SystemTray(Box<dyn std::error::Error + Send>),
|
||||
/// Failed to load window icon.
|
||||
#[error("invalid icon: {0}")]
|
||||
InvalidIcon(Box<dyn std::error::Error + Send>),
|
||||
}
|
||||
|
||||
/// Result type.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod private {
|
||||
pub trait ParamsBase {}
|
||||
}
|
||||
|
||||
/// Types associated with the running Tauri application.
|
||||
pub trait Params: private::ParamsBase + 'static {
|
||||
/// The event type used to create and listen to events.
|
||||
type Event: Tag;
|
||||
|
||||
/// The type used to determine the name of windows.
|
||||
type Label: Tag;
|
||||
|
||||
/// The type used to determine window menu ids.
|
||||
type MenuId: MenuId;
|
||||
|
||||
/// The type used to determine system tray menu ids.
|
||||
type SystemTrayMenuId: MenuId;
|
||||
|
||||
/// Assets that Tauri should serve from itself.
|
||||
type Assets: Assets;
|
||||
|
||||
/// The underlying webview runtime used by the Tauri application.
|
||||
type Runtime: Runtime;
|
||||
}
|
||||
|
||||
/// A icon definition.
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub enum Icon {
|
||||
/// Icon from file path.
|
||||
File(PathBuf),
|
||||
/// Icon from raw bytes.
|
||||
Raw(Vec<u8>),
|
||||
}
|
||||
|
||||
/// A system tray event.
|
||||
pub struct SystemTrayEvent {
|
||||
pub(crate) menu_item_id: u32,
|
||||
pub menu_item_id: u32,
|
||||
}
|
||||
|
||||
/// The webview runtime interface.
|
||||
@@ -8,16 +8,18 @@ use std::{
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
|
||||
/// A type that can be derived into a menu id.
|
||||
pub trait MenuId: Hash + Eq + Debug + Clone + Send + Sync + 'static {}
|
||||
use serde::Serialize;
|
||||
|
||||
impl<T> MenuId for T where T: Hash + Eq + Debug + Clone + Send + Sync + 'static {}
|
||||
/// A type that can be derived into a menu id.
|
||||
pub trait MenuId: Serialize + Hash + Eq + Debug + Clone + Send + Sync + 'static {}
|
||||
|
||||
impl<T> MenuId for T where T: Serialize + Hash + Eq + Debug + Clone + Send + Sync + 'static {}
|
||||
|
||||
/// A window menu.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Menu<I: MenuId> {
|
||||
pub(crate) title: String,
|
||||
pub(crate) items: Vec<MenuItem<I>>,
|
||||
pub title: String,
|
||||
pub items: Vec<MenuItem<I>>,
|
||||
}
|
||||
|
||||
impl<I: MenuId> Menu<I> {
|
||||
@@ -29,11 +31,12 @@ impl<I: MenuId> Menu<I> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A custom menu item.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CustomMenuItem<I: MenuId> {
|
||||
pub(crate) id: I,
|
||||
pub(crate) name: String,
|
||||
pub id: I,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl<I: MenuId> CustomMenuItem<I> {
|
||||
@@ -43,7 +46,8 @@ impl<I: MenuId> CustomMenuItem<I> {
|
||||
Self { id, name: title }
|
||||
}
|
||||
|
||||
pub(crate) fn id_value(&self) -> u32 {
|
||||
#[doc(hidden)]
|
||||
pub fn id_value(&self) -> u32 {
|
||||
let mut s = DefaultHasher::new();
|
||||
self.id.hash(&mut s);
|
||||
s.finish() as u32
|
||||
@@ -71,7 +71,7 @@ use std::{
|
||||
/// let event: Event = "tauri://file-drop".parse().unwrap();
|
||||
///
|
||||
/// // show that this event type can be represented as a Tag, a requirement for using it in Tauri.
|
||||
/// fn is_file_drop(tag: impl tauri::runtime::tag::Tag) {
|
||||
/// fn is_file_drop(tag: impl tauri_runtime::tag::Tag) {
|
||||
/// assert_eq!("tauri://file-drop", tag.to_string());
|
||||
/// }
|
||||
///
|
||||
@@ -113,7 +113,7 @@ where
|
||||
///
|
||||
/// We don't want downstream users to implement this trait so that [`Tag`]s cannot be turned into
|
||||
/// invalid JavaScript - regardless of their content.
|
||||
pub(crate) trait ToJsString {
|
||||
pub trait ToJsString {
|
||||
fn to_js_string(&self) -> crate::Result<String>;
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ impl<D: Display> ToJsString for D {
|
||||
}
|
||||
|
||||
/// Turn any collection of [`Tag`]s into a JavaScript array of strings.
|
||||
pub(crate) fn tags_to_javascript_array(tags: &[impl Tag]) -> crate::Result<String> {
|
||||
pub fn tags_to_javascript_array(tags: &[impl Tag]) -> crate::Result<String> {
|
||||
let tags: Vec<String> = tags.iter().map(ToString::to_string).collect();
|
||||
Ok(serde_json::to_string(&tags)?)
|
||||
}
|
||||
@@ -4,26 +4,27 @@
|
||||
|
||||
//! Items specific to the [`Runtime`](crate::runtime::Runtime)'s webview.
|
||||
|
||||
use crate::runtime::Icon;
|
||||
use crate::{
|
||||
api::config::{WindowConfig, WindowUrl},
|
||||
runtime::{
|
||||
menu::{Menu, MenuId},
|
||||
window::DetachedWindow,
|
||||
},
|
||||
menu::{Menu, MenuId},
|
||||
window::DetachedWindow,
|
||||
Icon,
|
||||
};
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
use tauri_utils::config::{WindowConfig, WindowUrl};
|
||||
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
type UriSchemeProtocol = dyn Fn(&str) -> crate::Result<Vec<u8>> + Send + Sync + 'static;
|
||||
type UriSchemeProtocol =
|
||||
dyn Fn(&str) -> Result<Vec<u8>, Box<dyn std::error::Error>> + Send + Sync + 'static;
|
||||
|
||||
/// The attributes used to create an webview.
|
||||
pub struct WebviewAttributes {
|
||||
pub(crate) url: WindowUrl,
|
||||
pub(crate) initialization_scripts: Vec<String>,
|
||||
pub(crate) data_directory: Option<PathBuf>,
|
||||
pub(crate) uri_scheme_protocols: HashMap<String, Box<UriSchemeProtocol>>,
|
||||
pub url: WindowUrl,
|
||||
pub initialization_scripts: Vec<String>,
|
||||
pub data_directory: Option<PathBuf>,
|
||||
pub uri_scheme_protocols: HashMap<String, Box<UriSchemeProtocol>>,
|
||||
}
|
||||
|
||||
impl WebviewAttributes {
|
||||
@@ -65,7 +66,7 @@ impl WebviewAttributes {
|
||||
/// * `protocol` the protocol associated with the given URI scheme. It's a function that takes an URL such as `example://localhost/asset.css`.
|
||||
pub fn register_uri_scheme_protocol<
|
||||
N: Into<String>,
|
||||
H: Fn(&str) -> crate::Result<Vec<u8>> + Send + Sync + 'static,
|
||||
H: Fn(&str) -> Result<Vec<u8>, Box<dyn std::error::Error>> + Send + Sync + 'static,
|
||||
>(
|
||||
mut self,
|
||||
uri_scheme: N,
|
||||
@@ -146,7 +147,6 @@ pub trait WindowBuilder: WindowBuilderBase {
|
||||
}
|
||||
|
||||
/// Rpc request.
|
||||
#[non_exhaustive]
|
||||
pub struct RpcRequest {
|
||||
/// RPC command.
|
||||
pub command: String,
|
||||
@@ -157,7 +157,8 @@ pub struct RpcRequest {
|
||||
/// Uses a custom URI scheme handler to resolve file requests
|
||||
pub struct CustomProtocol {
|
||||
/// Handler for protocol
|
||||
pub protocol: Box<dyn Fn(&str) -> crate::Result<Vec<u8>> + Send + Sync>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub protocol: Box<dyn Fn(&str) -> Result<Vec<u8>, Box<dyn std::error::Error>> + Send + Sync>,
|
||||
}
|
||||
|
||||
/// The file drop event payload.
|
||||
@@ -173,18 +174,18 @@ pub enum FileDropEvent {
|
||||
}
|
||||
|
||||
/// Rpc handler.
|
||||
pub(crate) type WebviewRpcHandler<M> = Box<dyn Fn(DetachedWindow<M>, RpcRequest) + Send>;
|
||||
pub type WebviewRpcHandler<M> = Box<dyn Fn(DetachedWindow<M>, RpcRequest) + Send>;
|
||||
|
||||
/// File drop handler callback
|
||||
/// Return `true` in the callback to block the OS' default behavior of handling a file drop.
|
||||
pub(crate) type FileDropHandler<M> = Box<dyn Fn(FileDropEvent, DetachedWindow<M>) -> bool + Send>;
|
||||
pub type FileDropHandler<M> = Box<dyn Fn(FileDropEvent, DetachedWindow<M>) -> bool + Send>;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub(crate) struct InvokePayload {
|
||||
pub struct InvokePayload {
|
||||
#[serde(rename = "__tauriModule")]
|
||||
pub(crate) tauri_module: Option<String>,
|
||||
pub(crate) callback: String,
|
||||
pub(crate) error: String,
|
||||
pub tauri_module: Option<String>,
|
||||
pub callback: String,
|
||||
pub error: String,
|
||||
#[serde(flatten)]
|
||||
pub(crate) inner: JsonValue,
|
||||
pub inner: JsonValue,
|
||||
}
|
||||
147
core/tauri-runtime/src/window.rs
Normal file
147
core/tauri-runtime/src/window.rs
Normal file
@@ -0,0 +1,147 @@
|
||||
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//! A layer between raw [`Runtime`] webview windows and Tauri.
|
||||
|
||||
use crate::{
|
||||
webview::{FileDropHandler, WebviewAttributes, WebviewRpcHandler},
|
||||
Dispatch, Params, Runtime, WindowBuilder,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use tauri_utils::config::WindowConfig;
|
||||
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
/// UI scaling utilities.
|
||||
pub mod dpi;
|
||||
|
||||
/// An event from a window.
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub enum WindowEvent {
|
||||
/// The size of the window has changed. Contains the client area's new dimensions.
|
||||
Resized(dpi::PhysicalSize<u32>),
|
||||
/// The position of the window has changed. Contains the window's new position.
|
||||
Moved(dpi::PhysicalPosition<i32>),
|
||||
/// The window has been requested to close.
|
||||
CloseRequested,
|
||||
/// The window has been destroyed.
|
||||
Destroyed,
|
||||
/// The window gained or lost focus.
|
||||
///
|
||||
/// The parameter is true if the window has gained focus, and false if it has lost focus.
|
||||
Focused(bool),
|
||||
///The window's scale factor has changed.
|
||||
///
|
||||
/// The following user actions can cause DPI changes:
|
||||
///
|
||||
/// - Changing the display's resolution.
|
||||
/// - Changing the display's scale factor (e.g. in Control Panel on Windows).
|
||||
/// - Moving the window to a display with a different scale factor.
|
||||
#[non_exhaustive]
|
||||
ScaleFactorChanged {
|
||||
/// The new scale factor.
|
||||
scale_factor: f64,
|
||||
/// The window inner size.
|
||||
new_inner_size: dpi::PhysicalSize<u32>,
|
||||
},
|
||||
}
|
||||
|
||||
/// A menu event.
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MenuEvent {
|
||||
pub menu_item_id: u32,
|
||||
}
|
||||
|
||||
/// A webview window that has yet to be built.
|
||||
pub struct PendingWindow<M: Params> {
|
||||
/// The label that the window will be named.
|
||||
pub label: M::Label,
|
||||
|
||||
/// The [`WindowBuilder`] that the window will be created with.
|
||||
pub window_builder: <<M::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
|
||||
|
||||
/// The [`WebviewAttributes`] that the webview will be created with.
|
||||
pub webview_attributes: WebviewAttributes,
|
||||
|
||||
/// How to handle RPC calls on the webview window.
|
||||
pub rpc_handler: Option<WebviewRpcHandler<M>>,
|
||||
|
||||
/// How to handle a file dropping onto the webview window.
|
||||
pub file_drop_handler: Option<FileDropHandler<M>>,
|
||||
|
||||
/// The resolved URL to load on the webview.
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
impl<M: Params> PendingWindow<M> {
|
||||
/// Create a new [`PendingWindow`] with a label and starting url.
|
||||
pub fn new(
|
||||
window_builder: <<M::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
|
||||
webview_attributes: WebviewAttributes,
|
||||
label: M::Label,
|
||||
) -> Self {
|
||||
Self {
|
||||
window_builder,
|
||||
webview_attributes,
|
||||
label,
|
||||
rpc_handler: None,
|
||||
file_drop_handler: None,
|
||||
url: "tauri://localhost".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [`PendingWindow`] from a [`WindowConfig`] with a label and starting url.
|
||||
pub fn with_config(
|
||||
window_config: WindowConfig,
|
||||
webview_attributes: WebviewAttributes,
|
||||
label: M::Label,
|
||||
) -> Self {
|
||||
Self {
|
||||
window_builder:
|
||||
<<<M::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder>::with_config(
|
||||
window_config,
|
||||
),
|
||||
webview_attributes,
|
||||
label,
|
||||
rpc_handler: None,
|
||||
file_drop_handler: None,
|
||||
url: "tauri://localhost".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A webview window that is not yet managed by Tauri.
|
||||
pub struct DetachedWindow<M: Params> {
|
||||
/// Name of the window
|
||||
pub label: M::Label,
|
||||
|
||||
/// The [`Dispatch`](crate::runtime::Dispatch) associated with the window.
|
||||
pub dispatcher: <M::Runtime as Runtime>::Dispatcher,
|
||||
}
|
||||
|
||||
impl<M: Params> Clone for DetachedWindow<M> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
label: self.label.clone(),
|
||||
dispatcher: self.dispatcher.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Params> Hash for DetachedWindow<M> {
|
||||
/// Only use the [`DetachedWindow`]'s label to represent its hash.
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.label.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Params> Eq for DetachedWindow<M> {}
|
||||
impl<M: Params> PartialEq for DetachedWindow<M> {
|
||||
/// Only use the [`DetachedWindow`]'s label to compare equality.
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.label.eq(&other.label)
|
||||
}
|
||||
}
|
||||
@@ -22,9 +22,9 @@ futures = "0.3"
|
||||
uuid = { version = "0.8.2", features = [ "v4" ] }
|
||||
thiserror = "1.0.24"
|
||||
once_cell = "1.7.2"
|
||||
tauri-runtime = { version = "0.0.0", path = "../tauri-runtime" }
|
||||
tauri-macros = { version = "1.0.0-beta-rc.1", path = "../tauri-macros" }
|
||||
tauri-utils = { version = "1.0.0-beta-rc.1", path = "../tauri-utils" }
|
||||
wry = { git = "https://github.com/tauri-apps/wry", rev = "6bc97aff525644b83a3a00537316c46d7afb985b" }
|
||||
rand = "0.8"
|
||||
reqwest = { version = "0.11", features = [ "json", "multipart" ] }
|
||||
tempfile = "3"
|
||||
|
||||
@@ -3,20 +3,21 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::{
|
||||
api::{assets::Assets, config::WindowUrl},
|
||||
api::assets::Assets,
|
||||
api::config::WindowUrl,
|
||||
hooks::{InvokeHandler, OnPageLoad, PageLoadPayload, SetupHook},
|
||||
manager::{Args, WindowManager},
|
||||
plugin::{Plugin, PluginStore},
|
||||
runtime::{
|
||||
flavors::wry::Wry,
|
||||
manager::{Args, WindowManager},
|
||||
menu::{Menu, MenuId, SystemTrayMenuItem},
|
||||
tag::Tag,
|
||||
webview::{CustomProtocol, WebviewAttributes, WindowBuilder},
|
||||
window::PendingWindow,
|
||||
Dispatch, Runtime,
|
||||
Dispatch, Params, Runtime,
|
||||
},
|
||||
sealed::{ManagerBase, RuntimeOrDispatch},
|
||||
Context, Invoke, Manager, Params, StateManager, Window,
|
||||
Context, Invoke, Manager, StateManager, Window,
|
||||
};
|
||||
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
@@ -97,13 +98,13 @@ impl<P: Params> App<P> {
|
||||
WebviewAttributes,
|
||||
),
|
||||
{
|
||||
let (window_attributes, webview_attributes) = setup(
|
||||
let (window_builder, webview_attributes) = setup(
|
||||
<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder::new(),
|
||||
WebviewAttributes::new(url),
|
||||
);
|
||||
self.create_new_window(
|
||||
RuntimeOrDispatch::Runtime(&self.runtime),
|
||||
PendingWindow::new(window_attributes, webview_attributes, label),
|
||||
PendingWindow::new(window_builder, webview_attributes, label),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -337,12 +338,12 @@ where
|
||||
WebviewAttributes,
|
||||
),
|
||||
{
|
||||
let (window_attributes, webview_attributes) = setup(
|
||||
let (window_builder, webview_attributes) = setup(
|
||||
<R::Dispatcher as Dispatch>::WindowBuilder::new(),
|
||||
WebviewAttributes::new(url),
|
||||
);
|
||||
self.pending_windows.push(PendingWindow::new(
|
||||
window_attributes,
|
||||
window_builder,
|
||||
webview_attributes,
|
||||
label,
|
||||
));
|
||||
@@ -394,7 +395,7 @@ where
|
||||
/// * `protocol` the protocol associated with the given URI scheme. It's a function that takes an URL such as `example://localhost/asset.css`.
|
||||
pub fn register_global_uri_scheme_protocol<
|
||||
N: Into<String>,
|
||||
H: Fn(&str) -> crate::Result<Vec<u8>> + Send + Sync + 'static,
|
||||
H: Fn(&str) -> Result<Vec<u8>, Box<dyn std::error::Error>> + Send + Sync + 'static,
|
||||
>(
|
||||
mut self,
|
||||
uri_scheme: N,
|
||||
@@ -12,7 +12,7 @@ use crate::{
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::Icon;
|
||||
use crate::runtime::Icon;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -115,7 +115,7 @@ impl Cmd {
|
||||
)
|
||||
})?
|
||||
.emit_others(
|
||||
&crate::runtime::manager::tauri_event::<P::Event>("tauri://window-created"),
|
||||
&crate::manager::tauri_event::<P::Event>("tauri://window-created"),
|
||||
Some(WindowCreatedEvent {
|
||||
label: label.to_string(),
|
||||
}),
|
||||
|
||||
@@ -8,6 +8,9 @@ use std::path::PathBuf;
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum Error {
|
||||
/// Runtime error.
|
||||
#[error("runtime error: {0}")]
|
||||
Runtime(#[from] tauri_runtime::Error),
|
||||
/// Failed to create webview.
|
||||
#[error("failed to create webview: {0}")]
|
||||
CreateWebview(Box<dyn std::error::Error + Send>),
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
use crate::{
|
||||
api::rpc::{format_callback, format_callback_result},
|
||||
runtime::app::App,
|
||||
app::App,
|
||||
Params, StateManager, Window,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -16,6 +16,7 @@ pub use tauri_macros::{command, generate_handler};
|
||||
|
||||
/// Core API.
|
||||
pub mod api;
|
||||
pub(crate) mod app;
|
||||
/// Async runtime.
|
||||
pub mod async_runtime;
|
||||
pub mod command;
|
||||
@@ -24,8 +25,11 @@ mod endpoints;
|
||||
mod error;
|
||||
mod event;
|
||||
mod hooks;
|
||||
mod manager;
|
||||
pub mod plugin;
|
||||
pub mod runtime;
|
||||
/// Tauri window.
|
||||
pub mod window;
|
||||
use tauri_runtime as runtime;
|
||||
/// The Tauri-specific settings for your runtime e.g. notification permission status.
|
||||
pub mod settings;
|
||||
mod state;
|
||||
@@ -40,38 +44,34 @@ pub type SyncTask = Box<dyn FnOnce() + Send>;
|
||||
|
||||
use crate::{
|
||||
event::{Event, EventHandler},
|
||||
runtime::{
|
||||
tag::{Tag, TagRef},
|
||||
window::PendingWindow,
|
||||
Runtime,
|
||||
},
|
||||
runtime::window::PendingWindow,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use std::{borrow::Borrow, collections::HashMap, path::PathBuf, sync::Arc};
|
||||
|
||||
// Export types likely to be used by the application.
|
||||
pub use {
|
||||
self::api::{
|
||||
assets::Assets,
|
||||
config::{Config, WindowUrl},
|
||||
},
|
||||
self::api::assets::Assets,
|
||||
self::api::config::{Config, WindowUrl},
|
||||
self::app::{App, Builder, SystemTrayEvent, WindowMenuEvent},
|
||||
self::hooks::{
|
||||
Invoke, InvokeError, InvokeHandler, InvokeMessage, InvokeResolver, InvokeResponse, OnPageLoad,
|
||||
PageLoadPayload, SetupHook,
|
||||
},
|
||||
self::runtime::app::{App, Builder, SystemTrayEvent, WindowMenuEvent},
|
||||
self::runtime::flavors::wry::Wry,
|
||||
self::runtime::menu::{CustomMenuItem, Menu, MenuId, MenuItem, SystemTrayMenuItem},
|
||||
self::runtime::monitor::Monitor,
|
||||
self::runtime::webview::{WebviewAttributes, WindowBuilder},
|
||||
self::runtime::window::{
|
||||
export::{
|
||||
self::runtime::{
|
||||
flavors::wry::Wry,
|
||||
menu::{CustomMenuItem, Menu, MenuId, MenuItem, SystemTrayMenuItem},
|
||||
monitor::Monitor,
|
||||
tag::{Tag, TagRef},
|
||||
webview::{WebviewAttributes, WindowBuilder},
|
||||
window::{
|
||||
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Pixel, Position, Size},
|
||||
Window,
|
||||
WindowEvent,
|
||||
},
|
||||
WindowEvent,
|
||||
Params,
|
||||
},
|
||||
self::state::{State, StateManager},
|
||||
self::window::{MenuEvent, Window},
|
||||
tauri_utils::platform,
|
||||
};
|
||||
|
||||
@@ -109,16 +109,6 @@ macro_rules! tauri_build_context {
|
||||
};
|
||||
}
|
||||
|
||||
/// A icon definition.
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub enum Icon {
|
||||
/// Icon from file path.
|
||||
File(PathBuf),
|
||||
/// Icon from raw bytes.
|
||||
Raw(Vec<u8>),
|
||||
}
|
||||
|
||||
/// User supplied data required inside of a Tauri application.
|
||||
pub struct Context<A: Assets> {
|
||||
/// The config the application was prepared with.
|
||||
@@ -142,27 +132,6 @@ pub struct Context<A: Assets> {
|
||||
pub package_info: crate::api::PackageInfo,
|
||||
}
|
||||
|
||||
/// Types associated with the running Tauri application.
|
||||
pub trait Params: sealed::ParamsBase {
|
||||
/// The event type used to create and listen to events.
|
||||
type Event: Tag;
|
||||
|
||||
/// The type used to determine the name of windows.
|
||||
type Label: Tag;
|
||||
|
||||
/// The type used to determine window menu ids.
|
||||
type MenuId: MenuId;
|
||||
|
||||
/// The type used to determine system tray menu ids.
|
||||
type SystemTrayMenuId: MenuId;
|
||||
|
||||
/// Assets that Tauri should serve from itself.
|
||||
type Assets: Assets;
|
||||
|
||||
/// The underlying webview runtime used by the Tauri application.
|
||||
type Runtime: Runtime;
|
||||
}
|
||||
|
||||
/// Manages a running application.
|
||||
///
|
||||
/// TODO: expand these docs
|
||||
@@ -262,13 +231,10 @@ pub trait Manager<P: Params>: sealed::ManagerBase<P> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Prevent implementation details from leaking out of the [`Manager`] and [`Params`] traits.
|
||||
/// Prevent implementation details from leaking out of the [`Manager`] trait.
|
||||
pub(crate) mod sealed {
|
||||
use super::Params;
|
||||
use crate::runtime::{manager::WindowManager, Runtime};
|
||||
|
||||
/// No downstream implementations of [`Params`].
|
||||
pub trait ParamsBase: 'static {}
|
||||
use crate::manager::WindowManager;
|
||||
use tauri_runtime::{Params, Runtime};
|
||||
|
||||
/// A running [`Runtime`] or a dispatcher to it.
|
||||
pub enum RuntimeOrDispatch<'r, P: Params> {
|
||||
@@ -294,8 +260,10 @@ pub(crate) mod sealed {
|
||||
let labels = self.manager().labels().into_iter().collect::<Vec<_>>();
|
||||
let pending = self.manager().prepare_window(pending, &labels)?;
|
||||
match runtime {
|
||||
RuntimeOrDispatch::Runtime(runtime) => runtime.create_window(pending),
|
||||
RuntimeOrDispatch::Dispatch(mut dispatcher) => dispatcher.create_window(pending),
|
||||
RuntimeOrDispatch::Runtime(runtime) => runtime.create_window(pending).map_err(Into::into),
|
||||
RuntimeOrDispatch::Dispatch(mut dispatcher) => {
|
||||
dispatcher.create_window(pending).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
.map(|window| self.manager().attach_window(window))
|
||||
}
|
||||
|
||||
@@ -9,22 +9,22 @@ use crate::{
|
||||
path::{resolve_path, BaseDirectory},
|
||||
PackageInfo,
|
||||
},
|
||||
app::{GlobalMenuEventListener, WindowMenuEvent},
|
||||
event::{Event, EventHandler, Listeners},
|
||||
hooks::{InvokeHandler, OnPageLoad, PageLoadPayload},
|
||||
plugin::PluginStore,
|
||||
runtime::{
|
||||
app::{GlobalMenuEventListener, WindowMenuEvent},
|
||||
menu::{Menu, MenuId, MenuItem},
|
||||
private::ParamsBase,
|
||||
tag::{tags_to_javascript_array, Tag, TagRef, ToJsString},
|
||||
webview::{
|
||||
CustomProtocol, FileDropEvent, FileDropHandler, InvokePayload, WebviewRpcHandler,
|
||||
WindowBuilder,
|
||||
},
|
||||
window::{dpi::PhysicalSize, DetachedWindow, MenuEvent, PendingWindow, WindowEvent},
|
||||
Icon, Runtime,
|
||||
window::{dpi::PhysicalSize, DetachedWindow, PendingWindow, WindowEvent},
|
||||
Icon, Params, Runtime,
|
||||
},
|
||||
sealed::ParamsBase,
|
||||
App, Context, Invoke, Params, StateManager, Window,
|
||||
App, Context, Invoke, MenuEvent, StateManager, Window,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
@@ -203,6 +203,11 @@ impl<P: Params> WindowManager<P> {
|
||||
self.inner.state.clone()
|
||||
}
|
||||
|
||||
/// Get the menu ids mapper.
|
||||
pub(crate) fn menu_ids(&self) -> HashMap<u32, P::MenuId> {
|
||||
self.inner.menu_ids.clone()
|
||||
}
|
||||
|
||||
// setup content for dev-server
|
||||
#[cfg(dev)]
|
||||
fn get_url(&self) -> String {
|
||||
@@ -243,15 +248,15 @@ impl<P: Params> WindowManager<P> {
|
||||
current_window_label = label.to_js_string()?,
|
||||
));
|
||||
|
||||
if !pending.window_attributes.has_icon() {
|
||||
if !pending.window_builder.has_icon() {
|
||||
if let Some(default_window_icon) = &self.inner.default_window_icon {
|
||||
let icon = Icon::Raw(default_window_icon.clone());
|
||||
pending.window_attributes = pending.window_attributes.icon(icon)?;
|
||||
pending.window_builder = pending.window_builder.icon(icon)?;
|
||||
}
|
||||
}
|
||||
|
||||
if !pending.window_attributes.has_menu() {
|
||||
pending.window_attributes = pending.window_attributes.menu(self.inner.menu.clone());
|
||||
if !pending.window_builder.has_menu() {
|
||||
pending.window_builder = pending.window_builder.menu(self.inner.menu.clone());
|
||||
}
|
||||
|
||||
for (uri_scheme, protocol) in &self.inner.uri_scheme_protocols {
|
||||
@@ -344,7 +349,7 @@ impl<P: Params> WindowManager<P> {
|
||||
Err(e) => {
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("{:?}", e); // TODO log::error!
|
||||
Err(e)
|
||||
Err(Box::new(e))
|
||||
}
|
||||
}
|
||||
}),
|
||||
@@ -369,6 +374,7 @@ impl<P: Params> WindowManager<P> {
|
||||
&tauri_event::<P::Event>("tauri://file-drop-cancelled"),
|
||||
Some(()),
|
||||
),
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
});
|
||||
true
|
||||
@@ -394,9 +400,9 @@ impl<P: Params> WindowManager<P> {
|
||||
}}
|
||||
{plugin_initialization_script}
|
||||
"#,
|
||||
core_script = include_str!("../../scripts/core.js"),
|
||||
core_script = include_str!("../scripts/core.js"),
|
||||
bundle_script = if with_global_tauri {
|
||||
include_str!("../../scripts/bundle.js")
|
||||
include_str!("../scripts/bundle.js")
|
||||
} else {
|
||||
""
|
||||
},
|
||||
@@ -548,13 +554,12 @@ impl<P: Params> WindowManager<P> {
|
||||
});
|
||||
let window_ = window.clone();
|
||||
let menu_event_listeners = self.inner.menu_event_listeners.clone();
|
||||
let menu_ids = self.inner.menu_ids.clone();
|
||||
window.on_menu_event(move |event| {
|
||||
let _ = on_menu_event(&window_, event);
|
||||
let _ = on_menu_event(&window_, &event);
|
||||
for handler in menu_event_listeners.iter() {
|
||||
handler(WindowMenuEvent {
|
||||
window: window_.clone(),
|
||||
menu_item_id: menu_ids.get(&event.menu_item_id).unwrap().clone(),
|
||||
menu_item_id: event.menu_item_id.clone(),
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -727,6 +732,7 @@ fn on_window_event<P: Params>(window: &Window<P>, event: &WindowEvent) -> crate:
|
||||
WindowEvent::ScaleFactorChanged {
|
||||
scale_factor,
|
||||
new_inner_size,
|
||||
..
|
||||
} => window.emit(
|
||||
&WINDOW_SCALE_FACTOR_CHANGED_EVENT
|
||||
.parse()
|
||||
@@ -736,6 +742,7 @@ fn on_window_event<P: Params>(window: &Window<P>, event: &WindowEvent) -> crate:
|
||||
size: new_inner_size.clone(),
|
||||
}),
|
||||
)?,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -747,11 +754,11 @@ struct ScaleFactorChanged {
|
||||
size: PhysicalSize<u32>,
|
||||
}
|
||||
|
||||
fn on_menu_event<P: Params>(window: &Window<P>, event: &MenuEvent) -> crate::Result<()> {
|
||||
fn on_menu_event<P: Params>(window: &Window<P>, event: &MenuEvent<P::MenuId>) -> crate::Result<()> {
|
||||
window.emit(
|
||||
&MENU_EVENT
|
||||
.parse()
|
||||
.unwrap_or_else(|_| panic!("unhandled event")),
|
||||
Some(event),
|
||||
Some(event.menu_item_id.clone()),
|
||||
)
|
||||
}
|
||||
@@ -1,552 +0,0 @@
|
||||
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//! A layer between raw [`Runtime`] webview windows and Tauri.
|
||||
|
||||
use crate::{
|
||||
api::config::{WindowConfig, WindowUrl},
|
||||
event::{Event, EventHandler},
|
||||
hooks::{InvokeMessage, InvokeResolver, PageLoadPayload},
|
||||
runtime::{
|
||||
tag::ToJsString,
|
||||
webview::{FileDropHandler, InvokePayload, WebviewAttributes, WebviewRpcHandler},
|
||||
Dispatch, Monitor, Runtime,
|
||||
},
|
||||
sealed::{ManagerBase, RuntimeOrDispatch},
|
||||
Icon, Manager, Params, WindowBuilder,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
/// UI scaling utilities.
|
||||
pub mod dpi;
|
||||
|
||||
/// An event from a window.
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub enum WindowEvent {
|
||||
/// The size of the window has changed. Contains the client area's new dimensions.
|
||||
Resized(dpi::PhysicalSize<u32>),
|
||||
/// The position of the window has changed. Contains the window's new position.
|
||||
Moved(dpi::PhysicalPosition<i32>),
|
||||
/// The window has been requested to close.
|
||||
CloseRequested,
|
||||
/// The window has been destroyed.
|
||||
Destroyed,
|
||||
/// The window gained or lost focus.
|
||||
///
|
||||
/// The parameter is true if the window has gained focus, and false if it has lost focus.
|
||||
Focused(bool),
|
||||
///The window's scale factor has changed.
|
||||
///
|
||||
/// The following user actions can cause DPI changes:
|
||||
///
|
||||
/// - Changing the display's resolution.
|
||||
/// - Changing the display's scale factor (e.g. in Control Panel on Windows).
|
||||
/// - Moving the window to a display with a different scale factor.
|
||||
#[non_exhaustive]
|
||||
ScaleFactorChanged {
|
||||
/// The new scale factor.
|
||||
scale_factor: f64,
|
||||
/// The window inner size.
|
||||
new_inner_size: dpi::PhysicalSize<u32>,
|
||||
},
|
||||
}
|
||||
|
||||
/// A menu event.
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MenuEvent {
|
||||
pub(crate) menu_item_id: u32,
|
||||
}
|
||||
|
||||
/// A webview window that has yet to be built.
|
||||
pub struct PendingWindow<M: Params> {
|
||||
/// The label that the window will be named.
|
||||
pub label: M::Label,
|
||||
|
||||
/// The [`WindowBuilder`] that the window will be created with.
|
||||
pub window_attributes: <<M::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
|
||||
|
||||
/// The [`WebviewAttributes`] that the webview will be created with.
|
||||
pub webview_attributes: WebviewAttributes,
|
||||
|
||||
/// How to handle RPC calls on the webview window.
|
||||
pub rpc_handler: Option<WebviewRpcHandler<M>>,
|
||||
|
||||
/// How to handle a file dropping onto the webview window.
|
||||
pub file_drop_handler: Option<FileDropHandler<M>>,
|
||||
|
||||
/// The resolved URL to load on the webview.
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
impl<M: Params> PendingWindow<M> {
|
||||
/// Create a new [`PendingWindow`] with a label and starting url.
|
||||
pub fn new(
|
||||
window_attributes: <<M::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
|
||||
webview_attributes: WebviewAttributes,
|
||||
label: M::Label,
|
||||
) -> Self {
|
||||
Self {
|
||||
window_attributes,
|
||||
webview_attributes,
|
||||
label,
|
||||
rpc_handler: None,
|
||||
file_drop_handler: None,
|
||||
url: "tauri://localhost".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [`PendingWindow`] from a [`WindowConfig`] with a label and starting url.
|
||||
pub fn with_config(
|
||||
window_config: WindowConfig,
|
||||
webview_attributes: WebviewAttributes,
|
||||
label: M::Label,
|
||||
) -> Self {
|
||||
Self {
|
||||
window_attributes:
|
||||
<<<M::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder>::with_config(
|
||||
window_config,
|
||||
),
|
||||
webview_attributes,
|
||||
label,
|
||||
rpc_handler: None,
|
||||
file_drop_handler: None,
|
||||
url: "tauri://localhost".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A webview window that is not yet managed by Tauri.
|
||||
pub struct DetachedWindow<M: Params> {
|
||||
/// Name of the window
|
||||
pub label: M::Label,
|
||||
|
||||
/// The [`Dispatch`](crate::runtime::Dispatch) associated with the window.
|
||||
pub dispatcher: <M::Runtime as Runtime>::Dispatcher,
|
||||
}
|
||||
|
||||
impl<M: Params> Clone for DetachedWindow<M> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
label: self.label.clone(),
|
||||
dispatcher: self.dispatcher.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Params> Hash for DetachedWindow<M> {
|
||||
/// Only use the [`DetachedWindow`]'s label to represent its hash.
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.label.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Params> Eq for DetachedWindow<M> {}
|
||||
impl<M: Params> PartialEq for DetachedWindow<M> {
|
||||
/// Only use the [`DetachedWindow`]'s label to compare equality.
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.label.eq(&other.label)
|
||||
}
|
||||
}
|
||||
|
||||
/// We want to export the runtime related window at the crate root, but not look like a re-export.
|
||||
pub(crate) mod export {
|
||||
pub(crate) use super::dpi;
|
||||
use super::*;
|
||||
use crate::command::{CommandArg, CommandItem};
|
||||
use crate::runtime::{manager::WindowManager, tag::TagRef};
|
||||
use crate::{Invoke, InvokeError};
|
||||
use dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use std::borrow::Borrow;
|
||||
|
||||
/// A webview window managed by Tauri.
|
||||
///
|
||||
/// This type also implements [`Manager`] which allows you to manage other windows attached to
|
||||
/// the same application.
|
||||
///
|
||||
/// TODO: expand these docs since this is a pretty important type
|
||||
pub struct Window<P: Params> {
|
||||
/// The webview window created by the runtime.
|
||||
window: DetachedWindow<P>,
|
||||
|
||||
/// The manager to associate this webview window with.
|
||||
manager: WindowManager<P>,
|
||||
}
|
||||
|
||||
impl<M: Params> Clone for Window<M> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
window: self.window.clone(),
|
||||
manager: self.manager.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Hash for Window<P> {
|
||||
/// Only use the [`Window`]'s label to represent its hash.
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.window.label.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Eq for Window<P> {}
|
||||
impl<P: Params> PartialEq for Window<P> {
|
||||
/// Only use the [`Window`]'s label to compare equality.
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.window.label.eq(&other.window.label)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Manager<P> for Window<P> {}
|
||||
impl<P: Params> ManagerBase<P> for Window<P> {
|
||||
fn manager(&self) -> &WindowManager<P> {
|
||||
&self.manager
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, P: Params> CommandArg<'de, P> for Window<P> {
|
||||
/// Grabs the [`Window`] from the [`CommandItem`]. This will never fail.
|
||||
fn from_command(command: CommandItem<'de, P>) -> Result<Self, InvokeError> {
|
||||
Ok(command.message.window())
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Window<P> {
|
||||
/// Create a new window that is attached to the manager.
|
||||
pub(crate) fn new(manager: WindowManager<P>, window: DetachedWindow<P>) -> Self {
|
||||
Self { window, manager }
|
||||
}
|
||||
|
||||
/// Creates a new webview window.
|
||||
pub fn create_window<F>(
|
||||
&mut self,
|
||||
label: P::Label,
|
||||
url: WindowUrl,
|
||||
setup: F,
|
||||
) -> crate::Result<Window<P>>
|
||||
where
|
||||
F: FnOnce(
|
||||
<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
|
||||
WebviewAttributes,
|
||||
) -> (
|
||||
<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
|
||||
WebviewAttributes,
|
||||
),
|
||||
{
|
||||
let (window_attributes, webview_attributes) = setup(
|
||||
<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder::new(),
|
||||
WebviewAttributes::new(url),
|
||||
);
|
||||
self.create_new_window(
|
||||
RuntimeOrDispatch::Dispatch(self.dispatcher()),
|
||||
PendingWindow::new(window_attributes, webview_attributes, label),
|
||||
)
|
||||
}
|
||||
|
||||
/// The current window's dispatcher.
|
||||
pub(crate) fn dispatcher(&self) -> <P::Runtime as Runtime>::Dispatcher {
|
||||
self.window.dispatcher.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn run_on_main_thread<F: FnOnce() + Send + 'static>(
|
||||
&self,
|
||||
f: F,
|
||||
) -> crate::Result<()> {
|
||||
self.window.dispatcher.run_on_main_thread(f)
|
||||
}
|
||||
|
||||
/// How to handle this window receiving an [`InvokeMessage`].
|
||||
pub(crate) fn on_message(self, command: String, payload: InvokePayload) -> crate::Result<()> {
|
||||
let manager = self.manager.clone();
|
||||
match command.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(),
|
||||
command.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 {
|
||||
let module = module.to_string();
|
||||
crate::endpoints::handle(module, invoke, manager.config(), manager.package_info());
|
||||
} else if command.starts_with("plugin:") {
|
||||
manager.extend_api(invoke);
|
||||
} else {
|
||||
manager.run_invoke_handler(invoke);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The label of this window.
|
||||
pub fn label(&self) -> &P::Label {
|
||||
&self.window.label
|
||||
}
|
||||
|
||||
pub(crate) fn emit_internal<E: ?Sized, S>(
|
||||
&self,
|
||||
event: &E,
|
||||
payload: Option<S>,
|
||||
) -> crate::Result<()>
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
S: Serialize,
|
||||
{
|
||||
let js_payload = match payload {
|
||||
Some(payload_value) => serde_json::to_value(payload_value)?,
|
||||
None => JsonValue::Null,
|
||||
};
|
||||
|
||||
self.eval(&format!(
|
||||
"window['{}']({{event: {}, payload: {}}}, '{}')",
|
||||
self.manager.event_emit_function_name(),
|
||||
event.to_js_string()?,
|
||||
js_payload,
|
||||
self.manager.generate_salt(),
|
||||
))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emits an event to the current window.
|
||||
pub fn emit<E: ?Sized, S>(&self, event: &E, payload: Option<S>) -> crate::Result<()>
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
S: Serialize,
|
||||
{
|
||||
self.emit_internal(event, payload)
|
||||
}
|
||||
|
||||
/// Emits an event on all windows except this one.
|
||||
pub fn emit_others<E: ?Sized, S>(&self, event: &E, payload: Option<S>) -> crate::Result<()>
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
S: Serialize + Clone,
|
||||
{
|
||||
self.manager.emit_filter(event, payload, |w| w != self)
|
||||
}
|
||||
|
||||
/// Listen to an event on this window.
|
||||
pub fn listen<E: Into<P::Event>, F>(&self, event: E, handler: F) -> EventHandler
|
||||
where
|
||||
F: Fn(Event) + Send + 'static,
|
||||
{
|
||||
let label = self.window.label.clone();
|
||||
self.manager.listen(event.into(), Some(label), handler)
|
||||
}
|
||||
|
||||
/// Listen to a an event on this window a single time.
|
||||
pub fn once<E: Into<P::Event>, F>(&self, event: E, handler: F) -> EventHandler
|
||||
where
|
||||
F: Fn(Event) + Send + 'static,
|
||||
{
|
||||
let label = self.window.label.clone();
|
||||
self.manager.once(event.into(), Some(label), handler)
|
||||
}
|
||||
|
||||
/// Triggers an event on this window.
|
||||
pub fn trigger<E: ?Sized>(&self, event: &E, data: Option<String>)
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
{
|
||||
let label = self.window.label.clone();
|
||||
self.manager.trigger(event, Some(label), data)
|
||||
}
|
||||
|
||||
/// Evaluates JavaScript on this window.
|
||||
pub fn eval(&self, js: &str) -> crate::Result<()> {
|
||||
self.window.dispatcher.eval_script(js)
|
||||
}
|
||||
|
||||
/// Registers a window event listener.
|
||||
pub fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) {
|
||||
self.window.dispatcher.on_window_event(f);
|
||||
}
|
||||
|
||||
/// Registers a menu event listener.
|
||||
pub fn on_menu_event<F: Fn(&MenuEvent) + Send + 'static>(&self, f: F) {
|
||||
self.window.dispatcher.on_menu_event(f);
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
/// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
|
||||
pub fn scale_factor(&self) -> crate::Result<f64> {
|
||||
self.window.dispatcher.scale_factor()
|
||||
}
|
||||
|
||||
/// Returns the position of the top-left hand corner of the window's client area relative to the top-left hand corner of the desktop.
|
||||
pub fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>> {
|
||||
self.window.dispatcher.inner_position()
|
||||
}
|
||||
|
||||
/// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop.
|
||||
pub fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>> {
|
||||
self.window.dispatcher.outer_position()
|
||||
}
|
||||
|
||||
/// Returns the physical size of the window's client area.
|
||||
///
|
||||
/// The client area is the content of the window, excluding the title bar and borders.
|
||||
pub fn inner_size(&self) -> crate::Result<PhysicalSize<u32>> {
|
||||
self.window.dispatcher.inner_size()
|
||||
}
|
||||
|
||||
/// Returns the physical size of the entire window.
|
||||
///
|
||||
/// These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead.
|
||||
pub fn outer_size(&self) -> crate::Result<PhysicalSize<u32>> {
|
||||
self.window.dispatcher.outer_size()
|
||||
}
|
||||
|
||||
/// Gets the window's current fullscreen state.
|
||||
pub fn is_fullscreen(&self) -> crate::Result<bool> {
|
||||
self.window.dispatcher.is_fullscreen()
|
||||
}
|
||||
|
||||
/// Gets the window's current maximized state.
|
||||
pub fn is_maximized(&self) -> crate::Result<bool> {
|
||||
self.window.dispatcher.is_maximized()
|
||||
}
|
||||
|
||||
/// Returns the monitor on which the window currently resides.
|
||||
///
|
||||
/// Returns None if current monitor can't be detected.
|
||||
pub fn current_monitor(&self) -> crate::Result<Option<Monitor>> {
|
||||
self.window.dispatcher.current_monitor()
|
||||
}
|
||||
|
||||
/// Returns the primary monitor of the system.
|
||||
///
|
||||
/// Returns None if it can't identify any monitor as a primary one.
|
||||
pub fn primary_monitor(&self) -> crate::Result<Option<Monitor>> {
|
||||
self.window.dispatcher.primary_monitor()
|
||||
}
|
||||
|
||||
/// Returns the list of all the monitors available on the system.
|
||||
pub fn available_monitors(&self) -> crate::Result<Vec<Monitor>> {
|
||||
self.window.dispatcher.available_monitors()
|
||||
}
|
||||
|
||||
// Setters
|
||||
|
||||
/// 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<()> {
|
||||
self.window.dispatcher.print()
|
||||
}
|
||||
|
||||
/// Determines if this window should be resizable.
|
||||
pub fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
|
||||
self.window.dispatcher.set_resizable(resizable)
|
||||
}
|
||||
|
||||
/// Set this window's title.
|
||||
pub fn set_title(&self, title: &str) -> crate::Result<()> {
|
||||
self.window.dispatcher.set_title(title.to_string())
|
||||
}
|
||||
|
||||
/// Maximizes this window.
|
||||
pub fn maximize(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.maximize()
|
||||
}
|
||||
|
||||
/// Un-maximizes this window.
|
||||
pub fn unmaximize(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.unmaximize()
|
||||
}
|
||||
|
||||
/// Minimizes this window.
|
||||
pub fn minimize(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.minimize()
|
||||
}
|
||||
|
||||
/// Un-minimizes this window.
|
||||
pub fn unminimize(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.unminimize()
|
||||
}
|
||||
|
||||
/// Show this window.
|
||||
pub fn show(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.show()
|
||||
}
|
||||
|
||||
/// Hide this window.
|
||||
pub fn hide(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.hide()
|
||||
}
|
||||
|
||||
/// Closes this window.
|
||||
pub fn close(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.close()
|
||||
}
|
||||
|
||||
/// Determines if this window should be [decorated].
|
||||
///
|
||||
/// [decorated]: https://en.wikipedia.org/wiki/Window_(computing)#Window_decoration
|
||||
pub fn set_decorations(&self, decorations: bool) -> crate::Result<()> {
|
||||
self.window.dispatcher.set_decorations(decorations)
|
||||
}
|
||||
|
||||
/// Determines if this window should always be on top of other windows.
|
||||
pub fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> {
|
||||
self.window.dispatcher.set_always_on_top(always_on_top)
|
||||
}
|
||||
|
||||
/// Resizes this window.
|
||||
pub fn set_size<S: Into<Size>>(&self, size: S) -> crate::Result<()> {
|
||||
self.window.dispatcher.set_size(size.into())
|
||||
}
|
||||
|
||||
/// Sets this window's minimum size.
|
||||
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()))
|
||||
}
|
||||
|
||||
/// Sets this window's maximum size.
|
||||
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()))
|
||||
}
|
||||
|
||||
/// Sets this window's position.
|
||||
pub fn set_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
|
||||
self.window.dispatcher.set_position(position.into())
|
||||
}
|
||||
|
||||
/// Determines if this window should be fullscreen.
|
||||
pub fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
|
||||
self.window.dispatcher.set_fullscreen(fullscreen)
|
||||
}
|
||||
|
||||
/// Sets this window' icon.
|
||||
pub fn set_icon(&self, icon: Icon) -> crate::Result<()> {
|
||||
self.window.dispatcher.set_icon(icon)
|
||||
}
|
||||
|
||||
/// Starts dragging the window.
|
||||
pub fn start_dragging(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.start_dragging()
|
||||
}
|
||||
|
||||
pub(crate) fn verify_salt(&self, salt: String) -> bool {
|
||||
self.manager.verify_salt(salt)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,7 +339,7 @@ mod error;
|
||||
|
||||
pub use self::error::Error;
|
||||
|
||||
use crate::runtime::manager::tauri_event;
|
||||
use crate::manager::tauri_event;
|
||||
use crate::{
|
||||
api::{
|
||||
config::UpdaterConfig,
|
||||
|
||||
478
core/tauri/src/window.rs
Normal file
478
core/tauri/src/window.rs
Normal file
@@ -0,0 +1,478 @@
|
||||
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::{
|
||||
api::config::WindowUrl,
|
||||
command::{CommandArg, CommandItem},
|
||||
event::{Event, EventHandler},
|
||||
manager::WindowManager,
|
||||
runtime::{
|
||||
menu::MenuId,
|
||||
monitor::Monitor,
|
||||
tag::{TagRef, ToJsString},
|
||||
webview::{InvokePayload, WebviewAttributes, WindowBuilder},
|
||||
window::{
|
||||
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||
DetachedWindow, PendingWindow, WindowEvent,
|
||||
},
|
||||
Dispatch, Icon, Params, Runtime,
|
||||
},
|
||||
sealed::ManagerBase,
|
||||
sealed::RuntimeOrDispatch,
|
||||
Invoke, InvokeError, InvokeMessage, InvokeResolver, Manager, PageLoadPayload,
|
||||
};
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
|
||||
/// The window menu event.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MenuEvent<I: MenuId> {
|
||||
pub(crate) menu_item_id: I,
|
||||
}
|
||||
|
||||
impl<I: MenuId> MenuEvent<I> {
|
||||
/// The menu item id.
|
||||
pub fn menu_item_id(&self) -> &I {
|
||||
&self.menu_item_id
|
||||
}
|
||||
}
|
||||
|
||||
/// A webview window managed by Tauri.
|
||||
///
|
||||
/// This type also implements [`Manager`] which allows you to manage other windows attached to
|
||||
/// the same application.
|
||||
///
|
||||
/// TODO: expand these docs since this is a pretty important type
|
||||
pub struct Window<P: Params> {
|
||||
/// The webview window created by the runtime.
|
||||
window: DetachedWindow<P>,
|
||||
|
||||
/// The manager to associate this webview window with.
|
||||
manager: WindowManager<P>,
|
||||
}
|
||||
|
||||
impl<M: Params> Clone for Window<M> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
window: self.window.clone(),
|
||||
manager: self.manager.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Hash for Window<P> {
|
||||
/// Only use the [`Window`]'s label to represent its hash.
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.window.label.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Eq for Window<P> {}
|
||||
impl<P: Params> PartialEq for Window<P> {
|
||||
/// Only use the [`Window`]'s label to compare equality.
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.window.label.eq(&other.window.label)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Manager<P> for Window<P> {}
|
||||
impl<P: Params> ManagerBase<P> for Window<P> {
|
||||
fn manager(&self) -> &WindowManager<P> {
|
||||
&self.manager
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, P: Params> CommandArg<'de, P> for Window<P> {
|
||||
/// Grabs the [`Window`] from the [`CommandItem`]. This will never fail.
|
||||
fn from_command(command: CommandItem<'de, P>) -> Result<Self, InvokeError> {
|
||||
Ok(command.message.window())
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Params> Window<P> {
|
||||
/// Create a new window that is attached to the manager.
|
||||
pub(crate) fn new(manager: WindowManager<P>, window: DetachedWindow<P>) -> Self {
|
||||
Self { window, manager }
|
||||
}
|
||||
|
||||
/// Creates a new webview window.
|
||||
pub fn create_window<F>(
|
||||
&mut self,
|
||||
label: P::Label,
|
||||
url: WindowUrl,
|
||||
setup: F,
|
||||
) -> crate::Result<Window<P>>
|
||||
where
|
||||
F: FnOnce(
|
||||
<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
|
||||
WebviewAttributes,
|
||||
) -> (
|
||||
<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder,
|
||||
WebviewAttributes,
|
||||
),
|
||||
{
|
||||
let (window_builder, webview_attributes) = setup(
|
||||
<<P::Runtime as Runtime>::Dispatcher as Dispatch>::WindowBuilder::new(),
|
||||
WebviewAttributes::new(url),
|
||||
);
|
||||
self.create_new_window(
|
||||
RuntimeOrDispatch::Dispatch(self.dispatcher()),
|
||||
PendingWindow::new(window_builder, webview_attributes, label),
|
||||
)
|
||||
}
|
||||
|
||||
/// The current window's dispatcher.
|
||||
pub(crate) fn dispatcher(&self) -> <P::Runtime as Runtime>::Dispatcher {
|
||||
self.window.dispatcher.clone()
|
||||
}
|
||||
|
||||
pub(crate) 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)
|
||||
}
|
||||
|
||||
/// How to handle this window receiving an [`InvokeMessage`].
|
||||
pub(crate) fn on_message(self, command: String, payload: InvokePayload) -> crate::Result<()> {
|
||||
let manager = self.manager.clone();
|
||||
match command.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(),
|
||||
command.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 {
|
||||
let module = module.to_string();
|
||||
crate::endpoints::handle(module, invoke, manager.config(), manager.package_info());
|
||||
} else if command.starts_with("plugin:") {
|
||||
manager.extend_api(invoke);
|
||||
} else {
|
||||
manager.run_invoke_handler(invoke);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The label of this window.
|
||||
pub fn label(&self) -> &P::Label {
|
||||
&self.window.label
|
||||
}
|
||||
|
||||
pub(crate) fn emit_internal<E: ?Sized, S>(
|
||||
&self,
|
||||
event: &E,
|
||||
payload: Option<S>,
|
||||
) -> crate::Result<()>
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
S: Serialize,
|
||||
{
|
||||
let js_payload = match payload {
|
||||
Some(payload_value) => serde_json::to_value(payload_value)?,
|
||||
None => JsonValue::Null,
|
||||
};
|
||||
|
||||
self.eval(&format!(
|
||||
"window['{}']({{event: {}, payload: {}}}, '{}')",
|
||||
self.manager.event_emit_function_name(),
|
||||
event.to_js_string()?,
|
||||
js_payload,
|
||||
self.manager.generate_salt(),
|
||||
))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Emits an event to the current window.
|
||||
pub fn emit<E: ?Sized, S>(&self, event: &E, payload: Option<S>) -> crate::Result<()>
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
S: Serialize,
|
||||
{
|
||||
self.emit_internal(event, payload)
|
||||
}
|
||||
|
||||
/// Emits an event on all windows except this one.
|
||||
pub fn emit_others<E: ?Sized, S>(&self, event: &E, payload: Option<S>) -> crate::Result<()>
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
S: Serialize + Clone,
|
||||
{
|
||||
self.manager.emit_filter(event, payload, |w| w != self)
|
||||
}
|
||||
|
||||
/// Listen to an event on this window.
|
||||
pub fn listen<E: Into<P::Event>, F>(&self, event: E, handler: F) -> EventHandler
|
||||
where
|
||||
F: Fn(Event) + Send + 'static,
|
||||
{
|
||||
let label = self.window.label.clone();
|
||||
self.manager.listen(event.into(), Some(label), handler)
|
||||
}
|
||||
|
||||
/// Listen to a an event on this window a single time.
|
||||
pub fn once<E: Into<P::Event>, F>(&self, event: E, handler: F) -> EventHandler
|
||||
where
|
||||
F: Fn(Event) + Send + 'static,
|
||||
{
|
||||
let label = self.window.label.clone();
|
||||
self.manager.once(event.into(), Some(label), handler)
|
||||
}
|
||||
|
||||
/// Triggers an event on this window.
|
||||
pub fn trigger<E: ?Sized>(&self, event: &E, data: Option<String>)
|
||||
where
|
||||
P::Event: Borrow<E>,
|
||||
E: TagRef<P::Event>,
|
||||
{
|
||||
let label = self.window.label.clone();
|
||||
self.manager.trigger(event, Some(label), data)
|
||||
}
|
||||
|
||||
/// Evaluates JavaScript on this window.
|
||||
pub fn eval(&self, js: &str) -> crate::Result<()> {
|
||||
self.window.dispatcher.eval_script(js).map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Registers a window event listener.
|
||||
pub fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) {
|
||||
self.window.dispatcher.on_window_event(f);
|
||||
}
|
||||
|
||||
/// Registers a menu event listener.
|
||||
pub fn on_menu_event<F: Fn(MenuEvent<P::MenuId>) + Send + 'static>(&self, f: F) {
|
||||
let menu_ids = self.manager.menu_ids();
|
||||
self.window.dispatcher.on_menu_event(move |event| {
|
||||
f(MenuEvent {
|
||||
menu_item_id: menu_ids.get(&event.menu_item_id).unwrap().clone(),
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
/// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
|
||||
pub fn scale_factor(&self) -> crate::Result<f64> {
|
||||
self.window.dispatcher.scale_factor().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Returns the position of the top-left hand corner of the window's client area relative to the top-left hand corner of the desktop.
|
||||
pub fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>> {
|
||||
self.window.dispatcher.inner_position().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop.
|
||||
pub fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>> {
|
||||
self.window.dispatcher.outer_position().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Returns the physical size of the window's client area.
|
||||
///
|
||||
/// The client area is the content of the window, excluding the title bar and borders.
|
||||
pub fn inner_size(&self) -> crate::Result<PhysicalSize<u32>> {
|
||||
self.window.dispatcher.inner_size().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Returns the physical size of the entire window.
|
||||
///
|
||||
/// These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead.
|
||||
pub fn outer_size(&self) -> crate::Result<PhysicalSize<u32>> {
|
||||
self.window.dispatcher.outer_size().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Gets the window's current fullscreen state.
|
||||
pub fn is_fullscreen(&self) -> crate::Result<bool> {
|
||||
self.window.dispatcher.is_fullscreen().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Gets the window's current maximized state.
|
||||
pub fn is_maximized(&self) -> crate::Result<bool> {
|
||||
self.window.dispatcher.is_maximized().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Returns the monitor on which the window currently resides.
|
||||
///
|
||||
/// Returns None if current monitor can't be detected.
|
||||
pub fn current_monitor(&self) -> crate::Result<Option<Monitor>> {
|
||||
self.window.dispatcher.current_monitor().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Returns the primary monitor of the system.
|
||||
///
|
||||
/// Returns None if it can't identify any monitor as a primary one.
|
||||
pub fn primary_monitor(&self) -> crate::Result<Option<Monitor>> {
|
||||
self.window.dispatcher.primary_monitor().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Returns the list of all the monitors available on the system.
|
||||
pub fn available_monitors(&self) -> crate::Result<Vec<Monitor>> {
|
||||
self
|
||||
.window
|
||||
.dispatcher
|
||||
.available_monitors()
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
// Setters
|
||||
|
||||
/// 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<()> {
|
||||
self.window.dispatcher.print().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Determines if this window should be resizable.
|
||||
pub fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
|
||||
self
|
||||
.window
|
||||
.dispatcher
|
||||
.set_resizable(resizable)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Set this window's title.
|
||||
pub fn set_title(&self, title: &str) -> crate::Result<()> {
|
||||
self
|
||||
.window
|
||||
.dispatcher
|
||||
.set_title(title.to_string())
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Maximizes this window.
|
||||
pub fn maximize(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.maximize().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Un-maximizes this window.
|
||||
pub fn unmaximize(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.unmaximize().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Minimizes this window.
|
||||
pub fn minimize(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.minimize().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Un-minimizes this window.
|
||||
pub fn unminimize(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.unminimize().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Show this window.
|
||||
pub fn show(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.show().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Hide this window.
|
||||
pub fn hide(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.hide().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Closes this window.
|
||||
pub fn close(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.close().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Determines if this window should be [decorated].
|
||||
///
|
||||
/// [decorated]: https://en.wikipedia.org/wiki/Window_(computing)#Window_decoration
|
||||
pub fn set_decorations(&self, decorations: bool) -> crate::Result<()> {
|
||||
self
|
||||
.window
|
||||
.dispatcher
|
||||
.set_decorations(decorations)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Determines if this window should always be on top of other windows.
|
||||
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)
|
||||
}
|
||||
|
||||
/// Resizes this window.
|
||||
pub fn set_size<S: Into<Size>>(&self, size: S) -> crate::Result<()> {
|
||||
self
|
||||
.window
|
||||
.dispatcher
|
||||
.set_size(size.into())
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Sets this window's minimum size.
|
||||
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)
|
||||
}
|
||||
|
||||
/// Sets this window's maximum size.
|
||||
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)
|
||||
}
|
||||
|
||||
/// Sets this window's position.
|
||||
pub fn set_position<Pos: Into<Position>>(&self, position: Pos) -> crate::Result<()> {
|
||||
self
|
||||
.window
|
||||
.dispatcher
|
||||
.set_position(position.into())
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Determines if this window should be fullscreen.
|
||||
pub fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
|
||||
self
|
||||
.window
|
||||
.dispatcher
|
||||
.set_fullscreen(fullscreen)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Sets this window' icon.
|
||||
pub fn set_icon(&self, icon: Icon) -> crate::Result<()> {
|
||||
self.window.dispatcher.set_icon(icon).map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Starts dragging the window.
|
||||
pub fn start_dragging(&self) -> crate::Result<()> {
|
||||
self.window.dispatcher.start_dragging().map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) fn verify_salt(&self, salt: String) -> bool {
|
||||
self.manager.verify_salt(salt)
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,8 @@ fn main() {
|
||||
.create_window(
|
||||
"Rust".to_string(),
|
||||
tauri::WindowUrl::App("index.html".into()),
|
||||
|window_attributes, webview_attributes| {
|
||||
(window_attributes.title("Tauri - Rust"), webview_attributes)
|
||||
|window_builder, webview_attributes| {
|
||||
(window_builder.title("Tauri - Rust"), webview_attributes)
|
||||
},
|
||||
)
|
||||
.run(tauri::generate_context!())
|
||||
|
||||
Reference in New Issue
Block a user