Skip to content
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
8 changes: 8 additions & 0 deletions .changes/focusable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"tauri": minor:feat
"tauri-runtime": minor:feat
"tauri-runtime-wry": minor:feat
"@tauri-apps/api": minor:feat
---

Add window focusable attribute and set_focusable API.
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions crates/tauri-cli/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,11 @@
"default": true,
"type": "boolean"
},
"focusable": {
"description": "Whether the window will be focusable or not.",
"default": true,
"type": "boolean"
},
"transparent": {
"description": "Whether the window is transparent or not.\n\n Note that on `macOS` this requires the `macos-private-api` feature flag, enabled under `tauri > macOSPrivateApi`.\n WARNING: Using private APIs on `macOS` prevents your application from being accepted to the `App Store`.",
"default": false,
Expand Down
5 changes: 5 additions & 0 deletions crates/tauri-cli/tauri.config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,11 @@
"default": true,
"type": "boolean"
},
"focusable": {
"description": "Whether the window will be focusable or not.",
"default": true,
"type": "boolean"
},
"transparent": {
"description": "Whether the window is transparent or not.\n\n Note that on `macOS` this requires the `macos-private-api` feature flag, enabled under `tauri > macOSPrivateApi`.\n WARNING: Using private APIs on `macOS` prevents your application from being accepted to the `App Store`.",
"default": false,
Expand Down
2 changes: 1 addition & 1 deletion crates/tauri-runtime-wry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ wry = { version = "0.53.1", default-features = false, features = [
"os-webview",
"linux-body",
] }
tao = { version = "0.34", default-features = false, features = ["rwh_06"] }
tao = { version = "0.34.1", default-features = false, features = ["rwh_06"] }
tauri-runtime = { version = "2.7.1", path = "../tauri-runtime" }
tauri-utils = { version = "2.6.0", path = "../tauri-utils" }
raw-window-handle = "0.6"
Expand Down
17 changes: 17 additions & 0 deletions crates/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,7 @@ impl WindowBuilder for WindowBuilderWrapper {
.title(config.title.to_string())
.inner_size(config.width, config.height)
.focused(config.focus)
.focusable(config.focusable)
.visible(config.visible)
.resizable(config.resizable)
.fullscreen(config.fullscreen)
Expand Down Expand Up @@ -1035,6 +1036,11 @@ impl WindowBuilder for WindowBuilderWrapper {
self
}

fn focusable(mut self, focusable: bool) -> Self {
self.inner = self.inner.with_focusable(focusable);
self
}

fn maximized(mut self, maximized: bool) -> Self {
self.inner = self.inner.with_maximized(maximized);
self
Expand Down Expand Up @@ -1355,6 +1361,7 @@ pub enum WindowMessage {
#[cfg(target_os = "macos")]
SetSimpleFullscreen(bool),
SetFocus,
SetFocusable(bool),
SetIcon(TaoWindowIcon),
SetSkipTaskbar(bool),
SetCursorGrab(bool),
Expand Down Expand Up @@ -2238,6 +2245,13 @@ impl<T: UserEvent> WindowDispatch<T> for WryWindowDispatcher<T> {
)
}

fn set_focusable(&self, focusable: bool) -> Result<()> {
send_user_message(
&self.context,
Message::Window(self.window_id, WindowMessage::SetFocusable(focusable)),
)
}

fn set_icon(&self, icon: Icon) -> Result<()> {
send_user_message(
&self.context,
Expand Down Expand Up @@ -3379,6 +3393,9 @@ fn handle_user_message<T: UserEvent>(
WindowMessage::SetFocus => {
window.set_focus();
}
WindowMessage::SetFocusable(focusable) => {
window.set_focusable(focusable);
}
WindowMessage::SetIcon(icon) => {
window.set_window_icon(Some(icon));
}
Expand Down
3 changes: 3 additions & 0 deletions crates/tauri-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,9 @@ pub trait WindowDispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 's
/// Bring the window to front and focus.
fn set_focus(&self) -> Result<()>;

/// Sets whether the window can be focused.
fn set_focusable(&self, focusable: bool) -> Result<()>;

/// Updates the window icon.
fn set_icon(&self, icon: Icon) -> Result<()>;

Expand Down
4 changes: 4 additions & 0 deletions crates/tauri-runtime/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,10 @@ pub trait WindowBuilder: WindowBuilderBase {
#[must_use]
fn focused(self, focused: bool) -> Self;

/// Whether the window will be focusable or not.
#[must_use]
fn focusable(self, focusable: bool) -> Self;

/// Whether the window should be maximized upon creation.
#[must_use]
fn maximized(self, maximized: bool) -> Self;
Expand Down
5 changes: 5 additions & 0 deletions crates/tauri-schema-generator/schemas/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,11 @@
"default": true,
"type": "boolean"
},
"focusable": {
"description": "Whether the window will be focusable or not.",
"default": true,
"type": "boolean"
},
"transparent": {
"description": "Whether the window is transparent or not.\n\n Note that on `macOS` this requires the `macos-private-api` feature flag, enabled under `tauri > macOSPrivateApi`.\n WARNING: Using private APIs on `macOS` prevents your application from being accepted to the `App Store`.",
"default": false,
Expand Down
6 changes: 6 additions & 0 deletions crates/tauri-utils/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1641,6 +1641,9 @@ pub struct WindowConfig {
/// Whether the window will be initially focused or not.
#[serde(default = "default_true")]
pub focus: bool,
/// Whether the window will be focusable or not.
#[serde(default = "default_true")]
pub focusable: bool,
/// Whether the window is transparent or not.
///
/// Note that on `macOS` this requires the `macos-private-api` feature flag, enabled under `tauri > macOSPrivateApi`.
Expand Down Expand Up @@ -1866,6 +1869,7 @@ impl Default for WindowConfig {
title: default_title(),
fullscreen: false,
focus: false,
focusable: true,
transparent: false,
maximized: false,
visible: true,
Expand Down Expand Up @@ -3319,6 +3323,7 @@ mod build {
let proxy_url = opt_lit(self.proxy_url.as_ref().map(url_lit).as_ref());
let fullscreen = self.fullscreen;
let focus = self.focus;
let focusable = self.focusable;
let transparent = self.transparent;
let maximized = self.maximized;
let visible = self.visible;
Expand Down Expand Up @@ -3376,6 +3381,7 @@ mod build {
proxy_url,
fullscreen,
focus,
focusable,
transparent,
maximized,
visible,
Expand Down
1 change: 1 addition & 0 deletions crates/tauri/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
("set_fullscreen", false),
("set_simple_fullscreen", false),
("set_focus", false),
("set_focusable", false),
("set_skip_taskbar", false),
("set_cursor_grab", false),
("set_cursor_visible", false),
Expand Down
26 changes: 26 additions & 0 deletions crates/tauri/permissions/window/autogenerated/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1265,6 +1265,32 @@ Denies the set_focus command without any pre-configured scope.
<tr>
<td>

`core:window:allow-set-focusable`

</td>
<td>

Enables the set_focusable command without any pre-configured scope.

</td>
</tr>

<tr>
<td>

`core:window:deny-set-focusable`

</td>
<td>

Denies the set_focusable command without any pre-configured scope.

</td>
</tr>

<tr>
<td>

`core:window:allow-set-fullscreen`

</td>
Expand Down
2 changes: 1 addition & 1 deletion crates/tauri/scripts/bundle.global.js

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions crates/tauri/src/test/mock_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,10 @@ impl WindowBuilder for MockWindowBuilder {
self
}

fn focusable(self, focusable: bool) -> Self {
self
}

fn maximized(self, maximized: bool) -> Self {
self
}
Expand Down Expand Up @@ -1002,6 +1006,10 @@ impl<T: UserEvent> WindowDispatch<T> for MockWindowDispatcher {
Ok(())
}

fn set_focusable(&self, focusable: bool) -> Result<()> {
Ok(())
}

fn set_icon(&self, icon: Icon<'_>) -> Result<()> {
Ok(())
}
Expand Down
17 changes: 17 additions & 0 deletions crates/tauri/src/webview/webview_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,13 @@ impl<'a, R: Runtime, M: Manager<R>> WebviewWindowBuilder<'a, R, M> {
self
}

/// Whether the window will be focusable or not.
#[must_use]
pub fn focusable(mut self, focusable: bool) -> Self {
self.window_builder = self.window_builder.focusable(focusable);
self
}

/// Whether the window will be initially focused or not.
#[must_use]
pub fn focused(mut self, focused: bool) -> Self {
Expand Down Expand Up @@ -2036,6 +2043,16 @@ impl<R: Runtime> WebviewWindow<R> {
self.window.set_focus()
}

/// Sets whether the window can be focused.
///
/// ## Platform-specific
///
/// - **macOS**: If the window is already focused, it is not possible to unfocus it after calling `set_focusable(false)`.
/// In this case, you might consider calling [`Window::set_focus`] but it will move the window to the back i.e. at the bottom in terms of z-order.
pub fn set_focusable(&self, focusable: bool) -> crate::Result<()> {
self.window.set_focusable(focusable)
}

/// Sets this window' icon.
pub fn set_icon(&self, icon: Image<'_>) -> crate::Result<()> {
self.window.set_icon(icon)
Expand Down
21 changes: 21 additions & 0 deletions crates/tauri/src/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,13 @@ impl<'a, R: Runtime, M: Manager<R>> WindowBuilder<'a, R, M> {
self
}

/// Whether the window will be focusable or not.
#[must_use]
pub fn focusable(mut self, focusable: bool) -> Self {
self.window_builder = self.window_builder.focusable(focusable);
self
}

/// Whether the window should be maximized upon creation.
#[must_use]
pub fn maximized(mut self, maximized: bool) -> Self {
Expand Down Expand Up @@ -1987,6 +1994,20 @@ tauri::Builder::default()
self.window.dispatcher.set_focus().map_err(Into::into)
}

/// Sets whether the window can be focused.
///
/// ## Platform-specific
///
/// - **macOS**: If the window is already focused, it is not possible to unfocus it after calling `set_focusable(false)`.
/// In this case, you might consider calling [`Window::set_focus`] but it will move the window to the back i.e. at the bottom in terms of z-order.
pub fn set_focusable(&self, focusable: bool) -> crate::Result<()> {
self
.window
.dispatcher
.set_focusable(focusable)
.map_err(Into::into)
}

/// Sets this window' icon.
pub fn set_icon(&self, icon: Image<'_>) -> crate::Result<()> {
self
Expand Down
2 changes: 2 additions & 0 deletions crates/tauri/src/window/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ mod desktop_commands {
setter!(set_fullscreen, bool);
setter!(set_simple_fullscreen, bool);
setter!(set_focus);
setter!(set_focusable, bool);
setter!(set_skip_taskbar, bool);
setter!(set_cursor_grab, bool);
setter!(set_cursor_visible, bool);
Expand Down Expand Up @@ -304,6 +305,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
desktop_commands::set_fullscreen,
desktop_commands::set_simple_fullscreen,
desktop_commands::set_focus,
desktop_commands::set_focusable,
desktop_commands::set_enabled,
desktop_commands::set_skip_taskbar,
desktop_commands::set_cursor_grab,
Expand Down
1 change: 1 addition & 0 deletions examples/api/src-tauri/capabilities/run-app.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"core:window:allow-set-fullscreen",
"core:window:allow-set-simple-fullscreen",
"core:window:allow-set-focus",
"core:window:allow-set-focusable",
"core:window:allow-set-skip-taskbar",
"core:window:allow-set-cursor-grab",
"core:window:allow-set-cursor-visible",
Expand Down
17 changes: 16 additions & 1 deletion examples/api/src/views/Window.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
[webview.label]: webview
})

let focusable = $state(true)

const cursorIconOptions = [
'default',
'crosshair',
Expand Down Expand Up @@ -490,6 +492,15 @@
>Request attention</button
>
<button class="btn" onclick={switchTheme}>Switch Theme ({theme})</button>
<button
class="btn"
onclick={() => {
focusable = !focusable
webviewMap[selectedWebview].setFocusable(!focusable)
}}
>
Set focusable to {!focusable}
</button>
</div>
<div class="grid cols-[repeat(auto-fill,minmax(180px,1fr))]">
<label>
Expand Down Expand Up @@ -537,7 +548,11 @@
Fullscreen
</label>
<label>
<input type="checkbox" class="checkbox" bind:checked={simpleFullscreen} />
<input
type="checkbox"
class="checkbox"
bind:checked={simpleFullscreen}
/>
Simple fullscreen
</label>
</div>
Expand Down
Loading
Loading