mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-11-24 04:03:52 +03:00
refactor(core): remove window endpoints (#6947)
This commit is contained in:
parent
5a9307d11c
commit
9a79dc0858
6
.changes/ipc-scope-remove-enable-tauri-api.md
Normal file
6
.changes/ipc-scope-remove-enable-tauri-api.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"tauri": patch
|
||||
"tauri-utils": patch
|
||||
---
|
||||
|
||||
Remove `enable_tauri_api` from the IPC scope.
|
5
.changes/remove-macros-command-module.md
Normal file
5
.changes/remove-macros-command-module.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri-macros": patch
|
||||
---
|
||||
|
||||
Removed the module command macros.
|
6
.changes/remove-window.md
Normal file
6
.changes/remove-window.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"tauri": patch
|
||||
"api": patch
|
||||
---
|
||||
|
||||
Moved the `window` JS APIs to its own plugin in the plugins-workspace repository.
|
@ -2508,11 +2508,6 @@
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"enableTauriAPI": {
|
||||
"description": "Enables access to the Tauri API.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
@ -1,303 +0,0 @@
|
||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use heck::{ToLowerCamelCase, ToSnakeCase};
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
|
||||
use quote::{format_ident, quote, quote_spanned};
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
parse_quote,
|
||||
spanned::Spanned,
|
||||
Data, DeriveInput, Error, Fields, Ident, ItemFn, LitStr, Token,
|
||||
};
|
||||
|
||||
pub(crate) fn generate_command_enum(mut input: DeriveInput) -> TokenStream {
|
||||
let mut deserialize_functions = TokenStream2::new();
|
||||
let mut errors = TokenStream2::new();
|
||||
|
||||
input.attrs.push(parse_quote!(#[allow(dead_code)]));
|
||||
|
||||
match &mut input.data {
|
||||
Data::Enum(data_enum) => {
|
||||
for variant in &mut data_enum.variants {
|
||||
let mut feature: Option<Ident> = None;
|
||||
let mut error_message: Option<String> = None;
|
||||
|
||||
for attr in &variant.attrs {
|
||||
if attr.path.is_ident("cmd") {
|
||||
let r = attr
|
||||
.parse_args_with(|input: ParseStream| {
|
||||
if let Ok(f) = input.parse::<Ident>() {
|
||||
feature.replace(f);
|
||||
input.parse::<Token![,]>()?;
|
||||
let error_message_raw: LitStr = input.parse()?;
|
||||
error_message.replace(error_message_raw.value());
|
||||
}
|
||||
Ok(quote!())
|
||||
})
|
||||
.unwrap_or_else(syn::Error::into_compile_error);
|
||||
errors.extend(r);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(f) = feature {
|
||||
let error_message = if let Some(e) = error_message {
|
||||
let e = e.to_string();
|
||||
quote!(#e)
|
||||
} else {
|
||||
quote!("This API is not enabled in the allowlist.")
|
||||
};
|
||||
|
||||
let deserialize_function_name = quote::format_ident!("__{}_deserializer", variant.ident);
|
||||
deserialize_functions.extend(quote! {
|
||||
#[cfg(not(#f))]
|
||||
#[allow(non_snake_case)]
|
||||
fn #deserialize_function_name<'de, D, T>(deserializer: D) -> ::std::result::Result<T, D::Error>
|
||||
where
|
||||
D: ::serde::de::Deserializer<'de>,
|
||||
{
|
||||
::std::result::Result::Err(::serde::de::Error::custom(crate::Error::ApiNotAllowlisted(#error_message.into()).to_string()))
|
||||
}
|
||||
});
|
||||
|
||||
let deserialize_function_name = deserialize_function_name.to_string();
|
||||
|
||||
variant
|
||||
.attrs
|
||||
.push(parse_quote!(#[cfg_attr(not(#f), serde(deserialize_with = #deserialize_function_name))]));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Error::new(
|
||||
Span::call_site(),
|
||||
"`command_enum` is only implemented for enums",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into()
|
||||
}
|
||||
};
|
||||
|
||||
TokenStream::from(quote! {
|
||||
#errors
|
||||
#input
|
||||
#deserialize_functions
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn generate_run_fn(input: DeriveInput) -> TokenStream {
|
||||
let name = &input.ident;
|
||||
let data = &input.data;
|
||||
|
||||
let mut errors = TokenStream2::new();
|
||||
|
||||
let mut is_async = false;
|
||||
|
||||
let attrs = input.attrs;
|
||||
for attr in attrs {
|
||||
if attr.path.is_ident("cmd") {
|
||||
let r = attr
|
||||
.parse_args_with(|input: ParseStream| {
|
||||
if let Ok(token) = input.parse::<Ident>() {
|
||||
is_async = token == "async";
|
||||
}
|
||||
Ok(quote!())
|
||||
})
|
||||
.unwrap_or_else(syn::Error::into_compile_error);
|
||||
errors.extend(r);
|
||||
}
|
||||
}
|
||||
|
||||
let maybe_await = if is_async { quote!(.await) } else { quote!() };
|
||||
let maybe_async = if is_async { quote!(async) } else { quote!() };
|
||||
|
||||
let mut matcher;
|
||||
|
||||
match data {
|
||||
Data::Enum(data_enum) => {
|
||||
matcher = TokenStream2::new();
|
||||
|
||||
for variant in &data_enum.variants {
|
||||
let variant_name = &variant.ident;
|
||||
|
||||
let mut feature = None;
|
||||
|
||||
for attr in &variant.attrs {
|
||||
if attr.path.is_ident("cmd") {
|
||||
let r = attr
|
||||
.parse_args_with(|input: ParseStream| {
|
||||
if let Ok(f) = input.parse::<Ident>() {
|
||||
feature.replace(f);
|
||||
input.parse::<Token![,]>()?;
|
||||
let _: LitStr = input.parse()?;
|
||||
}
|
||||
Ok(quote!())
|
||||
})
|
||||
.unwrap_or_else(syn::Error::into_compile_error);
|
||||
errors.extend(r);
|
||||
}
|
||||
}
|
||||
|
||||
let maybe_feature_check = if let Some(f) = feature {
|
||||
quote!(#[cfg(#f)])
|
||||
} else {
|
||||
quote!()
|
||||
};
|
||||
|
||||
let (fields_in_variant, variables) = match &variant.fields {
|
||||
Fields::Unit => (quote_spanned! { variant.span() => }, quote!()),
|
||||
Fields::Unnamed(fields) => {
|
||||
let mut variables = TokenStream2::new();
|
||||
for i in 0..fields.unnamed.len() {
|
||||
let variable_name = format_ident!("value{}", i);
|
||||
variables.extend(quote!(#variable_name,));
|
||||
}
|
||||
(quote_spanned! { variant.span() => (#variables) }, variables)
|
||||
}
|
||||
Fields::Named(fields) => {
|
||||
let mut variables = TokenStream2::new();
|
||||
for field in &fields.named {
|
||||
let ident = field.ident.as_ref().unwrap();
|
||||
variables.extend(quote!(#ident,));
|
||||
}
|
||||
(
|
||||
quote_spanned! { variant.span() => { #variables } },
|
||||
variables,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let mut variant_execute_function_name = format_ident!(
|
||||
"{}",
|
||||
variant_name.to_string().to_snake_case().to_lowercase()
|
||||
);
|
||||
variant_execute_function_name.set_span(variant_name.span());
|
||||
|
||||
matcher.extend(quote_spanned! {
|
||||
variant.span() => #maybe_feature_check #name::#variant_name #fields_in_variant => #name::#variant_execute_function_name(context, #variables)#maybe_await.map(Into::into),
|
||||
});
|
||||
}
|
||||
|
||||
matcher.extend(quote! {
|
||||
_ => Err(crate::error::into_anyhow("API not in the allowlist (https://tauri.app/docs/api/config#tauri.allowlist)")),
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
return Error::new(
|
||||
Span::call_site(),
|
||||
"CommandModule is only implemented for enums",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into()
|
||||
}
|
||||
};
|
||||
|
||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
|
||||
let expanded = quote! {
|
||||
#errors
|
||||
impl #impl_generics #name #ty_generics #where_clause {
|
||||
pub #maybe_async fn run<R: crate::Runtime>(self, context: crate::endpoints::InvokeContext<R>) -> super::Result<crate::endpoints::InvokeResponse> {
|
||||
match self {
|
||||
#matcher
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
/// Attributes for the module enum variant handler.
|
||||
pub struct HandlerAttributes {
|
||||
allowlist: Ident,
|
||||
}
|
||||
|
||||
impl Parse for HandlerAttributes {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
Ok(Self {
|
||||
allowlist: input.parse()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub enum AllowlistCheckKind {
|
||||
Runtime,
|
||||
Serde,
|
||||
}
|
||||
|
||||
pub struct HandlerTestAttributes {
|
||||
allowlist: Ident,
|
||||
error_message: String,
|
||||
allowlist_check_kind: AllowlistCheckKind,
|
||||
}
|
||||
|
||||
impl Parse for HandlerTestAttributes {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let allowlist = input.parse()?;
|
||||
input.parse::<Token![,]>()?;
|
||||
let error_message_raw: LitStr = input.parse()?;
|
||||
let error_message = error_message_raw.value();
|
||||
let allowlist_check_kind =
|
||||
if let (Ok(_), Ok(i)) = (input.parse::<Token![,]>(), input.parse::<Ident>()) {
|
||||
if i == "runtime" {
|
||||
AllowlistCheckKind::Runtime
|
||||
} else {
|
||||
AllowlistCheckKind::Serde
|
||||
}
|
||||
} else {
|
||||
AllowlistCheckKind::Serde
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
allowlist,
|
||||
error_message,
|
||||
allowlist_check_kind,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn command_handler(attributes: HandlerAttributes, function: ItemFn) -> TokenStream2 {
|
||||
let allowlist = attributes.allowlist;
|
||||
|
||||
quote!(
|
||||
#[cfg(#allowlist)]
|
||||
#function
|
||||
)
|
||||
}
|
||||
|
||||
pub fn command_test(attributes: HandlerTestAttributes, function: ItemFn) -> TokenStream2 {
|
||||
let allowlist = attributes.allowlist;
|
||||
let error_message = attributes.error_message.as_str();
|
||||
let signature = function.sig.clone();
|
||||
|
||||
let enum_variant_name = function.sig.ident.to_string().to_lower_camel_case();
|
||||
let response = match attributes.allowlist_check_kind {
|
||||
AllowlistCheckKind::Runtime => {
|
||||
let test_name = function.sig.ident.clone();
|
||||
quote!(super::Cmd::#test_name(crate::test::mock_invoke_context()))
|
||||
}
|
||||
AllowlistCheckKind::Serde => quote! {
|
||||
serde_json::from_str::<super::Cmd>(&format!(r#"{{ "cmd": "{}", "data": null }}"#, #enum_variant_name))
|
||||
},
|
||||
};
|
||||
|
||||
quote!(
|
||||
#[cfg(#allowlist)]
|
||||
#function
|
||||
|
||||
#[cfg(not(#allowlist))]
|
||||
#[allow(unused_variables)]
|
||||
#[quickcheck_macros::quickcheck]
|
||||
#signature {
|
||||
if let Err(e) = #response {
|
||||
assert!(e.to_string().contains(#error_message));
|
||||
} else {
|
||||
panic!("unexpected response");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
@ -4,10 +4,9 @@
|
||||
|
||||
use crate::context::ContextItems;
|
||||
use proc_macro::TokenStream;
|
||||
use syn::{parse_macro_input, DeriveInput, ItemFn};
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
|
||||
mod command;
|
||||
mod command_module;
|
||||
mod mobile;
|
||||
mod runtime;
|
||||
|
||||
@ -81,40 +80,3 @@ pub fn default_runtime(attributes: TokenStream, input: TokenStream) -> TokenStre
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
runtime::default_runtime(attributes, input).into()
|
||||
}
|
||||
|
||||
/// Prepares the command module enum.
|
||||
#[doc(hidden)]
|
||||
#[proc_macro_derive(CommandModule, attributes(cmd))]
|
||||
pub fn derive_command_module(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
command_module::generate_run_fn(input)
|
||||
}
|
||||
|
||||
/// Adds a `run` method to an enum (one of the tauri endpoint modules).
|
||||
/// The `run` method takes a `tauri::endpoints::InvokeContext`
|
||||
/// and returns a `tauri::Result<tauri::endpoints::InvokeResponse>`.
|
||||
/// It matches on each enum variant and call a method with name equal to the variant name, lowercased and snake_cased,
|
||||
/// passing the context and the variant's fields as arguments.
|
||||
/// That function must also return the same `Result<InvokeResponse>`.
|
||||
#[doc(hidden)]
|
||||
#[proc_macro_attribute]
|
||||
pub fn command_enum(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
command_module::generate_command_enum(input)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[proc_macro_attribute]
|
||||
pub fn module_command_handler(attributes: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let attributes = parse_macro_input!(attributes as command_module::HandlerAttributes);
|
||||
let input = parse_macro_input!(input as ItemFn);
|
||||
command_module::command_handler(attributes, input).into()
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[proc_macro_attribute]
|
||||
pub fn module_command_test(attributes: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let attributes = parse_macro_input!(attributes as command_module::HandlerTestAttributes);
|
||||
let input = parse_macro_input!(input as ItemFn);
|
||||
command_module::command_test(attributes, input).into()
|
||||
}
|
||||
|
@ -1019,9 +1019,6 @@ pub struct RemoteDomainAccessScope {
|
||||
/// The list of plugins that are allowed in this scope.
|
||||
#[serde(default)]
|
||||
pub plugins: Vec<String>,
|
||||
/// Enables access to the Tauri API.
|
||||
#[serde(default, rename = "enableTauriAPI", alias = "enable-tauri-api")]
|
||||
pub enable_tauri_api: bool,
|
||||
}
|
||||
|
||||
/// Security configuration.
|
||||
@ -3344,7 +3341,6 @@ mod build {
|
||||
let domain = str_lit(&self.domain);
|
||||
let windows = vec_lit(&self.windows, str_lit);
|
||||
let plugins = vec_lit(&self.plugins, str_lit);
|
||||
let enable_tauri_api = self.enable_tauri_api;
|
||||
|
||||
literal_struct!(
|
||||
tokens,
|
||||
@ -3352,8 +3348,7 @@ mod build {
|
||||
scheme,
|
||||
domain,
|
||||
windows,
|
||||
plugins,
|
||||
enable_tauri_api
|
||||
plugins
|
||||
);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,116 +0,0 @@
|
||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::{
|
||||
hooks::{InvokeError, InvokeMessage, InvokeResolver},
|
||||
Config, Invoke, PackageInfo, Runtime, Window,
|
||||
};
|
||||
pub use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
mod window;
|
||||
|
||||
/// The context passed to the invoke handler.
|
||||
pub struct InvokeContext<R: Runtime> {
|
||||
pub window: Window<R>,
|
||||
pub config: Arc<Config>,
|
||||
pub package_info: PackageInfo,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<R: Runtime> Clone for InvokeContext<R> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
window: self.window.clone(),
|
||||
config: self.config.clone(),
|
||||
package_info: self.package_info.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The response for a JS `invoke` call.
|
||||
pub struct InvokeResponse {
|
||||
json: Result<JsonValue>,
|
||||
}
|
||||
|
||||
impl<T: Serialize> From<T> for InvokeResponse {
|
||||
fn from(value: T) -> Self {
|
||||
Self {
|
||||
json: serde_json::to_value(value).map_err(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "module", content = "message")]
|
||||
enum Module {
|
||||
Window(Box<window::Cmd>),
|
||||
}
|
||||
|
||||
impl Module {
|
||||
fn run<R: Runtime>(
|
||||
self,
|
||||
window: Window<R>,
|
||||
resolver: InvokeResolver<R>,
|
||||
config: Arc<Config>,
|
||||
package_info: PackageInfo,
|
||||
) {
|
||||
let context = InvokeContext {
|
||||
window,
|
||||
config,
|
||||
package_info,
|
||||
};
|
||||
match self {
|
||||
Self::Window(cmd) => resolver.respond_async(async move {
|
||||
cmd
|
||||
.run(context)
|
||||
.await
|
||||
.and_then(|r| r.json)
|
||||
.map_err(InvokeError::from_anyhow)
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn handle<R: Runtime>(
|
||||
module: String,
|
||||
invoke: Invoke<R>,
|
||||
config: Arc<Config>,
|
||||
package_info: &PackageInfo,
|
||||
) {
|
||||
let Invoke { message, resolver } = invoke;
|
||||
let InvokeMessage {
|
||||
mut payload,
|
||||
window,
|
||||
..
|
||||
} = message;
|
||||
|
||||
if let JsonValue::Object(ref mut obj) = payload {
|
||||
obj.insert("module".to_string(), JsonValue::String(module.clone()));
|
||||
}
|
||||
|
||||
match serde_json::from_value::<Module>(payload) {
|
||||
Ok(module) => module.run(window, resolver, config, package_info.clone()),
|
||||
Err(e) => {
|
||||
let message = e.to_string();
|
||||
if message.starts_with("unknown variant") {
|
||||
let mut s = message.split('`');
|
||||
s.next();
|
||||
if let Some(unknown_variant_name) = s.next() {
|
||||
if unknown_variant_name == module {
|
||||
return resolver.reject(format!(
|
||||
"The `{module}` module is not enabled. You must enable one of its APIs in the allowlist.",
|
||||
));
|
||||
} else if module == "Window" {
|
||||
return resolver.reject(window::into_allowlist_error(unknown_variant_name).to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
resolver.reject(message);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,364 +0,0 @@
|
||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use super::{InvokeContext, InvokeResponse};
|
||||
#[cfg(window_create)]
|
||||
use crate::runtime::{webview::WindowBuilder, Dispatch};
|
||||
use crate::{
|
||||
runtime::{
|
||||
window::dpi::{Position, Size},
|
||||
UserAttentionType,
|
||||
},
|
||||
utils::config::WindowConfig,
|
||||
CursorIcon, Icon, Manager, Runtime,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use tauri_macros::{command_enum, module_command_handler, CommandModule};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum IconDto {
|
||||
#[cfg(any(feature = "icon-png", feature = "icon-ico"))]
|
||||
File(std::path::PathBuf),
|
||||
#[cfg(any(feature = "icon-png", feature = "icon-ico"))]
|
||||
Raw(Vec<u8>),
|
||||
Rgba {
|
||||
rgba: Vec<u8>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<IconDto> for Icon {
|
||||
fn from(icon: IconDto) -> Self {
|
||||
match icon {
|
||||
#[cfg(any(feature = "icon-png", feature = "icon-ico"))]
|
||||
IconDto::File(path) => Self::File(path),
|
||||
#[cfg(any(feature = "icon-png", feature = "icon-ico"))]
|
||||
IconDto::Raw(raw) => Self::Raw(raw),
|
||||
IconDto::Rgba {
|
||||
rgba,
|
||||
width,
|
||||
height,
|
||||
} => Self::Rgba {
|
||||
rgba,
|
||||
width,
|
||||
height,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Window management API descriptor.
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "type", content = "payload", rename_all = "camelCase")]
|
||||
pub enum WindowManagerCmd {
|
||||
// Getters
|
||||
ScaleFactor,
|
||||
InnerPosition,
|
||||
OuterPosition,
|
||||
InnerSize,
|
||||
OuterSize,
|
||||
IsFullscreen,
|
||||
IsMinimized,
|
||||
IsMaximized,
|
||||
IsDecorated,
|
||||
IsResizable,
|
||||
IsVisible,
|
||||
Title,
|
||||
CurrentMonitor,
|
||||
PrimaryMonitor,
|
||||
AvailableMonitors,
|
||||
Theme,
|
||||
// Setters
|
||||
#[cfg(window_center)]
|
||||
Center,
|
||||
#[cfg(window_request_user_attention)]
|
||||
RequestUserAttention(Option<UserAttentionType>),
|
||||
#[cfg(window_set_resizable)]
|
||||
SetResizable(bool),
|
||||
#[cfg(window_set_title)]
|
||||
SetTitle(String),
|
||||
#[cfg(window_maximize)]
|
||||
Maximize,
|
||||
#[cfg(window_unmaximize)]
|
||||
Unmaximize,
|
||||
#[cfg(all(window_maximize, window_unmaximize))]
|
||||
ToggleMaximize,
|
||||
#[cfg(window_minimize)]
|
||||
Minimize,
|
||||
#[cfg(window_unminimize)]
|
||||
Unminimize,
|
||||
#[cfg(window_show)]
|
||||
Show,
|
||||
#[cfg(window_hide)]
|
||||
Hide,
|
||||
#[cfg(window_close)]
|
||||
Close,
|
||||
#[cfg(window_set_decorations)]
|
||||
SetDecorations(bool),
|
||||
#[cfg(window_set_shadow)]
|
||||
SetShadow(bool),
|
||||
#[cfg(window_set_always_on_top)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SetAlwaysOnTop(bool),
|
||||
#[cfg(window_set_content_protected)]
|
||||
SetContentProtected(bool),
|
||||
#[cfg(window_set_size)]
|
||||
SetSize(Size),
|
||||
#[cfg(window_set_min_size)]
|
||||
SetMinSize(Option<Size>),
|
||||
#[cfg(window_set_max_size)]
|
||||
SetMaxSize(Option<Size>),
|
||||
#[cfg(window_set_position)]
|
||||
SetPosition(Position),
|
||||
#[cfg(window_set_fullscreen)]
|
||||
SetFullscreen(bool),
|
||||
#[cfg(window_set_focus)]
|
||||
SetFocus,
|
||||
#[cfg(window_set_icon)]
|
||||
SetIcon {
|
||||
icon: IconDto,
|
||||
},
|
||||
#[cfg(window_set_skip_taskbar)]
|
||||
SetSkipTaskbar(bool),
|
||||
#[cfg(window_set_cursor_grab)]
|
||||
SetCursorGrab(bool),
|
||||
#[cfg(window_set_cursor_visible)]
|
||||
SetCursorVisible(bool),
|
||||
#[cfg(window_set_cursor_icon)]
|
||||
SetCursorIcon(CursorIcon),
|
||||
#[cfg(window_set_cursor_position)]
|
||||
SetCursorPosition(Position),
|
||||
#[cfg(window_set_ignore_cursor_events)]
|
||||
SetIgnoreCursorEvents(bool),
|
||||
#[cfg(window_start_dragging)]
|
||||
StartDragging,
|
||||
#[cfg(window_print)]
|
||||
Print,
|
||||
// internals
|
||||
#[cfg(all(window_maximize, window_unmaximize))]
|
||||
#[serde(rename = "__toggleMaximize")]
|
||||
InternalToggleMaximize,
|
||||
#[cfg(any(debug_assertions, feature = "devtools"))]
|
||||
#[serde(rename = "__toggleDevtools")]
|
||||
InternalToggleDevtools,
|
||||
}
|
||||
|
||||
pub fn into_allowlist_error(variant: &str) -> crate::Error {
|
||||
match variant {
|
||||
"center" => crate::Error::ApiNotAllowlisted("window > center".to_string()),
|
||||
"requestUserAttention" => {
|
||||
crate::Error::ApiNotAllowlisted("window > requestUserAttention".to_string())
|
||||
}
|
||||
"setResizable" => crate::Error::ApiNotAllowlisted("window > setResizable".to_string()),
|
||||
"setTitle" => crate::Error::ApiNotAllowlisted("window > setTitle".to_string()),
|
||||
"maximize" => crate::Error::ApiNotAllowlisted("window > maximize".to_string()),
|
||||
"unmaximize" => crate::Error::ApiNotAllowlisted("window > unmaximize".to_string()),
|
||||
"toggleMaximize" => {
|
||||
crate::Error::ApiNotAllowlisted("window > maximize and window > unmaximize".to_string())
|
||||
}
|
||||
"minimize" => crate::Error::ApiNotAllowlisted("window > minimize".to_string()),
|
||||
"unminimize" => crate::Error::ApiNotAllowlisted("window > unminimize".to_string()),
|
||||
"show" => crate::Error::ApiNotAllowlisted("window > show".to_string()),
|
||||
"hide" => crate::Error::ApiNotAllowlisted("window > hide".to_string()),
|
||||
"close" => crate::Error::ApiNotAllowlisted("window > close".to_string()),
|
||||
"setDecorations" => crate::Error::ApiNotAllowlisted("window > setDecorations".to_string()),
|
||||
"setShadow" => crate::Error::ApiNotAllowlisted("window > setShadow".to_string()),
|
||||
"setAlwaysOnTop" => crate::Error::ApiNotAllowlisted("window > setAlwaysOnTop".to_string()),
|
||||
"setContentProtected" => {
|
||||
crate::Error::ApiNotAllowlisted("window > setContentProtected".to_string())
|
||||
}
|
||||
"setSize" => crate::Error::ApiNotAllowlisted("window > setSize".to_string()),
|
||||
"setMinSize" => crate::Error::ApiNotAllowlisted("window > setMinSize".to_string()),
|
||||
"setMaxSize" => crate::Error::ApiNotAllowlisted("window > setMaxSize".to_string()),
|
||||
"setPosition" => crate::Error::ApiNotAllowlisted("window > setPosition".to_string()),
|
||||
"setFullscreen" => crate::Error::ApiNotAllowlisted("window > setFullscreen".to_string()),
|
||||
"setIcon" => crate::Error::ApiNotAllowlisted("window > setIcon".to_string()),
|
||||
"setSkipTaskbar" => crate::Error::ApiNotAllowlisted("window > setSkipTaskbar".to_string()),
|
||||
"setCursorGrab" => crate::Error::ApiNotAllowlisted("window > setCursorGrab".to_string()),
|
||||
"setCursorVisible" => crate::Error::ApiNotAllowlisted("window > setCursorVisible".to_string()),
|
||||
"setCursorIcon" => crate::Error::ApiNotAllowlisted("window > setCursorIcon".to_string()),
|
||||
"setCursorPosition" => {
|
||||
crate::Error::ApiNotAllowlisted("window > setCursorPosition".to_string())
|
||||
}
|
||||
"setIgnoreCursorEvents" => {
|
||||
crate::Error::ApiNotAllowlisted("window > setIgnoreCursorEvents".to_string())
|
||||
}
|
||||
"startDragging" => crate::Error::ApiNotAllowlisted("window > startDragging".to_string()),
|
||||
"print" => crate::Error::ApiNotAllowlisted("window > print".to_string()),
|
||||
"__toggleMaximize" => {
|
||||
crate::Error::ApiNotAllowlisted("window > maximize and window > unmaximize".to_string())
|
||||
}
|
||||
"__toggleDevtools" => crate::Error::ApiNotAllowlisted("devtools".to_string()),
|
||||
_ => crate::Error::ApiNotAllowlisted("window".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
/// The API descriptor.
|
||||
#[command_enum]
|
||||
#[derive(Deserialize, CommandModule)]
|
||||
#[cmd(async)]
|
||||
#[serde(tag = "cmd", content = "data", rename_all = "camelCase")]
|
||||
pub enum Cmd {
|
||||
#[cmd(window_create, "window > create")]
|
||||
CreateWebview { options: Box<WindowConfig> },
|
||||
Manage {
|
||||
label: Option<String>,
|
||||
cmd: WindowManagerCmd,
|
||||
},
|
||||
}
|
||||
|
||||
impl Cmd {
|
||||
#[module_command_handler(window_create)]
|
||||
async fn create_webview<R: Runtime>(
|
||||
context: InvokeContext<R>,
|
||||
mut options: Box<WindowConfig>,
|
||||
) -> super::Result<()> {
|
||||
options.additional_browser_args = None;
|
||||
crate::window::WindowBuilder::from_config(&context.window, *options)
|
||||
.build()
|
||||
.map_err(crate::error::into_anyhow)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn manage<R: Runtime>(
|
||||
context: InvokeContext<R>,
|
||||
label: Option<String>,
|
||||
cmd: WindowManagerCmd,
|
||||
) -> super::Result<InvokeResponse> {
|
||||
Self::_manage(context, label, cmd)
|
||||
.await
|
||||
.map_err(crate::error::into_anyhow)
|
||||
}
|
||||
|
||||
async fn _manage<R: Runtime>(
|
||||
context: InvokeContext<R>,
|
||||
label: Option<String>,
|
||||
cmd: WindowManagerCmd,
|
||||
) -> crate::Result<InvokeResponse> {
|
||||
let window = match label {
|
||||
Some(l) if !l.is_empty() => context
|
||||
.window
|
||||
.get_window(&l)
|
||||
.ok_or(crate::Error::WebviewNotFound)?,
|
||||
_ => context.window,
|
||||
};
|
||||
match cmd {
|
||||
// Getters
|
||||
WindowManagerCmd::ScaleFactor => return Ok(window.scale_factor()?.into()),
|
||||
WindowManagerCmd::InnerPosition => return Ok(window.inner_position()?.into()),
|
||||
WindowManagerCmd::OuterPosition => return Ok(window.outer_position()?.into()),
|
||||
WindowManagerCmd::InnerSize => return Ok(window.inner_size()?.into()),
|
||||
WindowManagerCmd::OuterSize => return Ok(window.outer_size()?.into()),
|
||||
WindowManagerCmd::IsFullscreen => return Ok(window.is_fullscreen()?.into()),
|
||||
WindowManagerCmd::IsMinimized => return Ok(window.is_minimized()?.into()),
|
||||
WindowManagerCmd::IsMaximized => return Ok(window.is_maximized()?.into()),
|
||||
WindowManagerCmd::IsDecorated => return Ok(window.is_decorated()?.into()),
|
||||
WindowManagerCmd::IsResizable => return Ok(window.is_resizable()?.into()),
|
||||
WindowManagerCmd::IsVisible => return Ok(window.is_visible()?.into()),
|
||||
WindowManagerCmd::Title => return Ok(window.title()?.into()),
|
||||
WindowManagerCmd::CurrentMonitor => return Ok(window.current_monitor()?.into()),
|
||||
WindowManagerCmd::PrimaryMonitor => return Ok(window.primary_monitor()?.into()),
|
||||
WindowManagerCmd::AvailableMonitors => return Ok(window.available_monitors()?.into()),
|
||||
WindowManagerCmd::Theme => return Ok(window.theme()?.into()),
|
||||
// Setters
|
||||
#[cfg(all(desktop, window_center))]
|
||||
WindowManagerCmd::Center => window.center()?,
|
||||
#[cfg(all(desktop, window_request_user_attention))]
|
||||
WindowManagerCmd::RequestUserAttention(request_type) => {
|
||||
window.request_user_attention(request_type)?
|
||||
}
|
||||
#[cfg(all(desktop, window_set_resizable))]
|
||||
WindowManagerCmd::SetResizable(resizable) => window.set_resizable(resizable)?,
|
||||
#[cfg(all(desktop, window_set_title))]
|
||||
WindowManagerCmd::SetTitle(title) => window.set_title(&title)?,
|
||||
#[cfg(all(desktop, window_maximize))]
|
||||
WindowManagerCmd::Maximize => window.maximize()?,
|
||||
#[cfg(all(desktop, window_unmaximize))]
|
||||
WindowManagerCmd::Unmaximize => window.unmaximize()?,
|
||||
#[cfg(all(desktop, window_maximize, window_unmaximize))]
|
||||
WindowManagerCmd::ToggleMaximize => match window.is_maximized()? {
|
||||
true => window.unmaximize()?,
|
||||
false => window.maximize()?,
|
||||
},
|
||||
#[cfg(all(desktop, window_minimize))]
|
||||
WindowManagerCmd::Minimize => window.minimize()?,
|
||||
#[cfg(all(desktop, window_unminimize))]
|
||||
WindowManagerCmd::Unminimize => window.unminimize()?,
|
||||
#[cfg(all(desktop, window_show))]
|
||||
WindowManagerCmd::Show => window.show()?,
|
||||
#[cfg(all(desktop, window_hide))]
|
||||
WindowManagerCmd::Hide => window.hide()?,
|
||||
#[cfg(all(desktop, window_close))]
|
||||
WindowManagerCmd::Close => window.close()?,
|
||||
#[cfg(all(desktop, window_set_decorations))]
|
||||
WindowManagerCmd::SetDecorations(decorations) => window.set_decorations(decorations)?,
|
||||
#[cfg(all(desktop, window_set_shadow))]
|
||||
WindowManagerCmd::SetShadow(enable) => window.set_shadow(enable)?,
|
||||
#[cfg(all(desktop, window_set_always_on_top))]
|
||||
WindowManagerCmd::SetAlwaysOnTop(always_on_top) => window.set_always_on_top(always_on_top)?,
|
||||
#[cfg(all(desktop, window_set_content_protected))]
|
||||
WindowManagerCmd::SetContentProtected(protected) => {
|
||||
window.set_content_protected(protected)?
|
||||
}
|
||||
#[cfg(all(desktop, window_set_size))]
|
||||
WindowManagerCmd::SetSize(size) => window.set_size(size)?,
|
||||
#[cfg(all(desktop, window_set_min_size))]
|
||||
WindowManagerCmd::SetMinSize(size) => window.set_min_size(size)?,
|
||||
#[cfg(all(desktop, window_set_max_size))]
|
||||
WindowManagerCmd::SetMaxSize(size) => window.set_max_size(size)?,
|
||||
#[cfg(all(desktop, window_set_position))]
|
||||
WindowManagerCmd::SetPosition(position) => window.set_position(position)?,
|
||||
#[cfg(all(desktop, window_set_fullscreen))]
|
||||
WindowManagerCmd::SetFullscreen(fullscreen) => window.set_fullscreen(fullscreen)?,
|
||||
#[cfg(all(desktop, window_set_focus))]
|
||||
WindowManagerCmd::SetFocus => window.set_focus()?,
|
||||
#[cfg(all(desktop, window_set_icon))]
|
||||
WindowManagerCmd::SetIcon { icon } => window.set_icon(icon.into())?,
|
||||
#[cfg(all(desktop, window_set_skip_taskbar))]
|
||||
WindowManagerCmd::SetSkipTaskbar(skip) => window.set_skip_taskbar(skip)?,
|
||||
#[cfg(all(desktop, window_set_cursor_grab))]
|
||||
WindowManagerCmd::SetCursorGrab(grab) => window.set_cursor_grab(grab)?,
|
||||
#[cfg(all(desktop, window_set_cursor_visible))]
|
||||
WindowManagerCmd::SetCursorVisible(visible) => window.set_cursor_visible(visible)?,
|
||||
#[cfg(all(desktop, window_set_cursor_icon))]
|
||||
WindowManagerCmd::SetCursorIcon(icon) => window.set_cursor_icon(icon)?,
|
||||
#[cfg(all(desktop, window_set_cursor_position))]
|
||||
WindowManagerCmd::SetCursorPosition(position) => window.set_cursor_position(position)?,
|
||||
#[cfg(all(desktop, window_set_ignore_cursor_events))]
|
||||
WindowManagerCmd::SetIgnoreCursorEvents(ignore_cursor) => {
|
||||
window.set_ignore_cursor_events(ignore_cursor)?
|
||||
}
|
||||
#[cfg(all(desktop, window_start_dragging))]
|
||||
WindowManagerCmd::StartDragging => window.start_dragging()?,
|
||||
#[cfg(all(desktop, window_print))]
|
||||
WindowManagerCmd::Print => window.print()?,
|
||||
// internals
|
||||
#[cfg(all(desktop, window_maximize, window_unmaximize))]
|
||||
WindowManagerCmd::InternalToggleMaximize => {
|
||||
if window.is_resizable()? {
|
||||
match window.is_maximized()? {
|
||||
true => window.unmaximize()?,
|
||||
false => window.maximize()?,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(all(desktop, any(debug_assertions, feature = "devtools")))]
|
||||
WindowManagerCmd::InternalToggleDevtools => {
|
||||
if window.is_devtools_open() {
|
||||
window.close_devtools();
|
||||
} else {
|
||||
window.open_devtools();
|
||||
}
|
||||
}
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => (),
|
||||
}
|
||||
#[allow(unreachable_code)]
|
||||
Ok(().into())
|
||||
}
|
||||
}
|
@ -51,10 +51,7 @@ pub enum Error {
|
||||
AssetNotFound(String),
|
||||
/// Failed to serialize/deserialize.
|
||||
#[error("JSON error: {0}")]
|
||||
Json(serde_json::Error),
|
||||
/// Unknown API type.
|
||||
#[error("unknown API: {0:?}")]
|
||||
UnknownApi(Option<serde_json::Error>),
|
||||
Json(#[from] serde_json::Error),
|
||||
/// Failed to execute tauri API.
|
||||
#[error("failed to execute API: {0}")]
|
||||
FailedToExecuteApi(#[from] crate::api::Error),
|
||||
@ -105,24 +102,3 @@ pub enum Error {
|
||||
#[error("jni error: {0}")]
|
||||
Jni(#[from] jni::errors::Error),
|
||||
}
|
||||
|
||||
pub(crate) fn into_anyhow<T: std::fmt::Display>(err: T) -> anyhow::Error {
|
||||
anyhow::anyhow!(err.to_string())
|
||||
}
|
||||
|
||||
impl Error {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn into_anyhow(self) -> anyhow::Error {
|
||||
anyhow::anyhow!(self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serde_json::Error> for Error {
|
||||
fn from(error: serde_json::Error) -> Self {
|
||||
if error.to_string().contains("unknown variant") {
|
||||
Self::UnknownApi(Some(error))
|
||||
} else {
|
||||
Self::Json(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,9 +61,6 @@ impl PageLoadPayload {
|
||||
pub struct InvokePayload {
|
||||
/// The invoke command.
|
||||
pub cmd: String,
|
||||
#[serde(rename = "__tauriModule")]
|
||||
#[doc(hidden)]
|
||||
pub tauri_module: Option<String>,
|
||||
/// The success callback.
|
||||
pub callback: CallbackFn,
|
||||
/// The error callback.
|
||||
|
@ -179,8 +179,6 @@ pub mod api;
|
||||
pub(crate) mod app;
|
||||
pub mod async_runtime;
|
||||
pub mod command;
|
||||
/// The Tauri API endpoints.
|
||||
mod endpoints;
|
||||
mod error;
|
||||
mod event;
|
||||
mod hooks;
|
||||
|
@ -14,7 +14,6 @@ pub struct RemoteDomainAccessScope {
|
||||
domain: String,
|
||||
windows: Vec<String>,
|
||||
plugins: Vec<String>,
|
||||
enable_tauri_api: bool,
|
||||
}
|
||||
|
||||
impl RemoteDomainAccessScope {
|
||||
@ -25,7 +24,6 @@ impl RemoteDomainAccessScope {
|
||||
domain: domain.into(),
|
||||
windows: Vec::new(),
|
||||
plugins: Vec::new(),
|
||||
enable_tauri_api: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,9 +45,13 @@ impl RemoteDomainAccessScope {
|
||||
self
|
||||
}
|
||||
|
||||
/// Enables access to the Tauri API.
|
||||
pub fn enable_tauri_api(mut self) -> Self {
|
||||
self.enable_tauri_api = true;
|
||||
/// Adds the given list of plugins to the allowed plugin list.
|
||||
pub fn add_plugins<I, S>(mut self, plugins: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = S>,
|
||||
S: Into<String>,
|
||||
{
|
||||
self.plugins.extend(plugins.into_iter().map(Into::into));
|
||||
self
|
||||
}
|
||||
|
||||
@ -67,11 +69,6 @@ impl RemoteDomainAccessScope {
|
||||
pub fn plugins(&self) -> &Vec<String> {
|
||||
&self.plugins
|
||||
}
|
||||
|
||||
/// Whether this scope enables Tauri API access or not.
|
||||
pub fn enables_tauri_api(&self) -> bool {
|
||||
self.enable_tauri_api
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RemoteAccessError {
|
||||
@ -99,7 +96,6 @@ impl Scope {
|
||||
domain: s.domain,
|
||||
windows: s.windows,
|
||||
plugins: s.plugins,
|
||||
enable_tauri_api: s.enable_tauri_api,
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -119,7 +115,7 @@ impl Scope {
|
||||
/// app.ipc_scope().configure_remote_access(
|
||||
/// RemoteDomainAccessScope::new("tauri.app")
|
||||
/// .add_window("main")
|
||||
/// .enable_tauri_api()
|
||||
/// .add_plugins(["path", "event"])
|
||||
/// );
|
||||
/// Ok(())
|
||||
/// });
|
||||
@ -238,7 +234,6 @@ mod tests {
|
||||
|
||||
InvokePayload {
|
||||
cmd: "plugin:path|is_absolute".into(),
|
||||
tauri_module: None,
|
||||
callback,
|
||||
error,
|
||||
inner: serde_json::Value::Object(payload),
|
||||
@ -251,7 +246,6 @@ mod tests {
|
||||
|
||||
InvokePayload {
|
||||
cmd: format!("plugin:{PLUGIN_NAME}|doSomething"),
|
||||
tauri_module: None,
|
||||
callback,
|
||||
error,
|
||||
inner: Default::default(),
|
||||
@ -262,8 +256,7 @@ mod tests {
|
||||
fn scope_not_defined() {
|
||||
let (_app, window) = test_context(vec![RemoteDomainAccessScope::new("app.tauri.app")
|
||||
.add_window("other")
|
||||
.add_plugin("path")
|
||||
.enable_tauri_api()]);
|
||||
.add_plugin("path")]);
|
||||
|
||||
window.navigate("https://tauri.app".parse().unwrap());
|
||||
assert_ipc_response::<()>(
|
||||
@ -280,8 +273,7 @@ mod tests {
|
||||
fn scope_not_defined_for_window() {
|
||||
let (_app, window) = test_context(vec![RemoteDomainAccessScope::new("tauri.app")
|
||||
.add_window("second")
|
||||
.add_plugin("path")
|
||||
.enable_tauri_api()]);
|
||||
.add_plugin("path")]);
|
||||
|
||||
window.navigate("https://tauri.app".parse().unwrap());
|
||||
assert_ipc_response::<()>(
|
||||
@ -295,8 +287,7 @@ mod tests {
|
||||
fn scope_not_defined_for_url() {
|
||||
let (_app, window) = test_context(vec![RemoteDomainAccessScope::new("github.com")
|
||||
.add_window("main")
|
||||
.add_plugin("path")
|
||||
.enable_tauri_api()]);
|
||||
.add_plugin("path")]);
|
||||
|
||||
window.navigate("https://tauri.app".parse().unwrap());
|
||||
assert_ipc_response::<()>(
|
||||
@ -313,12 +304,10 @@ mod tests {
|
||||
let (_app, mut window) = test_context(vec![
|
||||
RemoteDomainAccessScope::new("tauri.app")
|
||||
.add_window("main")
|
||||
.add_plugin("path")
|
||||
.enable_tauri_api(),
|
||||
.add_plugin("path"),
|
||||
RemoteDomainAccessScope::new("sub.tauri.app")
|
||||
.add_window("main")
|
||||
.add_plugin("path")
|
||||
.enable_tauri_api(),
|
||||
.add_plugin("path"),
|
||||
]);
|
||||
|
||||
window.navigate("https://tauri.app".parse().unwrap());
|
||||
@ -352,8 +341,7 @@ mod tests {
|
||||
fn subpath_is_allowed() {
|
||||
let (_app, window) = test_context(vec![RemoteDomainAccessScope::new("tauri.app")
|
||||
.add_window("main")
|
||||
.add_plugin("path")
|
||||
.enable_tauri_api()]);
|
||||
.add_plugin("path")]);
|
||||
|
||||
window.navigate("https://tauri.app/inner/path".parse().unwrap());
|
||||
assert_ipc_response(&window, path_is_absolute_payload(), Ok(true));
|
||||
|
@ -9,7 +9,7 @@ pub use mock_runtime::*;
|
||||
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
|
||||
use crate::{Manager, Pattern, WindowBuilder};
|
||||
use crate::{Pattern, WindowBuilder};
|
||||
use tauri_utils::{
|
||||
assets::{AssetKey, Assets, CspHash},
|
||||
config::{Config, PatternKind, TauriConfig, WindowUrl},
|
||||
@ -81,13 +81,3 @@ pub fn mock_app() -> crate::App<MockRuntime> {
|
||||
|
||||
app
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn mock_invoke_context() -> crate::endpoints::InvokeContext<MockRuntime> {
|
||||
let app = mock_app();
|
||||
crate::endpoints::InvokeContext {
|
||||
window: app.get_window("main").unwrap(),
|
||||
config: app.config(),
|
||||
package_info: app.package_info().clone(),
|
||||
}
|
||||
}
|
||||
|
@ -1516,18 +1516,7 @@ impl<R: Runtime> Window<R> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(module) = &payload.tauri_module {
|
||||
if !is_local && scope.map(|s| !s.enables_tauri_api()).unwrap_or_default() {
|
||||
invoke.resolver.reject(IPC_SCOPE_DOES_NOT_ALLOW);
|
||||
return Ok(());
|
||||
}
|
||||
crate::endpoints::handle(
|
||||
module.to_string(),
|
||||
invoke,
|
||||
manager.config(),
|
||||
manager.package_info(),
|
||||
);
|
||||
} else if payload.cmd.starts_with("plugin:") {
|
||||
if payload.cmd.starts_with("plugin:") {
|
||||
if !is_local {
|
||||
let command = invoke.message.command.replace("plugin:", "");
|
||||
let plugin_name = command.split('|').next().unwrap().to_string();
|
||||
|
2
examples/api/dist/assets/index.css
vendored
2
examples/api/dist/assets/index.css
vendored
File diff suppressed because one or more lines are too long
41
examples/api/dist/assets/index.js
vendored
41
examples/api/dist/assets/index.js
vendored
File diff suppressed because one or more lines are too long
@ -52,11 +52,6 @@ pub fn run() {
|
||||
.content_protected(true);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
window_builder = window_builder.transparent(true).decorations(false);
|
||||
}
|
||||
|
||||
let window = window_builder.build().unwrap();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
|
@ -1,19 +1,11 @@
|
||||
<script>
|
||||
import { writable } from 'svelte/store'
|
||||
import { appWindow, getCurrent } from '@tauri-apps/api/window'
|
||||
|
||||
import Welcome from './views/Welcome.svelte'
|
||||
import Cli from './views/Cli.svelte'
|
||||
import Communication from './views/Communication.svelte'
|
||||
import Window from './views/Window.svelte'
|
||||
import WebRTC from './views/WebRTC.svelte'
|
||||
|
||||
import { onMount } from 'svelte'
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
|
||||
appWindow.onFileDropEvent((event) => {
|
||||
onMessage(`File drop: ${JSON.stringify(event.payload)}`)
|
||||
})
|
||||
|
||||
const userAgent = navigator.userAgent.toLowerCase()
|
||||
const isMobile = userAgent.includes('android') || userAgent.includes('iphone')
|
||||
@ -29,16 +21,6 @@
|
||||
component: Communication,
|
||||
icon: 'i-codicon-radio-tower'
|
||||
},
|
||||
!isMobile && {
|
||||
label: 'CLI',
|
||||
component: Cli,
|
||||
icon: 'i-codicon-terminal'
|
||||
},
|
||||
!isMobile && {
|
||||
label: 'Window',
|
||||
component: Window,
|
||||
icon: 'i-codicon-window'
|
||||
},
|
||||
{
|
||||
label: 'WebRTC',
|
||||
component: WebRTC,
|
||||
@ -51,25 +33,6 @@
|
||||
selected = view
|
||||
}
|
||||
|
||||
// Window controls
|
||||
let isWindowMaximized
|
||||
onMount(async () => {
|
||||
const window = getCurrent()
|
||||
isWindowMaximized = await window.isMaximized()
|
||||
listen('tauri://resize', async () => {
|
||||
isWindowMaximized = await window.isMaximized()
|
||||
})
|
||||
})
|
||||
|
||||
function minimize() {
|
||||
getCurrent().minimize()
|
||||
}
|
||||
|
||||
async function toggleMaximize() {
|
||||
const window = getCurrent()
|
||||
;(await window.isMaximized()) ? window.unmaximize() : window.maximize()
|
||||
}
|
||||
|
||||
// dark/light
|
||||
let isDark
|
||||
onMount(() => {
|
||||
@ -141,8 +104,6 @@
|
||||
document.addEventListener('mousemove', moveHandler)
|
||||
}
|
||||
|
||||
const isWindows = navigator.appVersion.includes('Win')
|
||||
|
||||
// mobile
|
||||
let isSideBarOpen = false
|
||||
let sidebar
|
||||
@ -211,52 +172,6 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- custom titlebar for Windows -->
|
||||
{#if isWindows}
|
||||
<div
|
||||
class="w-screen select-none h-8 pl-2 flex justify-between items-center absolute text-primaryText dark:text-darkPrimaryText"
|
||||
data-tauri-drag-region
|
||||
>
|
||||
<span class="lt-sm:pl-10 text-darkPrimaryText">Tauri API Validation</span>
|
||||
<span
|
||||
class="
|
||||
h-100%
|
||||
children:h-100% children:w-12 children:inline-flex
|
||||
children:items-center children:justify-center"
|
||||
>
|
||||
<span
|
||||
title={isDark ? 'Switch to Light mode' : 'Switch to Dark mode'}
|
||||
class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
|
||||
on:click={toggleDark}
|
||||
>
|
||||
{#if isDark}
|
||||
<div class="i-ph-sun" />
|
||||
{:else}
|
||||
<div class="i-ph-moon" />
|
||||
{/if}
|
||||
</span>
|
||||
<span
|
||||
title="Minimize"
|
||||
class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
|
||||
on:click={minimize}
|
||||
>
|
||||
<div class="i-codicon-chrome-minimize" />
|
||||
</span>
|
||||
<span
|
||||
title={isWindowMaximized ? 'Restore' : 'Maximize'}
|
||||
class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
|
||||
on:click={toggleMaximize}
|
||||
>
|
||||
{#if isWindowMaximized}
|
||||
<div class="i-codicon-chrome-restore" />
|
||||
{:else}
|
||||
<div class="i-codicon-chrome-maximize" />
|
||||
{/if}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Sidebar toggle, only visible on small screens -->
|
||||
<div
|
||||
id="sidebarToggle"
|
||||
@ -283,20 +198,18 @@
|
||||
src="tauri_logo.png"
|
||||
alt="Tauri logo"
|
||||
/>
|
||||
{#if !isWindows}
|
||||
<a href="##" class="nv justify-between h-8" on:click={toggleDark}>
|
||||
{#if isDark}
|
||||
Switch to Light mode
|
||||
<div class="i-ph-sun" />
|
||||
{:else}
|
||||
Switch to Dark mode
|
||||
<div class="i-ph-moon" />
|
||||
{/if}
|
||||
</a>
|
||||
<br />
|
||||
<div class="bg-white/5 h-2px" />
|
||||
<br />
|
||||
{/if}
|
||||
<a href="##" class="nv justify-between h-8" on:click={toggleDark}>
|
||||
{#if isDark}
|
||||
Switch to Light mode
|
||||
<div class="i-ph-sun" />
|
||||
{:else}
|
||||
Switch to Dark mode
|
||||
<div class="i-ph-moon" />
|
||||
{/if}
|
||||
</a>
|
||||
<br />
|
||||
<div class="bg-white/5 h-2px" />
|
||||
<br />
|
||||
|
||||
<a
|
||||
class="nv justify-between h-8"
|
||||
|
@ -1,29 +0,0 @@
|
||||
<script>
|
||||
import { invoke } from '@tauri-apps/api/tauri'
|
||||
|
||||
export let onMessage
|
||||
|
||||
function cliMatches() {
|
||||
invoke('plugin:cli|cli_matches').then(onMessage).catch(onMessage)
|
||||
}
|
||||
</script>
|
||||
|
||||
<p>
|
||||
This binary can be run from the terminal and takes the following arguments:
|
||||
<code class="code-block flex flex-wrap my-2">
|
||||
<pre>
|
||||
--config <PATH>
|
||||
--theme <light|dark|system>
|
||||
--verbose</pre>
|
||||
</code>
|
||||
Additionally, it has a <code>update --background</code> subcommand.
|
||||
</p>
|
||||
<br />
|
||||
<div class="note">
|
||||
Note that the arguments are only parsed, not implemented.
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
<button class="btn" id="cli-matches" on:click={cliMatches}>
|
||||
Get matches
|
||||
</button>
|
@ -1,438 +0,0 @@
|
||||
<script>
|
||||
import {
|
||||
appWindow,
|
||||
WebviewWindow,
|
||||
LogicalSize,
|
||||
UserAttentionType,
|
||||
PhysicalSize,
|
||||
PhysicalPosition
|
||||
} from '@tauri-apps/api/window'
|
||||
|
||||
let selectedWindow = appWindow.label
|
||||
const windowMap = {
|
||||
[appWindow.label]: appWindow
|
||||
}
|
||||
|
||||
const cursorIconOptions = [
|
||||
'default',
|
||||
'crosshair',
|
||||
'hand',
|
||||
'arrow',
|
||||
'move',
|
||||
'text',
|
||||
'wait',
|
||||
'help',
|
||||
'progress',
|
||||
// something cannot be done
|
||||
'notAllowed',
|
||||
'contextMenu',
|
||||
'cell',
|
||||
'verticalText',
|
||||
'alias',
|
||||
'copy',
|
||||
'noDrop',
|
||||
// something can be grabbed
|
||||
'grab',
|
||||
/// something is grabbed
|
||||
'grabbing',
|
||||
'allScroll',
|
||||
'zoomIn',
|
||||
'zoomOut',
|
||||
// edge is to be moved
|
||||
'eResize',
|
||||
'nResize',
|
||||
'neResize',
|
||||
'nwResize',
|
||||
'sResize',
|
||||
'seResize',
|
||||
'swResize',
|
||||
'wResize',
|
||||
'ewResize',
|
||||
'nsResize',
|
||||
'neswResize',
|
||||
'nwseResize',
|
||||
'colResize',
|
||||
'rowResize'
|
||||
]
|
||||
|
||||
export let onMessage
|
||||
|
||||
let newWindowLabel
|
||||
|
||||
let urlValue = 'https://tauri.app'
|
||||
let resizable = true
|
||||
let maximized = false
|
||||
let decorations = true
|
||||
let alwaysOnTop = false
|
||||
let contentProtected = true
|
||||
let fullscreen = false
|
||||
let width = null
|
||||
let height = null
|
||||
let minWidth = null
|
||||
let minHeight = null
|
||||
let maxWidth = null
|
||||
let maxHeight = null
|
||||
let x = null
|
||||
let y = null
|
||||
let scaleFactor = 1
|
||||
let innerPosition = new PhysicalPosition(x, y)
|
||||
let outerPosition = new PhysicalPosition(x, y)
|
||||
let innerSize = new PhysicalSize(width, height)
|
||||
let outerSize = new PhysicalSize(width, height)
|
||||
let resizeEventUnlisten
|
||||
let moveEventUnlisten
|
||||
let cursorGrab = false
|
||||
let cursorVisible = true
|
||||
let cursorX = null
|
||||
let cursorY = null
|
||||
let cursorIcon = 'default'
|
||||
let cursorIgnoreEvents = false
|
||||
let windowTitle = 'Awesome Tauri Example!'
|
||||
|
||||
function setTitle_() {
|
||||
windowMap[selectedWindow].setTitle(windowTitle)
|
||||
}
|
||||
|
||||
function hide_() {
|
||||
windowMap[selectedWindow].hide()
|
||||
setTimeout(windowMap[selectedWindow].show, 2000)
|
||||
}
|
||||
|
||||
function minimize_() {
|
||||
windowMap[selectedWindow].minimize()
|
||||
setTimeout(windowMap[selectedWindow].unminimize, 2000)
|
||||
}
|
||||
|
||||
function createWindow() {
|
||||
if (!newWindowLabel) return
|
||||
|
||||
const webview = new WebviewWindow(newWindowLabel)
|
||||
windowMap[newWindowLabel] = webview
|
||||
webview.once('tauri://error', function () {
|
||||
onMessage('Error creating new webview')
|
||||
})
|
||||
}
|
||||
|
||||
function loadWindowSize() {
|
||||
windowMap[selectedWindow].innerSize().then((response) => {
|
||||
innerSize = response
|
||||
width = innerSize.width
|
||||
height = innerSize.height
|
||||
})
|
||||
windowMap[selectedWindow].outerSize().then((response) => {
|
||||
outerSize = response
|
||||
})
|
||||
}
|
||||
|
||||
function loadWindowPosition() {
|
||||
windowMap[selectedWindow].innerPosition().then((response) => {
|
||||
innerPosition = response
|
||||
})
|
||||
windowMap[selectedWindow].outerPosition().then((response) => {
|
||||
outerPosition = response
|
||||
x = outerPosition.x
|
||||
y = outerPosition.y
|
||||
})
|
||||
}
|
||||
|
||||
async function addWindowEventListeners(window) {
|
||||
if (!window) return
|
||||
if (resizeEventUnlisten) {
|
||||
resizeEventUnlisten()
|
||||
}
|
||||
if (moveEventUnlisten) {
|
||||
moveEventUnlisten()
|
||||
}
|
||||
moveEventUnlisten = await window.listen('tauri://move', loadWindowPosition)
|
||||
resizeEventUnlisten = await window.listen('tauri://resize', loadWindowSize)
|
||||
}
|
||||
|
||||
async function requestUserAttention_() {
|
||||
await windowMap[selectedWindow].minimize()
|
||||
await windowMap[selectedWindow].requestUserAttention(
|
||||
UserAttentionType.Critical
|
||||
)
|
||||
await new Promise((resolve) => setTimeout(resolve, 3000))
|
||||
await windowMap[selectedWindow].requestUserAttention(null)
|
||||
}
|
||||
|
||||
$: {
|
||||
windowMap[selectedWindow]
|
||||
loadWindowPosition()
|
||||
loadWindowSize()
|
||||
}
|
||||
$: windowMap[selectedWindow]?.setResizable(resizable)
|
||||
$: maximized
|
||||
? windowMap[selectedWindow]?.maximize()
|
||||
: windowMap[selectedWindow]?.unmaximize()
|
||||
$: windowMap[selectedWindow]?.setDecorations(decorations)
|
||||
$: windowMap[selectedWindow]?.setAlwaysOnTop(alwaysOnTop)
|
||||
$: windowMap[selectedWindow]?.setContentProtected(contentProtected)
|
||||
$: windowMap[selectedWindow]?.setFullscreen(fullscreen)
|
||||
|
||||
$: width &&
|
||||
height &&
|
||||
windowMap[selectedWindow]?.setSize(new PhysicalSize(width, height))
|
||||
$: minWidth && minHeight
|
||||
? windowMap[selectedWindow]?.setMinSize(
|
||||
new LogicalSize(minWidth, minHeight)
|
||||
)
|
||||
: windowMap[selectedWindow]?.setMinSize(null)
|
||||
$: maxWidth > 800 && maxHeight > 400
|
||||
? windowMap[selectedWindow]?.setMaxSize(
|
||||
new LogicalSize(maxWidth, maxHeight)
|
||||
)
|
||||
: windowMap[selectedWindow]?.setMaxSize(null)
|
||||
$: x !== null &&
|
||||
y !== null &&
|
||||
windowMap[selectedWindow]?.setPosition(new PhysicalPosition(x, y))
|
||||
$: windowMap[selectedWindow]
|
||||
?.scaleFactor()
|
||||
.then((factor) => (scaleFactor = factor))
|
||||
$: addWindowEventListeners(windowMap[selectedWindow])
|
||||
|
||||
$: windowMap[selectedWindow]?.setCursorGrab(cursorGrab)
|
||||
$: windowMap[selectedWindow]?.setCursorVisible(cursorVisible)
|
||||
$: windowMap[selectedWindow]?.setCursorIcon(cursorIcon)
|
||||
$: cursorX !== null &&
|
||||
cursorY !== null &&
|
||||
windowMap[selectedWindow]?.setCursorPosition(
|
||||
new PhysicalPosition(cursorX, cursorY)
|
||||
)
|
||||
$: windowMap[selectedWindow]?.setIgnoreCursorEvents(cursorIgnoreEvents)
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col children:grow gap-2">
|
||||
<div class="flex gap-1">
|
||||
<input
|
||||
class="input grow"
|
||||
type="text"
|
||||
placeholder="New Window label.."
|
||||
bind:value={newWindowLabel}
|
||||
/>
|
||||
<button class="btn" on:click={createWindow}>New window</button>
|
||||
</div>
|
||||
<br />
|
||||
{#if Object.keys(windowMap).length >= 1}
|
||||
<span class="font-700 text-sm">Selected window:</span>
|
||||
<select class="input" bind:value={selectedWindow}>
|
||||
<option value="" disabled selected>Choose a window...</option>
|
||||
{#each Object.keys(windowMap) as label}
|
||||
<option value={label}>{label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{/if}
|
||||
{#if windowMap[selectedWindow]}
|
||||
<br />
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<button
|
||||
class="btn"
|
||||
title="Unminimizes after 2 seconds"
|
||||
on:click={() => windowMap[selectedWindow].center()}
|
||||
>
|
||||
Center
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
title="Unminimizes after 2 seconds"
|
||||
on:click={minimize_}
|
||||
>
|
||||
Minimize
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
title="Visible again after 2 seconds"
|
||||
on:click={hide_}
|
||||
>
|
||||
Hide
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
on:click={requestUserAttention_}
|
||||
title="Minimizes the window, requests attention for 3s and then resets it"
|
||||
>Request attention</button
|
||||
>
|
||||
</div>
|
||||
<br />
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<label>
|
||||
Maximized
|
||||
<input type="checkbox" bind:checked={maximized} />
|
||||
</label>
|
||||
<label>
|
||||
Resizable
|
||||
<input type="checkbox" bind:checked={resizable} />
|
||||
</label>
|
||||
<label>
|
||||
Has decorations
|
||||
<input type="checkbox" bind:checked={decorations} />
|
||||
</label>
|
||||
<label>
|
||||
Always on top
|
||||
<input type="checkbox" bind:checked={alwaysOnTop} />
|
||||
</label>
|
||||
<label>
|
||||
Content protected
|
||||
<input type="checkbox" bind:checked={contentProtected} />
|
||||
</label>
|
||||
<label>
|
||||
Fullscreen
|
||||
<input type="checkbox" bind:checked={fullscreen} />
|
||||
</label>
|
||||
</div>
|
||||
<br />
|
||||
<div class="flex flex-row gap-2 flex-wrap">
|
||||
<div class="flex children:grow flex-col">
|
||||
<div>
|
||||
X
|
||||
<input class="input" type="number" bind:value={x} min="0" />
|
||||
</div>
|
||||
<div>
|
||||
Y
|
||||
<input class="input" type="number" bind:value={y} min="0" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex children:grow flex-col">
|
||||
<div>
|
||||
Width
|
||||
<input class="input" type="number" bind:value={width} min="400" />
|
||||
</div>
|
||||
<div>
|
||||
Height
|
||||
<input class="input" type="number" bind:value={height} min="400" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex children:grow flex-col">
|
||||
<div>
|
||||
Min width
|
||||
<input class="input" type="number" bind:value={minWidth} />
|
||||
</div>
|
||||
<div>
|
||||
Min height
|
||||
<input class="input" type="number" bind:value={minHeight} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex children:grow flex-col">
|
||||
<div>
|
||||
Max width
|
||||
<input class="input" type="number" bind:value={maxWidth} min="800" />
|
||||
</div>
|
||||
<div>
|
||||
Max height
|
||||
<input class="input" type="number" bind:value={maxHeight} min="400" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<div class="flex">
|
||||
<div class="grow">
|
||||
<div class="text-accent dark:text-darkAccent font-700">
|
||||
Inner Size
|
||||
</div>
|
||||
<span>Width: {innerSize.width}</span>
|
||||
<span>Height: {innerSize.height}</span>
|
||||
</div>
|
||||
<div class="grow">
|
||||
<div class="text-accent dark:text-darkAccent font-700">
|
||||
Outer Size
|
||||
</div>
|
||||
<span>Width: {outerSize.width}</span>
|
||||
<span>Height: {outerSize.height}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="grow">
|
||||
<div class="text-accent dark:text-darkAccent font-700">
|
||||
Inner Logical Size
|
||||
</div>
|
||||
<span>Width: {innerSize.toLogical(scaleFactor).width}</span>
|
||||
<span>Height: {innerSize.toLogical(scaleFactor).height}</span>
|
||||
</div>
|
||||
<div class="grow">
|
||||
<div class="text-accent dark:text-darkAccent font-700">
|
||||
Outer Logical Size
|
||||
</div>
|
||||
<span>Width: {outerSize.toLogical(scaleFactor).width}</span>
|
||||
<span>Height: {outerSize.toLogical(scaleFactor).height}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="grow">
|
||||
<div class="text-accent dark:text-darkAccent font-700">
|
||||
Inner Position
|
||||
</div>
|
||||
<span>x: {innerPosition.x}</span>
|
||||
<span>y: {innerPosition.y}</span>
|
||||
</div>
|
||||
<div class="grow">
|
||||
<div class="text-accent dark:text-darkAccent font-700">
|
||||
Outer Position
|
||||
</div>
|
||||
<span>x: {outerPosition.x}</span>
|
||||
<span>y: {outerPosition.y}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="grow">
|
||||
<div class="text-accent dark:text-darkAccent font-700">
|
||||
Inner Logical Position
|
||||
</div>
|
||||
<span>x: {innerPosition.toLogical(scaleFactor).x}</span>
|
||||
<span>y: {innerPosition.toLogical(scaleFactor).y}</span>
|
||||
</div>
|
||||
<div class="grow">
|
||||
<div class="text-accent dark:text-darkAccent font-700">
|
||||
Outer Logical Position
|
||||
</div>
|
||||
<span>x: {outerPosition.toLogical(scaleFactor).x}</span>
|
||||
<span>y: {outerPosition.toLogical(scaleFactor).y}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<h4 class="mb-2">Cursor</h4>
|
||||
<div class="flex gap-2">
|
||||
<label>
|
||||
<input type="checkbox" bind:checked={cursorGrab} />
|
||||
Grab
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" bind:checked={cursorVisible} />
|
||||
Visible
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" bind:checked={cursorIgnoreEvents} />
|
||||
Ignore events
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<label>
|
||||
Icon
|
||||
<select class="input" bind:value={cursorIcon}>
|
||||
{#each cursorIconOptions as kind}
|
||||
<option value={kind}>{kind}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
X position
|
||||
<input class="input" type="number" bind:value={cursorX} />
|
||||
</label>
|
||||
<label>
|
||||
Y position
|
||||
<input class="input" type="number" bind:value={cursorY} />
|
||||
</label>
|
||||
</div>
|
||||
<br />
|
||||
<div class="flex flex-col gap-1">
|
||||
<form class="flex gap-1" on:submit|preventDefault={setTitle_}>
|
||||
<input class="input grow" id="title" bind:value={windowTitle} />
|
||||
<button class="btn" type="submit">Set title</button>
|
||||
</form>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
File diff suppressed because one or more lines are too long
@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { type WindowLabel } from '../window'
|
||||
import { invoke, transformCallback } from '../tauri'
|
||||
import { type EventName } from '../event'
|
||||
|
||||
@ -46,7 +45,7 @@ async function _unlisten(event: string, eventId: number): Promise<void> {
|
||||
*/
|
||||
async function emit(
|
||||
event: string,
|
||||
windowLabel?: WindowLabel,
|
||||
windowLabel?: string,
|
||||
payload?: unknown
|
||||
): Promise<void> {
|
||||
await invoke('plugin:event|emit', {
|
||||
|
@ -1,37 +0,0 @@
|
||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/** @ignore */
|
||||
|
||||
import { invoke } from '../tauri'
|
||||
|
||||
type TauriModule =
|
||||
| 'App'
|
||||
| 'Fs'
|
||||
| 'Path'
|
||||
| 'Os'
|
||||
| 'Window'
|
||||
| 'Shell'
|
||||
| 'Event'
|
||||
| 'Internal'
|
||||
| 'Dialog'
|
||||
| 'Cli'
|
||||
| 'Notification'
|
||||
| 'Http'
|
||||
| 'GlobalShortcut'
|
||||
| 'Process'
|
||||
| 'Clipboard'
|
||||
|
||||
interface TauriCommand {
|
||||
__tauriModule: TauriModule
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
async function invokeTauriCommand<T>(command: TauriCommand): Promise<T> {
|
||||
return invoke('tauri', command)
|
||||
}
|
||||
|
||||
export type { TauriModule, TauriCommand }
|
||||
|
||||
export { invokeTauriCommand }
|
@ -16,9 +16,8 @@
|
||||
import * as event from './event'
|
||||
import * as path from './path'
|
||||
import * as tauri from './tauri'
|
||||
import * as window from './window'
|
||||
|
||||
/** @ignore */
|
||||
const invoke = tauri.invoke
|
||||
|
||||
export { invoke, event, path, tauri, window }
|
||||
export { invoke, event, path, tauri }
|
||||
|
@ -2,6 +2,21 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/** @ignore */
|
||||
declare global {
|
||||
interface Window {
|
||||
__TAURI_METADATA__: {
|
||||
__windows: WindowDef[]
|
||||
__currentWindow: WindowDef
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
interface WindowDef {
|
||||
label: string
|
||||
}
|
||||
|
||||
interface IPCMessage {
|
||||
cmd: string
|
||||
callback: number
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2508,11 +2508,6 @@
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"enableTauriAPI": {
|
||||
"description": "Enables access to the Tauri API.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
Loading…
Reference in New Issue
Block a user