Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: move window plugin back to core #8007

Merged
merged 10 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/api-window.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tauri-apps/api": 'minor:feat'
---

Add the `window` module back
5 changes: 5 additions & 0 deletions .changes/window-plugin-core.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tauri": patch:changes
---

Added the `window` plugin back into core.
2 changes: 1 addition & 1 deletion core/tauri/scripts/bundle.global.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions core/tauri/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,7 @@ impl<R: Runtime> App<R> {
fn register_core_plugins(&self) -> crate::Result<()> {
self.handle.plugin(crate::path::init())?;
self.handle.plugin(crate::event::init())?;
self.handle.plugin(crate::window::plugin::init())?;
Ok(())
}

Expand Down
3 changes: 3 additions & 0 deletions core/tauri/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,7 @@ pub enum Error {
#[cfg(all(desktop, feature = "tray-icon"))]
#[cfg_attr(doc_cfg, doc(cfg(all(desktop, feature = "tray-icon"))))]
BadTrayIcon(#[from] tray_icon::BadIcon),
/// window not found.
#[error("window not found")]
WindowNotFound,
}
4 changes: 3 additions & 1 deletion core/tauri/src/window.rs → core/tauri/src/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

//! The Tauri window types and functions.

pub(crate) mod plugin;

use http::HeaderMap;
pub use tauri_utils::{config::Color, WindowEffect as Effect, WindowEffectState as EffectState};
use url::Url;
Expand Down Expand Up @@ -2461,7 +2463,7 @@ impl<R: Runtime> Window<R> {
///
/// This listener only receives events that are triggered using the
/// [`trigger`](Window#method.trigger) and [`emit_and_trigger`](Window#method.emit_and_trigger) methods or
/// the `emit` function from the window plugin (`@tauri-apps/plugin-window` package).
/// the `emit` function from the window plugin (`@tauri-apps/api/window` package).
///
/// # Examples
/// ```
Expand Down
322 changes: 322 additions & 0 deletions core/tauri/src/window/plugin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,322 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

//! The tauri plugin to create and manipulate windows from JS.

use crate::{
plugin::{Builder, TauriPlugin},
Runtime,
};

#[cfg(desktop)]
mod desktop_commands {
use serde::Deserialize;

use super::*;
use crate::{
command,
utils::config::{WindowConfig, WindowEffectsConfig},
AppHandle, CursorIcon, Icon, Manager, Monitor, PhysicalPosition, PhysicalSize, Position, Size,
Theme, UserAttentionType, Window, WindowBuilder,
};

#[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,
},
}
}
}

#[command(root = "crate")]
pub async fn create<R: Runtime>(app: AppHandle<R>, options: WindowConfig) -> crate::Result<()> {
WindowBuilder::from_config(&app, options).build()?;
Ok(())
}

fn get_window<R: Runtime>(window: Window<R>, label: Option<String>) -> crate::Result<Window<R>> {
match label {
Some(l) if !l.is_empty() => window.get_window(&l).ok_or(crate::Error::WindowNotFound),
_ => Ok(window),
}
}

macro_rules! getter {
($cmd: ident, $ret: ty) => {
#[command(root = "crate")]
pub async fn $cmd<R: Runtime>(
window: Window<R>,
label: Option<String>,
) -> crate::Result<$ret> {
get_window(window, label)?.$cmd().map_err(Into::into)
}
};
}

macro_rules! setter {
($cmd: ident) => {
#[command(root = "crate")]
pub async fn $cmd<R: Runtime>(window: Window<R>, label: Option<String>) -> crate::Result<()> {
get_window(window, label)?.$cmd().map_err(Into::into)
}
};

($cmd: ident, $input: ty) => {
#[command(root = "crate")]
pub async fn $cmd<R: Runtime>(
window: Window<R>,
label: Option<String>,
value: $input,
) -> crate::Result<()> {
get_window(window, label)?.$cmd(value).map_err(Into::into)
}
};
}

getter!(scale_factor, f64);
getter!(inner_position, PhysicalPosition<i32>);
getter!(outer_position, PhysicalPosition<i32>);
getter!(inner_size, PhysicalSize<u32>);
getter!(outer_size, PhysicalSize<u32>);
getter!(is_fullscreen, bool);
getter!(is_minimized, bool);
getter!(is_maximized, bool);
getter!(is_focused, bool);
getter!(is_decorated, bool);
getter!(is_resizable, bool);
getter!(is_maximizable, bool);
getter!(is_minimizable, bool);
getter!(is_closable, bool);
getter!(is_visible, bool);
getter!(title, String);
getter!(current_monitor, Option<Monitor>);
getter!(primary_monitor, Option<Monitor>);
getter!(available_monitors, Vec<Monitor>);
getter!(theme, Theme);

setter!(center);
setter!(request_user_attention, Option<UserAttentionType>);
setter!(set_resizable, bool);
setter!(set_maximizable, bool);
setter!(set_minimizable, bool);
setter!(set_closable, bool);
setter!(set_title, &str);
setter!(maximize);
setter!(unmaximize);
setter!(minimize);
setter!(unminimize);
setter!(show);
setter!(hide);
setter!(close);
setter!(set_decorations, bool);
setter!(set_shadow, bool);
setter!(set_effects, Option<WindowEffectsConfig>);
setter!(set_always_on_top, bool);
setter!(set_content_protected, bool);
setter!(set_size, Size);
setter!(set_min_size, Option<Size>);
setter!(set_max_size, Option<Size>);
setter!(set_position, Position);
setter!(set_fullscreen, bool);
setter!(set_focus);
setter!(set_skip_taskbar, bool);
setter!(set_cursor_grab, bool);
setter!(set_cursor_visible, bool);
setter!(set_cursor_icon, CursorIcon);
setter!(set_cursor_position, Position);
setter!(set_ignore_cursor_events, bool);
setter!(start_dragging);
setter!(print);

