From 8cf4d101e014ee9b82087cd3b2e84e3f193cc46b Mon Sep 17 00:00:00 2001 From: Pavel Kuzmin Date: Fri, 25 Jul 2025 12:33:14 +0500 Subject: [PATCH 1/7] feat(menu): add support for submenu icons in Windows platform implementation --- src/platform_impl/windows/mod.rs | 44 ++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 4e081005..17180ccc 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -235,17 +235,30 @@ impl Menu { let child_ = child.borrow(); let item_type = child_.item_type(); + // Set icons for both regular menu items and submenus if matches!(item_type, MenuItemType::Icon | MenuItemType::Submenu) { let hbitmap = child_ .icon .as_ref() .map(|i| unsafe { i.inner.to_hbitmap() }) .unwrap_or(std::ptr::null_mut()); - let info = create_icon_item_info(hbitmap); + + let info = if matches!(item_type, MenuItemType::Submenu) { + create_submenu_icon_item_info(hbitmap) + } else { + create_icon_item_info(hbitmap) + }; unsafe { - SetMenuItemInfoW(self.hmenu, child_.internal_id, FALSE, &info); - SetMenuItemInfoW(self.hpopupmenu, child_.internal_id, FALSE, &info); + // For submenus, use hmenu as ID, for regular items use internal_id + let id = if matches!(item_type, MenuItemType::Submenu) { + child_.hmenu as _ + } else { + child_.internal_id() + }; + + SetMenuItemInfoW(self.hmenu, id, FALSE, &info); + SetMenuItemInfoW(self.hpopupmenu, id, FALSE, &info); }; } } @@ -795,9 +808,22 @@ impl MenuChild { let hbitmap = icon .map(|i| unsafe { i.inner.to_hbitmap() }) .unwrap_or(std::ptr::null_mut()); - let info = create_icon_item_info(hbitmap); + + let info = if matches!(self.item_type(), MenuItemType::Submenu) { + create_submenu_icon_item_info(hbitmap) + } else { + create_icon_item_info(hbitmap) + }; + for (parent, menu_bars) in &self.parents_hemnu { - unsafe { SetMenuItemInfoW(*parent, self.internal_id(), FALSE, &info) }; + // For submenus, use hmenu as ID, for regular items use internal_id + let id = if matches!(self.item_type(), MenuItemType::Submenu) { + self.hmenu as _ + } else { + self.internal_id() + }; + + unsafe { SetMenuItemInfoW(*parent, id, FALSE, &info) }; if let Some(menu_bars) = menu_bars { for hwnd in menu_bars.borrow().keys() { @@ -1080,6 +1106,14 @@ fn create_icon_item_info(hbitmap: HBITMAP) -> MENUITEMINFOW { info } +fn create_submenu_icon_item_info(hbitmap: HBITMAP) -> MENUITEMINFOW { + let mut info: MENUITEMINFOW = unsafe { std::mem::zeroed() }; + info.cbSize = std::mem::size_of::() as _; + info.fMask = MIIM_BITMAP; + info.hbmpItem = hbitmap; + info +} + fn dwrefdata_from_obj(obj: &T) -> usize { (obj as *const T) as usize } From 61b849f7dc655fb48c75e46ccbf9e978b18e00ec Mon Sep 17 00:00:00 2001 From: Pavel Kuzmin Date: Fri, 25 Jul 2025 12:33:24 +0500 Subject: [PATCH 2/7] feat(examples): add application icon to menu windows --- examples/tao.rs | 7 +++++-- examples/winit.rs | 7 +++++-- examples/wry.rs | 7 +++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/examples/tao.rs b/examples/tao.rs index afa95f68..93de5edd 100644 --- a/examples/tao.rs +++ b/examples/tao.rs @@ -78,10 +78,15 @@ fn main() { ]); } + let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); + let icon = load_icon(std::path::Path::new(path)); + let file_m = Submenu::new("&File", true); let edit_m = Submenu::new("&Edit", true); let window_m = Submenu::new("&Window", true); + window_m.set_icon(Some(icon.clone())); + menu_bar.append_items(&[&file_m, &edit_m, &window_m]); let custom_i_1 = MenuItem::with_id( @@ -91,8 +96,6 @@ fn main() { Some(Accelerator::new(Some(Modifiers::ALT), Code::KeyC)), ); - let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); - let icon = load_icon(std::path::Path::new(path)); let image_item = IconMenuItem::with_id( "image-custom-1", "Image custom 1", diff --git a/examples/winit.rs b/examples/winit.rs index 1911baea..7f628a17 100644 --- a/examples/winit.rs +++ b/examples/winit.rs @@ -186,10 +186,15 @@ impl AppMenu { menu_bar.append(&app_menu); } + let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); + let icon = load_icon(std::path::Path::new(path)); + let file_menu = Submenu::new("&File", true); let edit_menu = Submenu::new("&Edit", true); let window_menu = Submenu::new("&Window", true); + window_menu.set_icon(Some(icon.clone())); + menu_bar.append_items(&[&file_menu, &edit_menu, &window_menu]); let custom_i_1 = MenuItem::new( @@ -198,8 +203,6 @@ impl AppMenu { Some(Accelerator::new(Some(Modifiers::ALT), Code::KeyC)), ); - let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); - let icon = load_icon(std::path::Path::new(path)); let image_item = IconMenuItem::new("Image Custom 1", true, Some(icon), None); let check_custom_i_1 = CheckMenuItem::new("Check Custom 1", true, true, None); diff --git a/examples/wry.rs b/examples/wry.rs index c2ed00f7..1d86dc95 100644 --- a/examples/wry.rs +++ b/examples/wry.rs @@ -86,10 +86,15 @@ fn main() -> wry::Result<()> { .unwrap(); } + let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); + let icon = load_icon(std::path::Path::new(path)); + let file_m = Submenu::new("&File", true); let edit_m = Submenu::new("&Edit", true); let window_m = Submenu::new("&Window", true); + window_m.set_icon(Some(icon.clone())); + menu_bar .append_items(&[&file_m, &edit_m, &window_m]) .unwrap(); @@ -100,8 +105,6 @@ fn main() -> wry::Result<()> { Some(Accelerator::new(Some(Modifiers::ALT), Code::KeyC)), ); - let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); - let icon = load_icon(std::path::Path::new(path)); let image_item = IconMenuItem::new( "Image custom 1", true, From a5b7abae79a410520acbf9f0b3be21d750d386bb Mon Sep 17 00:00:00 2001 From: Pavel Kuzmin Date: Fri, 25 Jul 2025 12:33:32 +0500 Subject: [PATCH 3/7] feat(windows-common-controls): add icon loading functionality --- examples/windows-common-controls-v6/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/windows-common-controls-v6/src/main.rs b/examples/windows-common-controls-v6/src/main.rs index 21114605..8bf1fc2d 100644 --- a/examples/windows-common-controls-v6/src/main.rs +++ b/examples/windows-common-controls-v6/src/main.rs @@ -77,6 +77,9 @@ fn main() { Some(Accelerator::new(Some(Modifiers::ALT), Code::KeyC)), ); + let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); + let icon = load_icon(std::path::Path::new(path)); + let image_item = IconMenuItem::new("Image Custom 1", true, Some(icon), None); let check_custom_i_1 = CheckMenuItem::new("Check Custom 1", true, true, None); From e2f0e157d1f8cc7ba8288f5871f65fe88345e615 Mon Sep 17 00:00:00 2001 From: Pavel Kuzmin Date: Fri, 25 Jul 2025 12:55:34 +0500 Subject: [PATCH 4/7] refactor(platform_impl): simplify icon item info creation --- src/platform_impl/windows/mod.rs | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 17180ccc..d161235e 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -243,11 +243,7 @@ impl Menu { .map(|i| unsafe { i.inner.to_hbitmap() }) .unwrap_or(std::ptr::null_mut()); - let info = if matches!(item_type, MenuItemType::Submenu) { - create_submenu_icon_item_info(hbitmap) - } else { - create_icon_item_info(hbitmap) - }; + let info = create_icon_item_info(hbitmap); unsafe { // For submenus, use hmenu as ID, for regular items use internal_id @@ -809,11 +805,7 @@ impl MenuChild { .map(|i| unsafe { i.inner.to_hbitmap() }) .unwrap_or(std::ptr::null_mut()); - let info = if matches!(self.item_type(), MenuItemType::Submenu) { - create_submenu_icon_item_info(hbitmap) - } else { - create_icon_item_info(hbitmap) - }; + let info = create_icon_item_info(hbitmap); for (parent, menu_bars) in &self.parents_hemnu { // For submenus, use hmenu as ID, for regular items use internal_id @@ -1106,14 +1098,6 @@ fn create_icon_item_info(hbitmap: HBITMAP) -> MENUITEMINFOW { info } -fn create_submenu_icon_item_info(hbitmap: HBITMAP) -> MENUITEMINFOW { - let mut info: MENUITEMINFOW = unsafe { std::mem::zeroed() }; - info.cbSize = std::mem::size_of::() as _; - info.fMask = MIIM_BITMAP; - info.hbmpItem = hbitmap; - info -} - fn dwrefdata_from_obj(obj: &T) -> usize { (obj as *const T) as usize } From ef2647369e62550527785fb44f9a901d222cd24f Mon Sep 17 00:00:00 2001 From: Pavel Kuzmin Date: Sun, 27 Jul 2025 09:23:54 +0500 Subject: [PATCH 5/7] refactor(windows): simplify menu item ID handling in SetMenuItemInfoW --- src/platform_impl/windows/mod.rs | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index d161235e..9f736262 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -246,15 +246,8 @@ impl Menu { let info = create_icon_item_info(hbitmap); unsafe { - // For submenus, use hmenu as ID, for regular items use internal_id - let id = if matches!(item_type, MenuItemType::Submenu) { - child_.hmenu as _ - } else { - child_.internal_id() - }; - - SetMenuItemInfoW(self.hmenu, id, FALSE, &info); - SetMenuItemInfoW(self.hpopupmenu, id, FALSE, &info); + SetMenuItemInfoW(self.hmenu, child_.internal_id(), FALSE, &info); + SetMenuItemInfoW(self.hpopupmenu, child_.internal_id(), FALSE, &info); }; } } @@ -808,14 +801,7 @@ impl MenuChild { let info = create_icon_item_info(hbitmap); for (parent, menu_bars) in &self.parents_hemnu { - // For submenus, use hmenu as ID, for regular items use internal_id - let id = if matches!(self.item_type(), MenuItemType::Submenu) { - self.hmenu as _ - } else { - self.internal_id() - }; - - unsafe { SetMenuItemInfoW(*parent, id, FALSE, &info) }; + unsafe { SetMenuItemInfoW(*parent, self.internal_id(), FALSE, &info) }; if let Some(menu_bars) = menu_bars { for hwnd in menu_bars.borrow().keys() { From 36f6a2a22b9bd63267a8a597ff0736b7e71c2274 Mon Sep 17 00:00:00 2001 From: Pavel Kuzmin Date: Sun, 27 Jul 2025 09:26:42 +0500 Subject: [PATCH 6/7] refactor(platform_impl): simplify `internal_id()` usage in Windows menu implementation --- .changes/refactor-simplify-internal-id-usage.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changes/refactor-simplify-internal-id-usage.md diff --git a/.changes/refactor-simplify-internal-id-usage.md b/.changes/refactor-simplify-internal-id-usage.md new file mode 100644 index 00000000..2adbe3ae --- /dev/null +++ b/.changes/refactor-simplify-internal-id-usage.md @@ -0,0 +1,5 @@ +--- +"muda": patch +--- + +refactor(platform_impl): simplify internal_id() usage in Windows menu implementation From 350244217cedb75762034375e997182787d8aa68 Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Mon, 28 Jul 2025 16:43:29 +0300 Subject: [PATCH 7/7] Update .changes/refactor-simplify-internal-id-usage.md --- .changes/refactor-simplify-internal-id-usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changes/refactor-simplify-internal-id-usage.md b/.changes/refactor-simplify-internal-id-usage.md index 2adbe3ae..05b07eca 100644 --- a/.changes/refactor-simplify-internal-id-usage.md +++ b/.changes/refactor-simplify-internal-id-usage.md @@ -2,4 +2,4 @@ "muda": patch --- -refactor(platform_impl): simplify internal_id() usage in Windows menu implementation +On Windows, fix icon of `Submenu` not visible when added to a root `Menu`