feat: add Window::set_enabled and Window::is_enabled (#11154)

* feat: add `Window::set_enabled` and `Window::is_enabled`

closes #6660

* license headers

* fix build

* fix mobile and macos

* fix macos

* again

* unsafe

* fix macos is_enabled

* update example

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
This commit is contained in:
Amr Bashir
2024-09-27 20:35:01 +03:00
committed by GitHub
parent a49fc999fc
commit de7414aab9
21 changed files with 455 additions and 154 deletions

View File

@@ -0,0 +1,5 @@
---
"@tauri-apps/api": "patch:feat"
---
Add `Window::setEnabled` and `Window::isEnabled` methods

View File

@@ -0,0 +1,7 @@
---
"tauri": "patch:feat"
"tauri-runtime": "patch:feat"
"tauri-runtime-wry": "patch:feat"
---
Add `Window::set_enabled` and `Window::is_enabled` methods

View File

@@ -30,8 +30,8 @@ members = [
# examples
"examples/file-associations/src-tauri",
"examples/api/src-tauri",
"examples/resources/src-tauri",
"examples/api/src-tauri",
"examples/api/src-tauri/tauri-plugin-sample",
]
resolver = "2"

View File

@@ -49,9 +49,12 @@ percent-encoding = "2.1"
objc2 = "0.5.2"
objc2-foundation = { version = "0.2.2", features = [] }
objc2-app-kit = { version = "0.2.2", features = [
"block2",
"NSApplication",
"NSResponder",
"NSView",
"NSWindow",
"NSGraphics",
] }
[target."cfg(target_os = \"android\")".dependencies]

View File

@@ -127,9 +127,11 @@ type IpcHandler = dyn Fn(Request<String>) + 'static;
target_os = "openbsd"
))]
mod undecorated_resizing;
mod webview;
mod window;
pub use webview::Webview;
use window::WindowExt as _;
#[derive(Debug)]
pub struct WebContext {
@@ -1166,9 +1168,11 @@ pub enum WindowMessage {
GtkBox(Sender<GtkBox>),
RawWindowHandle(Sender<std::result::Result<SendRawWindowHandle, raw_window_handle::HandleError>>),
Theme(Sender<Theme>),
IsEnabled(Sender<bool>),
// Setters
Center,
RequestUserAttention(Option<UserAttentionTypeWrapper>),
SetEnabled(bool),
SetResizable(bool),
SetMaximizable(bool),
SetMinimizable(bool),
@@ -1700,6 +1704,10 @@ impl<T: UserEvent> WindowDispatch<T> for WryWindowDispatcher<T> {
window_getter!(self, WindowMessage::Theme)
}
fn is_enabled(&self) -> Result<bool> {
window_getter!(self, WindowMessage::IsEnabled)
}
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
@@ -1775,6 +1783,13 @@ impl<T: UserEvent> WindowDispatch<T> for WryWindowDispatcher<T> {
)
}
fn set_enabled(&self, enabled: bool) -> Result<()> {
send_user_message(
&self.context,
Message::Window(self.window_id, WindowMessage::SetEnabled(enabled)),
)
}
fn set_maximizable(&self, maximizable: bool) -> Result<()> {
send_user_message(
&self.context,
@@ -2865,40 +2880,10 @@ fn handle_user_message<T: UserEvent>(
WindowMessage::Theme(tx) => {
tx.send(map_theme(&window.theme())).unwrap();
}
// Setters
WindowMessage::Center => {
#[cfg(not(target_os = "macos"))]
if let Some(monitor) = window.current_monitor() {
#[allow(unused_mut)]
let mut window_size = window.outer_size();
#[cfg(windows)]
if window.is_decorated() {
use windows::Win32::Foundation::RECT;
use windows::Win32::Graphics::Dwm::{
DwmGetWindowAttribute, DWMWA_EXTENDED_FRAME_BOUNDS,
};
let mut rect = RECT::default();
let result = unsafe {
DwmGetWindowAttribute(
HWND(window.hwnd() as _),
DWMWA_EXTENDED_FRAME_BOUNDS,
&mut rect as *mut _ as *mut _,
std::mem::size_of::<RECT>() as u32,
)
};
if result.is_ok() {
window_size.height = (rect.bottom - rect.top) as u32;
}
}
window.set_outer_position(calculate_window_center_position(window_size, monitor));
}
WindowMessage::IsEnabled(tx) => tx.send(window.is_enabled()).unwrap(),
#[cfg(target_os = "macos")]
{
let ns_window: &objc2_app_kit::NSWindow = unsafe { &*window.ns_window().cast() };
ns_window.center();
}
}
// Setters
WindowMessage::Center => window.center(),
WindowMessage::RequestUserAttention(request_type) => {
window.request_user_attention(request_type.map(|r| r.0));
}
@@ -2919,6 +2904,7 @@ fn handle_user_message<T: UserEvent>(
WindowMessage::Unmaximize => window.set_maximized(false),
WindowMessage::Minimize => window.set_minimized(true),
WindowMessage::Unminimize => window.set_minimized(false),
WindowMessage::SetEnabled(enabled) => window.set_enabled(enabled),
WindowMessage::Show => window.set_visible(true),
WindowMessage::Hide => window.set_visible(false),
WindowMessage::Close => {
@@ -3421,7 +3407,7 @@ fn handle_user_message<T: UserEvent>(
let surface = if is_window_transparent {
if let Ok(context) = softbuffer::Context::new(window.clone()) {
if let Ok(mut surface) = softbuffer::Surface::new(&context, window.clone()) {
clear_window_surface(&window, &mut surface);
window.clear_surface(&mut surface);
Some(surface)
} else {
None
@@ -3499,7 +3485,7 @@ fn handle_event_loop<T: UserEvent>(
if window.is_window_transparent {
if let Some(surface) = &mut window.surface {
if let Some(window) = &window.inner {
clear_window_surface(window, surface)
window.clear_surface(surface);
}
}
}
@@ -3842,7 +3828,7 @@ fn create_window<T: UserEvent, F: Fn(RawWindow) + Send + 'static>(
}
}
}
let position = calculate_window_center_position(window_size, monitor);
let position = window::calculate_window_center_position(window_size, monitor);
let logical_position = position.to_logical::<f64>(scale_factor);
window_builder = window_builder.position(logical_position.x, logical_position.y);
}
@@ -3914,7 +3900,7 @@ fn create_window<T: UserEvent, F: Fn(RawWindow) + Send + 'static>(
let surface = if is_window_transparent {
if let Ok(context) = softbuffer::Context::new(window.clone()) {
if let Ok(mut surface) = softbuffer::Surface::new(&context, window.clone()) {
clear_window_surface(&window, &mut surface);
window.clear_surface(&mut surface);
Some(surface)
} else {
None
@@ -4398,49 +4384,3 @@ fn inner_size(
) -> TaoPhysicalSize<u32> {
window.inner_size()
}
fn calculate_window_center_position(
window_size: TaoPhysicalSize<u32>,
target_monitor: MonitorHandle,
) -> TaoPhysicalPosition<i32> {
#[cfg(windows)]
{
use tao::platform::windows::MonitorHandleExtWindows;
use windows::Win32::Graphics::Gdi::{GetMonitorInfoW, HMONITOR, MONITORINFO};
let mut monitor_info = MONITORINFO {
cbSize: std::mem::size_of::<MONITORINFO>() as u32,
..Default::default()
};
let status =
unsafe { GetMonitorInfoW(HMONITOR(target_monitor.hmonitor() as _), &mut monitor_info) };
if status.into() {
let available_width = monitor_info.rcWork.right - monitor_info.rcWork.left;
let available_height = monitor_info.rcWork.bottom - monitor_info.rcWork.top;
let x = (available_width - window_size.width as i32) / 2 + monitor_info.rcWork.left;
let y = (available_height - window_size.height as i32) / 2 + monitor_info.rcWork.top;
return TaoPhysicalPosition::new(x, y);
}
}
let screen_size = target_monitor.size();
let monitor_pos = target_monitor.position();
let x = (screen_size.width as i32 - window_size.width as i32) / 2 + monitor_pos.x;
let y = (screen_size.height as i32 - window_size.height as i32) / 2 + monitor_pos.y;
TaoPhysicalPosition::new(x, y)
}
#[cfg(windows)]
fn clear_window_surface(
window: &Window,
surface: &mut softbuffer::Surface<Arc<Window>, Arc<Window>>,
) {
let size = window.inner_size();
if let (Some(width), Some(height)) = (
std::num::NonZeroU32::new(size.width),
std::num::NonZeroU32::new(size.height),
) {
surface.resize(width, height).unwrap();
let mut buffer = surface.buffer_mut().unwrap();
buffer.fill(0);
let _ = buffer.present();
}
}

View File

@@ -0,0 +1,31 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use gtk::prelude::*;
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
use tao::platform::unix::WindowExtUnix;
impl super::WindowExt for tao::window::Window {
fn set_enabled(&self, enabled: bool) {
self.gtk_window().set_sensitive(enabled);
}
fn is_enabled(&self) -> bool {
self.gtk_window().is_sensitive()
}
fn center(&self) {
if let Some(monitor) = self.current_monitor() {
let window_size = self.outer_size();
let new_pos = super::calculate_window_center_position(window_size, monitor);
self.set_outer_position(new_pos);
}
}
}

View File

@@ -0,0 +1,43 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use objc2_app_kit::{NSBackingStoreType, NSWindow, NSWindowStyleMask};
use objc2_foundation::MainThreadMarker;
use tao::platform::macos::WindowExtMacOS;
impl super::WindowExt for tao::window::Window {
// based on electron implementation
// https://github.com/electron/electron/blob/15db63e26df3e3d59ce6281f030624f746518511/shell/browser/native_window_mac.mm#L474
fn set_enabled(&self, enabled: bool) {
let ns_window: &NSWindow = unsafe { &*self.ns_window().cast() };
if !enabled {
let frame = ns_window.frame();
let mtm = MainThreadMarker::new()
.expect("`Window::set_enabled` can only be called on the main thread");
let sheet = unsafe {
NSWindow::initWithContentRect_styleMask_backing_defer(
mtm.alloc(),
frame,
NSWindowStyleMask::Titled,
NSBackingStoreType::NSBackingStoreBuffered,
false,
)
};
unsafe { sheet.setAlphaValue(0.5) };
unsafe { ns_window.beginSheet_completionHandler(&sheet, None) };
} else if let Some(attached) = unsafe { ns_window.attachedSheet() } {
unsafe { ns_window.endSheet(&attached) };
}
}
fn is_enabled(&self) -> bool {
let ns_window: &NSWindow = unsafe { &*self.ns_window().cast() };
unsafe { ns_window.attachedSheet() }.is_none()
}
fn center(&self) {
let ns_window: &NSWindow = unsafe { &*self.ns_window().cast() };
ns_window.center();
}
}

View File

@@ -0,0 +1,88 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
mod linux;
#[cfg(target_os = "macos")]
mod macos;
#[cfg(windows)]
mod windows;
pub trait WindowExt {
/// Enable or disable the window
///
/// ## Platform-specific:
///
/// - **Android / iOS**: Unsupported.
fn set_enabled(&self, enabled: bool);
/// Whether the window is enabled or disabled.
///
/// ## Platform-specific:
///
/// - **Android / iOS**: Unsupported, always returns `true`.
fn is_enabled(&self) -> bool;
/// Center the window
///
/// ## Platform-specific:
///
/// - **Android / iOS**: Unsupported.
fn center(&self) {}
/// Clears the window sufrace. i.e make it it transparent.
#[cfg(windows)]
fn clear_surface(
&self,
surface: &mut softbuffer::Surface<
std::sync::Arc<tao::window::Window>,
std::sync::Arc<tao::window::Window>,
>,
);
}
#[cfg(mobile)]
impl WindowExt for tao::window::Window {
fn set_enabled(&self, _: bool) {}
fn is_enabled(&self) -> bool {
true
}
}
pub fn calculate_window_center_position(
window_size: tao::dpi::PhysicalSize<u32>,
target_monitor: tao::monitor::MonitorHandle,
) -> tao::dpi::PhysicalPosition<i32> {
#[cfg(windows)]
{
use ::windows::Win32::Graphics::Gdi::{GetMonitorInfoW, HMONITOR, MONITORINFO};
use tao::platform::windows::MonitorHandleExtWindows;
let mut monitor_info = MONITORINFO {
cbSize: std::mem::size_of::<MONITORINFO>() as u32,
..Default::default()
};
let hmonitor = target_monitor.hmonitor();
let status = unsafe { GetMonitorInfoW(HMONITOR(hmonitor as _), &mut monitor_info) };
if status.into() {
let available_width = monitor_info.rcWork.right - monitor_info.rcWork.left;
let available_height = monitor_info.rcWork.bottom - monitor_info.rcWork.top;
let x = (available_width - window_size.width as i32) / 2 + monitor_info.rcWork.left;
let y = (available_height - window_size.height as i32) / 2 + monitor_info.rcWork.top;
return tao::dpi::PhysicalPosition::new(x, y);
}
}
let screen_size = target_monitor.size();
let monitor_pos = target_monitor.position();
let x = (screen_size.width as i32 - window_size.width as i32) / 2 + monitor_pos.x;
let y = (screen_size.height as i32 - window_size.height as i32) / 2 + monitor_pos.y;
tao::dpi::PhysicalPosition::new(x, y)
}

View File

@@ -0,0 +1,64 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use windows::Win32::{
Foundation::{HWND, RECT},
Graphics::Dwm::{DwmGetWindowAttribute, DWMWA_EXTENDED_FRAME_BOUNDS},
UI::Input::KeyboardAndMouse::{EnableWindow, IsWindowEnabled},
};
use tao::platform::windows::WindowExtWindows;
impl super::WindowExt for tao::window::Window {
fn set_enabled(&self, enabled: bool) {
let _ = unsafe { EnableWindow(HWND(self.hwnd() as _), enabled) };
}
fn is_enabled(&self) -> bool {
unsafe { IsWindowEnabled(HWND(self.hwnd() as _)) }.as_bool()
}
fn center(&self) {
if let Some(monitor) = self.current_monitor() {
let mut window_size = self.outer_size();
if self.is_decorated() {
let mut rect = RECT::default();
let result = unsafe {
DwmGetWindowAttribute(
HWND(self.hwnd() as _),
DWMWA_EXTENDED_FRAME_BOUNDS,
&mut rect as *mut _ as *mut _,
std::mem::size_of::<RECT>() as u32,
)
};
if result.is_ok() {
window_size.height = (rect.bottom - rect.top) as u32;
}
}
let new_pos = super::calculate_window_center_position(window_size, monitor);
self.set_outer_position(new_pos);
}
}
fn clear_surface(
&self,
surface: &mut softbuffer::Surface<
std::sync::Arc<tao::window::Window>,
std::sync::Arc<tao::window::Window>,
>,
) {
let size = self.inner_size();
if let (Some(width), Some(height)) = (
std::num::NonZeroU32::new(size.width),
std::num::NonZeroU32::new(size.height),
) {
surface.resize(width, height).unwrap();
let mut buffer = surface.buffer_mut().unwrap();
buffer.fill(0);
let _ = buffer.present();
}
}
}

View File

@@ -603,6 +603,10 @@ pub trait WindowDispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 's
/// Gets the window's current visibility state.
fn is_visible(&self) -> Result<bool>;
/// Whether the window is enabled or disable.
fn is_enabled(&self) -> Result<bool>;
/// Gets the window's current title.
fn title(&self) -> Result<String>;
@@ -676,6 +680,13 @@ pub trait WindowDispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 's
/// Updates the window resizable flag.
fn set_resizable(&self, resizable: bool) -> Result<()>;
/// Enable or disable the window.
///
/// ## Platform-specific
///
/// - **Android / iOS**: Unsupported.
fn set_enabled(&self, enabled: bool) -> Result<()>;
/// Updates the window's native maximize button state.
///
/// ## Platform-specific

View File

@@ -57,6 +57,7 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
("is_minimizable", true),
("is_closable", true),
("is_visible", true),
("is_enabled", true),
("title", true),
("current_monitor", true),
("primary_monitor", true),
@@ -67,6 +68,7 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
// setters
("center", false),
("request_user_attention", false),
("set_enabled", false),
("set_resizable", false),
("set_maximizable", false),
("set_minimizable", false),

View File

@@ -123,32 +123,6 @@ Denies the get_all_webviews command without any pre-configured scope.
<tr>
<td>
`core:webview:allow-hide-webview`
</td>
<td>
Enables the hide_webview command without any pre-configured scope.
</td>
</tr>
<tr>
<td>
`core:webview:deny-hide-webview`
</td>
<td>
Denies the hide_webview command without any pre-configured scope.
</td>
</tr>
<tr>
<td>
`core:webview:allow-internal-toggle-devtools`
</td>
@@ -331,32 +305,6 @@ Denies the set_webview_zoom command without any pre-configured scope.
<tr>
<td>
`core:webview:allow-show-webview`
</td>
<td>
Enables the show_webview command without any pre-configured scope.
</td>
</tr>
<tr>
<td>
`core:webview:deny-show-webview`
</td>
<td>
Denies the show_webview command without any pre-configured scope.
</td>
</tr>
<tr>
<td>
`core:webview:allow-webview-close`
</td>

View File

@@ -18,6 +18,7 @@ Default permissions for the plugin.
- `allow-is-minimizable`
- `allow-is-closable`
- `allow-is-visible`
- `allow-is-enabled`
- `allow-title`
- `allow-current-monitor`
- `allow-primary-monitor`
@@ -403,6 +404,32 @@ Denies the is_decorated command without any pre-configured scope.
<tr>
<td>
`core:window:allow-is-enabled`
</td>
<td>
Enables the is_enabled command without any pre-configured scope.
</td>
</tr>
<tr>
<td>
`core:window:deny-is-enabled`
</td>
<td>
Denies the is_enabled command without any pre-configured scope.
</td>
</tr>
<tr>
<td>
`core:window:allow-is-focused`
</td>
@@ -1079,6 +1106,32 @@ Denies the set_effects command without any pre-configured scope.
<tr>
<td>
`core:window:allow-set-enabled`
</td>
<td>
Enables the set_enabled command without any pre-configured scope.
</td>
</tr>
<tr>
<td>
`core:window:deny-set-enabled`
</td>
<td>
Denies the set_enabled command without any pre-configured scope.
</td>
</tr>
<tr>
<td>
`core:window:allow-set-focus`
</td>

File diff suppressed because one or more lines are too long

View File

@@ -971,6 +971,14 @@ impl<T: UserEvent> WindowDispatch<T> for MockWindowDispatcher {
fn set_theme(&self, theme: Option<Theme>) -> Result<()> {
Ok(())
}
fn set_enabled(&self, enabled: bool) -> Result<()> {
Ok(())
}
fn is_enabled(&self) -> Result<bool> {
Ok(true)
}
}
#[derive(Debug, Clone)]

View File

@@ -1157,6 +1157,11 @@ impl<R: Runtime> WebviewWindow<R> {
self.window.is_resizable()
}
/// Whether the window is enabled or disabled.
pub fn is_enabled(&self) -> crate::Result<bool> {
self.webview.window().is_enabled()
}
/// Gets the window's native maximize button state
///
/// ## Platform-specific
@@ -1322,6 +1327,11 @@ impl<R: Runtime> WebviewWindow<R> {
self.window.set_resizable(resizable)
}
/// Enable or disable the window.
pub fn set_enabled(&self, enabled: bool) -> crate::Result<()> {
self.webview.window().set_enabled(enabled)
}
/// Determines if this window's native maximize button should be enabled.
/// If resizable is set to false, this setting is ignored.
///

View File

@@ -1370,6 +1370,11 @@ impl<R: Runtime> Window<R> {
self.window.dispatcher.is_resizable().map_err(Into::into)
}
/// Whether the window is enabled or disabled.
pub fn is_enabled(&self) -> crate::Result<bool> {
self.window.dispatcher.is_enabled().map_err(Into::into)
}
/// Gets the window's native maximize button state
///
/// ## Platform-specific
@@ -1650,6 +1655,15 @@ impl<R: Runtime> Window<R> {
.map_err(Into::into)
}
/// Enable or disable the window.
pub fn set_enabled(&self, enabled: bool) -> crate::Result<()> {
self
.window
.dispatcher
.set_enabled(enabled)
.map_err(Into::into)
}
/// Maximizes this window.
pub fn maximize(&self) -> crate::Result<()> {
self.window.dispatcher.maximize().map_err(Into::into)

View File

@@ -92,6 +92,7 @@ mod desktop_commands {
getter!(is_minimizable, bool);
getter!(is_closable, bool);
getter!(is_visible, bool);
getter!(is_enabled, bool);
getter!(title, String);
getter!(current_monitor, Option<Monitor>);
getter!(primary_monitor, Option<Monitor>);
@@ -139,6 +140,7 @@ mod desktop_commands {
setter!(set_title_bar_style, TitleBarStyle);
setter!(set_size_constraints, WindowSizeConstraints);
setter!(set_theme, Option<Theme>);
setter!(set_enabled, bool);
#[command(root = "crate")]
pub async fn set_icon<R: Runtime>(
@@ -240,6 +242,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
desktop_commands::is_minimizable,
desktop_commands::is_closable,
desktop_commands::is_visible,
desktop_commands::is_enabled,
desktop_commands::title,
desktop_commands::current_monitor,
desktop_commands::primary_monitor,
@@ -276,6 +279,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
desktop_commands::set_position,
desktop_commands::set_fullscreen,
desktop_commands::set_focus,
desktop_commands::set_enabled,
desktop_commands::set_skip_taskbar,
desktop_commands::set_cursor_grab,
desktop_commands::set_cursor_visible,

View File

@@ -4,6 +4,8 @@
"description": "permissions to run the app",
"windows": ["main", "main-*"],
"permissions": [
"core:window:allow-is-enabled",
"core:window:allow-set-enabled",
{
"identifier": "allow-log-operation",
"allow": [

View File

@@ -138,16 +138,42 @@
let windowIconPath
function setTitle_() {
function setTitle() {
webviewMap[selectedWebview].setTitle(windowTitle)
}
function hide_() {
webviewMap[selectedWebview].hide()
setTimeout(webviewMap[selectedWebview].show, 2000)
async function hide() {
let visible = await webviewMap[selectedWebview].isVisible()
onMessage('window is ' + (visible ? 'visible' : 'invisible'))
await webviewMap[selectedWebview].hide()
setTimeout(async () => {
visible = await webviewMap[selectedWebview].isVisible()
onMessage('window is ' + (visible ? 'visible' : 'invisible'))
await webviewMap[selectedWebview].show()
visible = await webviewMap[selectedWebview].isVisible()
onMessage('window is ' + (visible ? 'visible' : 'invisible'))
}, 2000)
}
function minimize_() {
async function disable() {
let enabled = await webviewMap[selectedWebview].isEnabled()
onMessage('window is ' + (enabled ? 'enabled' : 'disabled'))
await webviewMap[selectedWebview].setEnabled(false)
setTimeout(async () => {
enabled = await webviewMap[selectedWebview].isEnabled()
onMessage('window is ' + (enabled ? 'enabled' : 'disabled'))
await webviewMap[selectedWebview].setEnabled(true)
enabled = await webviewMap[selectedWebview].isEnabled()
onMessage('window is ' + (enabled ? 'enabled' : 'disabled'))
}, 2000)
}
function minimize() {
webviewMap[selectedWebview].minimize()
setTimeout(webviewMap[selectedWebview].unminimize, 2000)
}
@@ -200,7 +226,7 @@
resizeEventUnlisten = await window.listen('tauri://resize', loadWindowSize)
}
async function requestUserAttention_() {
async function requestUserAttention() {
await webviewMap[selectedWebview].minimize()
await webviewMap[selectedWebview].requestUserAttention(
UserAttentionType.Critical
@@ -363,7 +389,7 @@
</div>
<div class="grid gap-1 grow">
<h4 class="my-2">Set Window Title</h4>
<form class="flex gap-2" on:submit|preventDefault={setTitle_}>
<form class="flex gap-2" on:submit|preventDefault={setTitle}>
<input class="input flex-1 min-w-10" bind:value={windowTitle} />
<button class="btn" type="submit">Set</button>
</form>
@@ -380,20 +406,23 @@
<button
class="btn"
title="Unminimizes after 2 seconds"
on:click={minimize_}
on:click={minimize}
>
Minimize
</button>
<button
class="btn"
title="Visible again after 2 seconds"
on:click={hide_}
>
<button class="btn" title="Visible again after 2 seconds" on:click={hide}>
Hide
</button>
<button
class="btn"
on:click={requestUserAttention_}
title="Enabled again after 2 seconds"
on:click={disable}
>
Disable
</button>
<button
class="btn"
on:click={requestUserAttention}
title="Minimizes the window, requests attention for 3s and then resets it"
>Request attention</button
>
@@ -531,14 +560,16 @@
Inner Logical Size
</div>
<span>Width: {innerSize.toLogical(scaleFactor).width.toFixed(3)}</span>
<span>Height: {innerSize.toLogical(scaleFactor).height.toFixed(3)}</span>
<span>Height: {innerSize.toLogical(scaleFactor).height.toFixed(3)}</span
>
</div>
<div>
<div class="text-accent dark:text-darkAccent font-700 m-block-1">
Outer Logical Size
</div>
<span>Width: {outerSize.toLogical(scaleFactor).width.toFixed(3)}</span>
<span>Height: {outerSize.toLogical(scaleFactor).height.toFixed(3)}</span>
<span>Height: {outerSize.toLogical(scaleFactor).height.toFixed(3)}</span
>
</div>
<div>
<div class="text-accent dark:text-darkAccent font-700 m-block-1">

View File

@@ -870,6 +870,43 @@ class Window {
})
}
/**
* Enable or disable the window.
* @example
* ```typescript
* import { getCurrentWindow } from '@tauri-apps/api/window';
* await getCurrentWindow().setEnabled(false);
* ```
*
* @returns A promise indicating the success or failure of the operation.
*
* @since 2.0.0
*/
async setEnabled(enabled: boolean): Promise<void> {
return invoke('plugin:window|set_enabled', {
label: this.label,
value: enabled
})
}
/**
* Whether the window is enabled or disabled.
* @example
* ```typescript
* import { getCurrentWindow } from '@tauri-apps/api/window';
* await getCurrentWindow().setEnabled(false);
* ```
*
* @returns A promise indicating the success or failure of the operation.
*
* @since 2.0.0
*/
async isEnabled(): Promise<boolean> {
return invoke('plugin:window|is_enabled', {
label: this.label
})
}
/**
* Sets whether the window's native maximize button is enabled or not.
* If resizable is set to false, this setting is ignored.