#[command(root = "crate")]
pub async fn set_icon<R: Runtime>(
window: Window<R>,
label: Option<String>,
value: IconDto,
) -> crate::Result<()> {
get_window(window, label)?
.set_icon(value.into())
.map_err(Into::into)
}

#[command(root = "crate")]
pub async fn toggle_maximize<R: Runtime>(
window: Window<R>,
label: Option<String>,
) -> crate::Result<()> {
let window = get_window(window, label)?;
match window.is_maximized()? {
true => window.unmaximize()?,
false => window.maximize()?,
};
Ok(())
}

#[command(root = "crate")]
pub async fn internal_toggle_maximize<R: Runtime>(
window: Window<R>,
label: Option<String>,
) -> crate::Result<()> {
let window = get_window(window, label)?;
if window.is_resizable()? {
match window.is_maximized()? {
true => window.unmaximize()?,
false => window.maximize()?,
};
}
Ok(())
}

#[cfg(any(debug_assertions, feature = "devtools"))]
#[command(root = "crate")]
pub async fn internal_toggle_devtools<R: Runtime>(
window: Window<R>,
label: Option<String>,
) -> crate::Result<()> {
let window = get_window(window, label)?;
if window.is_devtools_open() {
window.close_devtools();
} else {
window.open_devtools();
}
Ok(())
}
}

/// Initializes the plugin.
pub fn init<R: Runtime>() -> TauriPlugin<R> {
let mut init_script = String::new();
// window.print works on Linux/Windows; need to use the API on macOS
#[cfg(any(target_os = "macos", target_os = "ios"))]
{
init_script.push_str(include_str!("./scripts/print.js"));
}
init_script.push_str(include_str!("./scripts/drag.js"));

#[cfg(any(debug_assertions, feature = "devtools"))]
{
use serialize_to_javascript::{default_template, DefaultTemplate, Template};

#[derive(Template)]
#[default_template("./scripts/toggle-devtools.js")]
struct Devtools<'a> {
os_name: &'a str,
}

init_script.push_str(
&Devtools {
os_name: std::env::consts::OS,
}
.render_default(&Default::default())
.unwrap()
.into_string(),
);
}

Builder::new("window")
.js_init_script(init_script)
.invoke_handler(|invoke| {
#[cfg(desktop)]
{
let handler: Box<dyn Fn(crate::ipc::Invoke<R>) -> bool> =
Box::new(crate::generate_handler![
desktop_commands::create,
// getters
desktop_commands::scale_factor,
desktop_commands::inner_position,
desktop_commands::outer_position,
desktop_commands::inner_size,
desktop_commands::outer_size,
desktop_commands::is_fullscreen,
desktop_commands::is_minimized,
desktop_commands::is_maximized,
desktop_commands::is_focused,
desktop_commands::is_decorated,
desktop_commands::is_resizable,
desktop_commands::is_maximizable,
desktop_commands::is_minimizable,
desktop_commands::is_closable,
desktop_commands::is_visible,
desktop_commands::title,
desktop_commands::current_monitor,
desktop_commands::primary_monitor,
desktop_commands::available_monitors,
desktop_commands::theme,
// setters
desktop_commands::center,
desktop_commands::request_user_attention,
desktop_commands::set_resizable,
desktop_commands::set_maximizable,
desktop_commands::set_minimizable,
desktop_commands::set_closable,
desktop_commands::set_title,
desktop_commands::maximize,
desktop_commands::unmaximize,
desktop_commands::minimize,
desktop_commands::unminimize,
desktop_commands::show,
desktop_commands::hide,
desktop_commands::close,
desktop_commands::set_decorations,
desktop_commands::set_shadow,
desktop_commands::set_effects,
desktop_commands::set_always_on_top,
desktop_commands::set_content_protected,
desktop_commands::set_size,
desktop_commands::set_min_size,
desktop_commands::set_max_size,
desktop_commands::set_position,
desktop_commands::set_fullscreen,
desktop_commands::set_focus,
desktop_commands::set_skip_taskbar,
desktop_commands::set_cursor_grab,
desktop_commands::set_cursor_visible,
desktop_commands::set_cursor_icon,
desktop_commands::set_cursor_position,
desktop_commands::set_ignore_cursor_events,
desktop_commands::start_dragging,
desktop_commands::print,
desktop_commands::set_icon,
desktop_commands::toggle_maximize,
desktop_commands::internal_toggle_maximize,
#[cfg(any(debug_assertions, feature = "devtools"))]
desktop_commands::internal_toggle_devtools,
]);
#[allow(clippy::needless_return)]
return handler(invoke);
}
#[cfg(mobile)]
{
invoke.resolver.reject("Window API not available on mobile");
return true;
}
})
.build()
}
17 changes: 17 additions & 0 deletions core/tauri/src/window/scripts/drag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

document.addEventListener("mousedown", (e) => {
if (e.target.hasAttribute("data-tauri-drag-region") && e.button === 0) {
// prevents text cursor
e.preventDefault();
// fix #2549: double click on drag region edge causes content to maximize without window sizing change
// https://github.com/tauri-apps/tauri/issues/2549#issuecomment-1250036908
e.stopImmediatePropagation();

// start dragging if the element has a `tauri-drag-region` data attribute and maximize on double-clicking it
const cmd = e.detail === 2 ? "internal_toggle_maximize" : "start_dragging";
window.__TAURI_INVOKE__("plugin:window|" + cmd);
}
});
7 changes: 7 additions & 0 deletions core/tauri/src/window/scripts/print.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

window.print = function () {
return window.__TAURI_INVOKE__("plugin:window|print");
};
Loading
Loading