Skip to content

Commit 129414f

Browse files
authored
fix: fix webview not focused by default (#11569)
* fix: fix webview not focused by default closes #10746 * fix compile * typo * fix compile again * clippy
1 parent 12ffc19 commit 129414f

File tree

12 files changed

+82
-24
lines changed

12 files changed

+82
-24
lines changed

.changes/webview-focus-apis.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": "patch:feat"
3+
---
4+
5+
Add `WebviewBuilder::focused` method to choose whether to focus webview or not on creation.

.changes/webview-window-focused.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"tauri": "patch:bug"
3+
"tauri-runtime": "patch:bug"
4+
"tauri-runtime-wry": "patch:bug"
5+
---
6+
7+
Fix webview not focused by default.

crates/tauri-cli/config.schema.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,7 +1104,7 @@
11041104
]
11051105
},
11061106
"Capability": {
1107-
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n \"identifier\": \"main-user-files-write\",\n \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n \"windows\": [\n \"main\"\n ],\n \"permissions\": [\n \"core:default\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n },\n ],\n \"platforms\": [\"macOS\",\"windows\"]\n }\n ```",
1107+
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n \"identifier\": \"main-user-files-write\",\n \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n \"windows\": [\n \"main\"\n ],\n \"permissions\": [\n \"core:default\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n },\n ],\n \"platforms\": [\"macOS\",\"windows\"]\n }\n ```",
11081108
"type": "object",
11091109
"required": [
11101110
"identifier",
@@ -1151,7 +1151,7 @@
11511151
}
11521152
},
11531153
"permissions": {
1154-
"description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n \"core:default\",\n \"shell:allow-open\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n }\n ```",
1154+
"description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n \"core:default\",\n \"shell:allow-open\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n }\n ]\n ```",
11551155
"type": "array",
11561156
"items": {
11571157
"$ref": "#/definitions/PermissionEntry"

crates/tauri-runtime-wry/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,7 @@ impl WindowBuilder for WindowBuilderWrapper {
789789
window = window
790790
.title(config.title.to_string())
791791
.inner_size(config.width, config.height)
792+
.focused(config.focus)
792793
.visible(config.visible)
793794
.resizable(config.resizable)
794795
.fullscreen(config.fullscreen)
@@ -4017,7 +4018,7 @@ fn create_webview<T: UserEvent>(
40174018

40184019
let mut webview_builder = WebViewBuilder::with_web_context(&mut web_context.inner)
40194020
.with_id(&label)
4020-
.with_focused(window.is_focused())
4021+
.with_focused(webview_attributes.focus)
40214022
.with_url(&url)
40224023
.with_transparent(webview_attributes.transparent)
40234024
.with_accept_first_mouse(webview_attributes.accept_first_mouse)

crates/tauri-runtime/src/webview.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ pub struct WebviewAttributes {
204204
pub window_effects: Option<WindowEffectsConfig>,
205205
pub incognito: bool,
206206
pub transparent: bool,
207+
pub focus: bool,
207208
pub bounds: Option<Rect>,
208209
pub auto_resize: bool,
209210
pub proxy_url: Option<Url>,
@@ -213,8 +214,11 @@ pub struct WebviewAttributes {
213214

214215
impl From<&WindowConfig> for WebviewAttributes {
215216
fn from(config: &WindowConfig) -> Self {
216-
let mut builder = Self::new(config.url.clone());
217-
builder = builder.incognito(config.incognito);
217+
let mut builder = Self::new(config.url.clone())
218+
.incognito(config.incognito)
219+
.focused(config.focus)
220+
.zoom_hotkeys_enabled(config.zoom_hotkeys_enabled)
221+
.browser_extensions_enabled(config.browser_extensions_enabled);
218222
#[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
219223
{
220224
builder = builder.transparent(config.transparent);
@@ -235,8 +239,6 @@ impl From<&WindowConfig> for WebviewAttributes {
235239
if let Some(url) = &config.proxy_url {
236240
builder = builder.proxy_url(url.to_owned());
237241
}
238-
builder = builder.zoom_hotkeys_enabled(config.zoom_hotkeys_enabled);
239-
builder = builder.browser_extensions_enabled(config.browser_extensions_enabled);
240242
builder
241243
}
242244
}
@@ -256,6 +258,7 @@ impl WebviewAttributes {
256258
window_effects: None,
257259
incognito: false,
258260
transparent: false,
261+
focus: true,
259262
bounds: None,
260263
auto_resize: false,
261264
proxy_url: None,
@@ -338,6 +341,13 @@ impl WebviewAttributes {
338341
self
339342
}
340343

344+
/// Whether the webview should be focused or not.
345+
#[must_use]
346+
pub fn focused(mut self, focus: bool) -> Self {
347+
self.focus = focus;
348+
self
349+
}
350+
341351
/// Sets the webview to automatically grow and shrink its size and position when the parent window resizes.
342352
#[must_use]
343353
pub fn auto_resize(mut self) -> Self {

crates/tauri-schema-generator/schemas/capability.schema.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "http://json-schema.org/draft-07/schema#",
33
"title": "Capability",
4-
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n \"identifier\": \"main-user-files-write\",\n \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n \"windows\": [\n \"main\"\n ],\n \"permissions\": [\n \"core:default\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n },\n ],\n \"platforms\": [\"macOS\",\"windows\"]\n }\n ```",
4+
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n \"identifier\": \"main-user-files-write\",\n \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n \"windows\": [\n \"main\"\n ],\n \"permissions\": [\n \"core:default\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n },\n ],\n \"platforms\": [\"macOS\",\"windows\"]\n }\n ```",
55
"type": "object",
66
"required": [
77
"identifier",
@@ -48,7 +48,7 @@
4848
}
4949
},
5050
"permissions": {
51-
"description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n \"core:default\",\n \"shell:allow-open\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n }\n ```",
51+
"description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n \"core:default\",\n \"shell:allow-open\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n }\n ]\n ```",
5252
"type": "array",
5353
"items": {
5454
"$ref": "#/definitions/PermissionEntry"

crates/tauri-schema-generator/schemas/config.schema.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,7 +1104,7 @@
11041104
]
11051105
},
11061106
"Capability": {
1107-
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n \"identifier\": \"main-user-files-write\",\n \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n \"windows\": [\n \"main\"\n ],\n \"permissions\": [\n \"core:default\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n },\n ],\n \"platforms\": [\"macOS\",\"windows\"]\n }\n ```",
1107+
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n \"identifier\": \"main-user-files-write\",\n \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n \"windows\": [\n \"main\"\n ],\n \"permissions\": [\n \"core:default\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n },\n ],\n \"platforms\": [\"macOS\",\"windows\"]\n }\n ```",
11081108
"type": "object",
11091109
"required": [
11101110
"identifier",
@@ -1151,7 +1151,7 @@
11511151
}
11521152
},
11531153
"permissions": {
1154-
"description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n \"core:default\",\n \"shell:allow-open\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n }\n ```",
1154+
"description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n \"core:default\",\n \"shell:allow-open\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n }\n ]\n ```",
11551155
"type": "array",
11561156
"items": {
11571157
"$ref": "#/definitions/PermissionEntry"

crates/tauri/src/webview/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,13 @@ fn main() {
754754
self
755755
}
756756

757+
/// Whether the webview should be focused or not.
758+
#[must_use]
759+
pub fn focused(mut self, focus: bool) -> Self {
760+
self.webview_attributes.focus = focus;
761+
self
762+
}
763+
757764
/// Sets the webview to automatically grow and shrink its size and position when the parent window resizes.
758765
#[must_use]
759766
pub fn auto_resize(mut self) -> Self {

crates/tauri/src/webview/plugin.rs

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ mod desktop_commands {
2222
WebviewWindowBuilder,
2323
};
2424

25+
fn default_true() -> bool {
26+
true
27+
}
28+
2529
#[derive(Debug, PartialEq, Clone, Deserialize)]
2630
#[serde(rename_all = "camelCase")]
2731
pub struct WebviewConfig {
@@ -35,6 +39,8 @@ mod desktop_commands {
3539
height: f64,
3640
#[serde(default)]
3741
transparent: bool,
42+
#[serde(default = "default_true")]
43+
focus: bool,
3844
#[serde(default)]
3945
accept_first_mouse: bool,
4046
window_effects: Option<WindowEffectsConfig>,
@@ -44,6 +50,23 @@ mod desktop_commands {
4450
zoom_hotkeys_enabled: bool,
4551
}
4652

53+
#[cfg(feature = "unstable")]
54+
impl<R: Runtime> crate::webview::WebviewBuilder<R> {
55+
fn from_webview_config(label: String, config: WebviewConfig) -> Self {
56+
let mut builder = Self::new(label, config.url);
57+
builder.webview_attributes.user_agent = config.user_agent;
58+
builder.webview_attributes.drag_drop_handler_enabled =
59+
config.drag_drop_enabled.unwrap_or(true);
60+
builder.webview_attributes.transparent = config.transparent;
61+
builder.webview_attributes.focus = config.focus;
62+
builder.webview_attributes.accept_first_mouse = config.accept_first_mouse;
63+
builder.webview_attributes.window_effects = config.window_effects;
64+
builder.webview_attributes.incognito = config.incognito;
65+
builder.webview_attributes.zoom_hotkeys_enabled = config.zoom_hotkeys_enabled;
66+
builder
67+
}
68+
}
69+
4770
#[derive(Serialize)]
4871
pub struct WebviewRef {
4972
window_label: String,
@@ -89,21 +112,18 @@ mod desktop_commands {
89112
.manager()
90113
.get_window(&window_label)
91114
.ok_or(crate::Error::WindowNotFound)?;
92-
let mut builder = crate::webview::WebviewBuilder::new(label, options.url);
93115

94-
builder.webview_attributes.user_agent = options.user_agent;
95-
builder.webview_attributes.drag_drop_handler_enabled =
96-
options.drag_drop_enabled.unwrap_or(true);
97-
builder.webview_attributes.transparent = options.transparent;
98-
builder.webview_attributes.accept_first_mouse = options.accept_first_mouse;
99-
builder.webview_attributes.window_effects = options.window_effects;
100-
builder.webview_attributes.incognito = options.incognito;
101-
builder.webview_attributes.zoom_hotkeys_enabled = options.zoom_hotkeys_enabled;
116+
let x = options.x;
117+
let y = options.y;
118+
let width = options.width;
119+
let height = options.height;
120+
121+
let builder = crate::webview::WebviewBuilder::from_webview_config(label, options);
102122

103123
window.add_child(
104124
builder,
105-
tauri_runtime::dpi::LogicalPosition::new(options.x, options.y),
106-
tauri_runtime::dpi::LogicalSize::new(options.width, options.height),
125+
tauri_runtime::dpi::LogicalPosition::new(x, y),
126+
tauri_runtime::dpi::LogicalSize::new(width, height),
107127
)?;
108128

109129
Ok(())

crates/tauri/src/webview/webview_window.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,17 +476,19 @@ impl<'a, R: Runtime, M: Manager<R>> WebviewWindowBuilder<'a, R, M> {
476476
#[must_use]
477477
#[deprecated(
478478
since = "1.2.0",
479-
note = "The window is automatically focused by default. This function Will be removed in 2.0.0. Use `focused` instead."
479+
note = "The window is automatically focused by default. This function Will be removed in 3.0.0. Use `focused` instead."
480480
)]
481481
pub fn focus(mut self) -> Self {
482482
self.window_builder = self.window_builder.focused(true);
483+
self.webview_builder = self.webview_builder.focused(true);
483484
self
484485
}
485486

486487
/// Whether the window will be initially focused or not.
487488
#[must_use]
488489
pub fn focused(mut self, focused: bool) -> Self {
489490
self.window_builder = self.window_builder.focused(focused);
491+
self.webview_builder = self.webview_builder.focused(focused);
490492
self
491493
}
492494

0 commit comments

Comments
 (0)