From b4907570f839f201dc641642bdd71217fb039c06 Mon Sep 17 00:00:00 2001 From: amrbashir Date: Mon, 14 Oct 2024 13:32:48 +0300 Subject: [PATCH 1/2] feat(core): add `ContextMenu::hpopupmenu` on Windows closes #11339 --- .changes/hpopupmenu.md | 5 +++++ crates/tauri-cli/config.schema.json | 2 +- .../tauri-schema-generator/schemas/capability.schema.json | 2 +- crates/tauri-schema-generator/schemas/config.schema.json | 2 +- crates/tauri/src/menu/menu.rs | 5 +++++ crates/tauri/src/menu/mod.rs | 8 ++++++++ crates/tauri/src/menu/submenu.rs | 5 +++++ 7 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 .changes/hpopupmenu.md diff --git a/.changes/hpopupmenu.md b/.changes/hpopupmenu.md new file mode 100644 index 000000000000..4363d8bb8101 --- /dev/null +++ b/.changes/hpopupmenu.md @@ -0,0 +1,5 @@ +--- +"tauri": "patch:feat" +--- + +On Windows, Add `ContextMenu::hpopupmenu` method to get the [`HMENU`](https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types#HMENU) used for popups and tray icon menu. diff --git a/crates/tauri-cli/config.schema.json b/crates/tauri-cli/config.schema.json index d889051c26a0..72b53fa0a091 100644 --- a/crates/tauri-cli/config.schema.json +++ b/crates/tauri-cli/config.schema.json @@ -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 \"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", diff --git a/crates/tauri-schema-generator/schemas/capability.schema.json b/crates/tauri-schema-generator/schemas/capability.schema.json index 850d4b528a82..80df9a6893f8 100644 --- a/crates/tauri-schema-generator/schemas/capability.schema.json +++ b/crates/tauri-schema-generator/schemas/capability.schema.json @@ -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 \"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", diff --git a/crates/tauri-schema-generator/schemas/config.schema.json b/crates/tauri-schema-generator/schemas/config.schema.json index d889051c26a0..72b53fa0a091 100644 --- a/crates/tauri-schema-generator/schemas/config.schema.json +++ b/crates/tauri-schema-generator/schemas/config.schema.json @@ -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 \"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", diff --git a/crates/tauri/src/menu/menu.rs b/crates/tauri/src/menu/menu.rs index 550f0a8f0ad0..4c1849b97e5b 100644 --- a/crates/tauri/src/menu/menu.rs +++ b/crates/tauri/src/menu/menu.rs @@ -21,6 +21,11 @@ pub const WINDOW_SUBMENU_ID: &str = "__tauri_window_menu__"; pub const HELP_SUBMENU_ID: &str = "__tauri_help_menu__"; impl super::ContextMenu for Menu { + #[cfg(target_os = "windows")] + fn hpopupmenu(&self) -> crate::Result { + run_item_main_thread!(self, |self_: Self| (*self_.0).as_ref().hpopupmenu()) + } + fn popup(&self, window: Window) -> crate::Result<()> { self.popup_inner(window, None::) } diff --git a/crates/tauri/src/menu/mod.rs b/crates/tauri/src/menu/mod.rs index 7f3922263fbb..fafdea6d21ab 100644 --- a/crates/tauri/src/menu/mod.rs +++ b/crates/tauri/src/menu/mod.rs @@ -732,6 +732,14 @@ pub trait IsMenuItem: sealed::IsMenuItemBase { /// /// This trait is ONLY meant to be implemented internally by the crate. pub trait ContextMenu: sealed::ContextMenuBase + Send + Sync { + /// Get the popup [`HMENU`] for this menu. + /// + /// The returned [`HMENU`] is valid as long as the [`ContextMenu`] is. + /// + /// [`HMENU`]: https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types#HMENU + #[cfg(target_os = "windows")] + fn hpopupmenu(&self) -> crate::Result; + /// Popup this menu as a context menu on the specified window at the cursor position. fn popup(&self, window: crate::Window) -> crate::Result<()>; diff --git a/crates/tauri/src/menu/submenu.rs b/crates/tauri/src/menu/submenu.rs index 429c88403d80..1f96f718433b 100644 --- a/crates/tauri/src/menu/submenu.rs +++ b/crates/tauri/src/menu/submenu.rs @@ -13,6 +13,11 @@ use crate::{AppHandle, Manager, Position, Runtime, Window}; use muda::{ContextMenu, MenuId}; impl super::ContextMenu for Submenu { + #[cfg(target_os = "windows")] + fn hpopupmenu(&self) -> crate::Result { + run_item_main_thread!(self, |self_: Self| (*self_.0).as_ref().hpopupmenu()) + } + fn popup(&self, window: Window) -> crate::Result<()> { self.popup_inner(window, None::) } From 13e4c89a0083762d93b3ff361b3bf7be29d39f1c Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Mon, 14 Oct 2024 13:19:26 -0300 Subject: [PATCH 2/2] Update crates/tauri/src/menu/mod.rs --- crates/tauri/src/menu/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/tauri/src/menu/mod.rs b/crates/tauri/src/menu/mod.rs index fafdea6d21ab..08015d00a0ea 100644 --- a/crates/tauri/src/menu/mod.rs +++ b/crates/tauri/src/menu/mod.rs @@ -737,7 +737,8 @@ pub trait ContextMenu: sealed::ContextMenuBase + Send + Sync { /// The returned [`HMENU`] is valid as long as the [`ContextMenu`] is. /// /// [`HMENU`]: https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types#HMENU - #[cfg(target_os = "windows")] + #[cfg(windows)] + #[cfg_attr(docsrs, doc(cfg(windows)))] fn hpopupmenu(&self) -> crate::Result; /// Popup this menu as a context menu on the specified window at the cursor position.