Skip to content

Commit

Permalink
fix: fix webview not focused by default (#11569)
Browse files Browse the repository at this point in the history
* fix: fix webview not focused by default

closes #10746

* fix compile

* typo

* fix compile again

* clippy
  • Loading branch information
amrbashir authored Nov 4, 2024
1 parent 12ffc19 commit 129414f
Show file tree
Hide file tree
Showing 12 changed files with 82 additions and 24 deletions.
5 changes: 5 additions & 0 deletions .changes/webview-focus-apis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tauri": "patch:feat"
---

Add `WebviewBuilder::focused` method to choose whether to focus webview or not on creation.
7 changes: 7 additions & 0 deletions .changes/webview-window-focused.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"tauri": "patch:bug"
"tauri-runtime": "patch:bug"
"tauri-runtime-wry": "patch:bug"
---

Fix webview not focused by default.
4 changes: 2 additions & 2 deletions crates/tauri-cli/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,7 @@
]
},
"Capability": {
"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 ```",
"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 ```",
"type": "object",
"required": [
"identifier",
Expand Down Expand Up @@ -1151,7 +1151,7 @@
}
},
"permissions": {
"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 ```",
"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 ```",
"type": "array",
"items": {
"$ref": "#/definitions/PermissionEntry"
Expand Down
3 changes: 2 additions & 1 deletion crates/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,7 @@ impl WindowBuilder for WindowBuilderWrapper {
window = window
.title(config.title.to_string())
.inner_size(config.width, config.height)
.focused(config.focus)
.visible(config.visible)
.resizable(config.resizable)
.fullscreen(config.fullscreen)
Expand Down Expand Up @@ -4017,7 +4018,7 @@ fn create_webview<T: UserEvent>(

let mut webview_builder = WebViewBuilder::with_web_context(&mut web_context.inner)
.with_id(&label)
.with_focused(window.is_focused())
.with_focused(webview_attributes.focus)
.with_url(&url)
.with_transparent(webview_attributes.transparent)
.with_accept_first_mouse(webview_attributes.accept_first_mouse)
Expand Down
18 changes: 14 additions & 4 deletions crates/tauri-runtime/src/webview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ pub struct WebviewAttributes {
pub window_effects: Option<WindowEffectsConfig>,
pub incognito: bool,
pub transparent: bool,
pub focus: bool,
pub bounds: Option<Rect>,
pub auto_resize: bool,
pub proxy_url: Option<Url>,
Expand All @@ -213,8 +214,11 @@ pub struct WebviewAttributes {

impl From<&WindowConfig> for WebviewAttributes {
fn from(config: &WindowConfig) -> Self {
let mut builder = Self::new(config.url.clone());
builder = builder.incognito(config.incognito);
let mut builder = Self::new(config.url.clone())
.incognito(config.incognito)
.focused(config.focus)
.zoom_hotkeys_enabled(config.zoom_hotkeys_enabled)
.browser_extensions_enabled(config.browser_extensions_enabled);
#[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
{
builder = builder.transparent(config.transparent);
Expand All @@ -235,8 +239,6 @@ impl From<&WindowConfig> for WebviewAttributes {
if let Some(url) = &config.proxy_url {
builder = builder.proxy_url(url.to_owned());
}
builder = builder.zoom_hotkeys_enabled(config.zoom_hotkeys_enabled);
builder = builder.browser_extensions_enabled(config.browser_extensions_enabled);
builder
}
}
Expand All @@ -256,6 +258,7 @@ impl WebviewAttributes {
window_effects: None,
incognito: false,
transparent: false,
focus: true,
bounds: None,
auto_resize: false,
proxy_url: None,
Expand Down Expand Up @@ -338,6 +341,13 @@ impl WebviewAttributes {
self
}

/// Whether the webview should be focused or not.
#[must_use]
pub fn focused(mut self, focus: bool) -> Self {
self.focus = focus;
self
}

/// Sets the webview to automatically grow and shrink its size and position when the parent window resizes.
#[must_use]
pub fn auto_resize(mut self) -> Self {
Expand Down
4 changes: 2 additions & 2 deletions crates/tauri-schema-generator/schemas/capability.schema.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Capability",
"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 ```",
"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 ```",
"type": "object",
"required": [
"identifier",
Expand Down Expand Up @@ -48,7 +48,7 @@
}
},
"permissions": {
"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 ```",
"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 ```",
"type": "array",
"items": {
"$ref": "#/definitions/PermissionEntry"
Expand Down
4 changes: 2 additions & 2 deletions crates/tauri-schema-generator/schemas/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,7 @@
]
},
"Capability": {
"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 ```",
"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 ```",
"type": "object",
"required": [
"identifier",
Expand Down Expand Up @@ -1151,7 +1151,7 @@
}
},
"permissions": {
"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 ```",
"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 ```",
"type": "array",
"items": {
"$ref": "#/definitions/PermissionEntry"
Expand Down
7 changes: 7 additions & 0 deletions crates/tauri/src/webview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,13 @@ fn main() {
self
}

/// Whether the webview should be focused or not.
#[must_use]
pub fn focused(mut self, focus: bool) -> Self {
self.webview_attributes.focus = focus;
self
}

/// Sets the webview to automatically grow and shrink its size and position when the parent window resizes.
#[must_use]
pub fn auto_resize(mut self) -> Self {
Expand Down
42 changes: 31 additions & 11 deletions crates/tauri/src/webview/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ mod desktop_commands {
WebviewWindowBuilder,
};

fn default_true() -> bool {
true
}

#[derive(Debug, PartialEq, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct WebviewConfig {
Expand All @@ -35,6 +39,8 @@ mod desktop_commands {
height: f64,
#[serde(default)]
transparent: bool,
#[serde(default = "default_true")]
focus: bool,
#[serde(default)]
accept_first_mouse: bool,
window_effects: Option<WindowEffectsConfig>,
Expand All @@ -44,6 +50,23 @@ mod desktop_commands {
zoom_hotkeys_enabled: bool,
}

#[cfg(feature = "unstable")]
impl<R: Runtime> crate::webview::WebviewBuilder<R> {
fn from_webview_config(label: String, config: WebviewConfig) -> Self {
let mut builder = Self::new(label, config.url);
builder.webview_attributes.user_agent = config.user_agent;
builder.webview_attributes.drag_drop_handler_enabled =
config.drag_drop_enabled.unwrap_or(true);
builder.webview_attributes.transparent = config.transparent;
builder.webview_attributes.focus = config.focus;
builder.webview_attributes.accept_first_mouse = config.accept_first_mouse;
builder.webview_attributes.window_effects = config.window_effects;
builder.webview_attributes.incognito = config.incognito;
builder.webview_attributes.zoom_hotkeys_enabled = config.zoom_hotkeys_enabled;
builder
}
}

#[derive(Serialize)]
pub struct WebviewRef {
window_label: String,
Expand Down Expand Up @@ -89,21 +112,18 @@ mod desktop_commands {
.manager()
.get_window(&window_label)
.ok_or(crate::Error::WindowNotFound)?;
let mut builder = crate::webview::WebviewBuilder::new(label, options.url);

builder.webview_attributes.user_agent = options.user_agent;
builder.webview_attributes.drag_drop_handler_enabled =
options.drag_drop_enabled.unwrap_or(true);
builder.webview_attributes.transparent = options.transparent;
builder.webview_attributes.accept_first_mouse = options.accept_first_mouse;
builder.webview_attributes.window_effects = options.window_effects;
builder.webview_attributes.incognito = options.incognito;
builder.webview_attributes.zoom_hotkeys_enabled = options.zoom_hotkeys_enabled;
let x = options.x;
let y = options.y;
let width = options.width;
let height = options.height;

let builder = crate::webview::WebviewBuilder::from_webview_config(label, options);

window.add_child(
builder,
tauri_runtime::dpi::LogicalPosition::new(options.x, options.y),
tauri_runtime::dpi::LogicalSize::new(options.width, options.height),
tauri_runtime::dpi::LogicalPosition::new(x, y),
tauri_runtime::dpi::LogicalSize::new(width, height),
)?;

Ok(())
Expand Down
4 changes: 3 additions & 1 deletion crates/tauri/src/webview/webview_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,17 +476,19 @@ impl<'a, R: Runtime, M: Manager<R>> WebviewWindowBuilder<'a, R, M> {
#[must_use]
#[deprecated(
since = "1.2.0",
note = "The window is automatically focused by default. This function Will be removed in 2.0.0. Use `focused` instead."
note = "The window is automatically focused by default. This function Will be removed in 3.0.0. Use `focused` instead."
)]
pub fn focus(mut self) -> Self {
self.window_builder = self.window_builder.focused(true);
self.webview_builder = self.webview_builder.focused(true);
self
}

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

Expand Down
2 changes: 1 addition & 1 deletion crates/tauri/src/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ impl<'a, R: Runtime, M: Manager<R>> WindowBuilder<'a, R, M> {
#[must_use]
#[deprecated(
since = "1.2.0",
note = "The window is automatically focused by default. This function Will be removed in 2.0.0. Use `focused` instead."
note = "The window is automatically focused by default. This function Will be removed in 3.0.0. Use `focused` instead."
)]
pub fn focus(mut self) -> Self {
self.window_builder = self.window_builder.focused(true);
Expand Down
6 changes: 6 additions & 0 deletions packages/api/src/webview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,12 @@ interface WebviewOptions {
* WARNING: Using private APIs on `macOS` prevents your application from being accepted to the `App Store`.
*/
transparent?: boolean
/**
* Whether the webview should have focus or not
*
* @since 2.1.0
*/
focus?: boolean
/**
* Whether the drag and drop is enabled or not on the webview. By default it is enabled.
*
Expand Down

0 comments on commit 129414f

Please sign in to comment.