From ab617f923e1374c77f1eb522a9518443d8f6d637 Mon Sep 17 00:00:00 2001 From: Daniel Faust Date: Sun, 20 Oct 2024 17:18:02 +0200 Subject: [PATCH 01/13] Export more internals so muda can be used in combination with ksni --- Cargo.toml | 1 + src/icon.rs | 12 ++++++ src/items/icon.rs | 15 ++++--- src/items/predefined.rs | 7 +++- src/items/submenu.rs | 4 ++ src/lib.rs | 8 +++- src/menu.rs | 4 ++ src/platform_impl/gtk/about_dialog.rs | 56 +++++++++++++++++++++++++++ src/platform_impl/gtk/icon.rs | 18 +++++++++ src/platform_impl/gtk/mod.rs | 46 ++++------------------ src/platform_impl/macos/mod.rs | 4 +- src/platform_impl/mod.rs | 3 ++ src/platform_impl/windows/mod.rs | 4 +- 13 files changed, 132 insertions(+), 50 deletions(-) create mode 100644 src/platform_impl/gtk/about_dialog.rs diff --git a/Cargo.toml b/Cargo.toml index 4440677f..afb764f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ features = [ [target.'cfg(target_os = "linux")'.dependencies] gtk = "0.18" libxdo = { version = "0.6.0", optional = true } +png = "0.17" [target.'cfg(target_os = "macos")'.dependencies] objc2 = "0.5.2" diff --git a/src/icon.rs b/src/icon.rs index 14294538..25bc9ec1 100644 --- a/src/icon.rs +++ b/src/icon.rs @@ -163,6 +163,18 @@ impl Icon { let win_icon = PlatformIcon::from_resource(ordinal, size)?; Ok(Icon { inner: win_icon }) } + + /// Convert the icon into a GTK pixbuf object. + #[cfg(target_os = "linux")] + pub fn to_pixbuf(&self) -> gtk::gdk_pixbuf::Pixbuf { + self.inner.to_pixbuf() + } + + /// Convert the icon into PNG. + #[cfg(target_os = "linux")] + pub fn to_png(&self) -> Vec { + self.inner.to_png() + } } /// A native Icon to be used for the menu item diff --git a/src/items/icon.rs b/src/items/icon.rs index 907a5492..daf04442 100644 --- a/src/items/icon.rs +++ b/src/items/icon.rs @@ -145,24 +145,24 @@ impl IconMenuItem { &self.id } - /// Get the text for this check menu item. + /// Get the text for this menu item. pub fn text(&self) -> String { self.inner.borrow().text() } - /// Set the text for this check menu item. `text` could optionally contain + /// Set the text for this menu item. `text` could optionally contain /// an `&` before a character to assign this character as the mnemonic - /// for this check menu item. To display a `&` without assigning a mnemenonic, use `&&`. + /// for this menu item. To display a `&` without assigning a mnemenonic, use `&&`. pub fn set_text>(&self, text: S) { self.inner.borrow_mut().set_text(text.as_ref()) } - /// Get whether this check menu item is enabled or not. + /// Get whether this menu item is enabled or not. pub fn is_enabled(&self) -> bool { self.inner.borrow().is_enabled() } - /// Enable or disable this check menu item. + /// Enable or disable this menu item. pub fn set_enabled(&self, enabled: bool) { self.inner.borrow_mut().set_enabled(enabled) } @@ -172,6 +172,11 @@ impl IconMenuItem { self.inner.borrow_mut().set_accelerator(accelerator) } + /// Get the icon for this menu item. + pub fn icon(&self) -> Option { + self.inner.borrow().icon.clone() + } + /// Change this menu item icon or remove it. pub fn set_icon(&self, icon: Option) { self.inner.borrow_mut().set_icon(icon) diff --git a/src/items/predefined.rs b/src/items/predefined.rs index 8ed4a342..53035548 100644 --- a/src/items/predefined.rs +++ b/src/items/predefined.rs @@ -34,6 +34,11 @@ impl IsMenuItem for PredefinedMenuItem { } impl PredefinedMenuItem { + /// The type of predefined menu item + pub fn predefined_item_type(&self) -> Option { + self.inner.borrow().predefined_item_type.clone() + } + /// Separator menu item pub fn separator() -> PredefinedMenuItem { PredefinedMenuItem::new::<&str>(PredefinedMenuItemType::Separator, None) @@ -241,7 +246,7 @@ fn test_about_metadata() { #[derive(Debug, Clone)] #[non_exhaustive] #[allow(clippy::large_enum_variant)] -pub(crate) enum PredefinedMenuItemType { +pub enum PredefinedMenuItemType { Separator, Copy, Cut, diff --git a/src/items/submenu.rs b/src/items/submenu.rs index 3c21c382..15ceeef3 100644 --- a/src/items/submenu.rs +++ b/src/items/submenu.rs @@ -249,6 +249,10 @@ impl ContextMenu for Submenu { self.inner.borrow_mut().gtk_context_menu() } + fn items(&self) -> Vec { + self.inner.borrow_mut().items() + } + #[cfg(target_os = "macos")] unsafe fn show_context_menu_for_nsview( &self, diff --git a/src/lib.rs b/src/lib.rs index 25773831..135b1c40 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -176,6 +176,9 @@ pub use items::*; pub use menu::*; pub use menu_id::MenuId; +#[cfg(target_os = "linux")] +pub use platform_impl::AboutDialog; + /// An enumeration of all available menu types, useful to match against /// the items returned from [`Menu::items`] or [`Submenu::items`] #[derive(Clone)] @@ -388,6 +391,9 @@ pub trait ContextMenu { #[cfg(target_os = "linux")] fn gtk_context_menu(&self) -> gtk::Menu; + /// Get all menu items as a vector of `MenuItemKind` elements. + fn items(&self) -> Vec; + /// Shows this menu as a context menu for the specified `NSView`. /// /// - `position` is relative to the window top-left corner, if `None`, the cursor position is used. @@ -457,7 +463,7 @@ impl MenuEvent { } } - pub(crate) fn send(event: MenuEvent) { + pub fn send(event: MenuEvent) { if let Some(handler) = MENU_EVENT_HANDLER.get_or_init(|| None) { handler(event); } else { diff --git a/src/menu.rs b/src/menu.rs index 8d5c79fe..d309d749 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -407,6 +407,10 @@ impl ContextMenu for Menu { self.inner.borrow_mut().gtk_context_menu() } + fn items(&self) -> Vec { + self.inner.borrow_mut().items() + } + #[cfg(target_os = "macos")] unsafe fn show_context_menu_for_nsview( &self, diff --git a/src/platform_impl/gtk/about_dialog.rs b/src/platform_impl/gtk/about_dialog.rs new file mode 100644 index 00000000..3886f1f7 --- /dev/null +++ b/src/platform_impl/gtk/about_dialog.rs @@ -0,0 +1,56 @@ +use gtk::prelude::*; + +use crate::AboutMetadata; + +/// Displays an about dialog using GTK with the provided metadata. +pub struct AboutDialog { + metadata: AboutMetadata, +} + +impl AboutDialog { + /// Create a new about dialog using `metadata` but without showing it. + pub fn new(metadata: AboutMetadata) -> AboutDialog { + AboutDialog { metadata } + } + + /// Show the about dialog and block until it is closed. + pub fn show(&self) { + let mut builder = gtk::AboutDialog::builder().modal(true).resizable(false); + + if let Some(name) = &self.metadata.name { + builder = builder.program_name(name); + } + if let Some(version) = &self.metadata.full_version() { + builder = builder.version(version); + } + if let Some(authors) = &self.metadata.authors { + builder = builder.authors(authors.clone()); + } + if let Some(comments) = &self.metadata.comments { + builder = builder.comments(comments); + } + if let Some(copyright) = &self.metadata.copyright { + builder = builder.copyright(copyright); + } + if let Some(license) = &self.metadata.license { + builder = builder.license(license); + } + if let Some(website) = &self.metadata.website { + builder = builder.website(website); + } + if let Some(website_label) = &self.metadata.website_label { + builder = builder.website_label(website_label); + } + if let Some(icon) = &self.metadata.icon { + builder = builder.logo(&icon.to_pixbuf()); + } + + let about = builder.build(); + + about.run(); + + unsafe { + about.destroy(); + } + } +} diff --git a/src/platform_impl/gtk/icon.rs b/src/platform_impl/gtk/icon.rs index 31ddd003..37ad54a5 100644 --- a/src/platform_impl/gtk/icon.rs +++ b/src/platform_impl/gtk/icon.rs @@ -2,6 +2,8 @@ // Copyright 2021-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 +use std::io::Cursor; + use gtk::gdk_pixbuf::{Colorspace, Pixbuf}; use crate::icon::BadIcon; @@ -62,4 +64,20 @@ impl PlatformIcon { .scale_simple(w, h, gtk::gdk_pixbuf::InterpType::Bilinear) .unwrap() } + + pub fn to_png(&self) -> Vec { + let mut png = Vec::new(); + + { + let mut encoder = + png::Encoder::new(Cursor::new(&mut png), self.width as _, self.height as _); + encoder.set_color(png::ColorType::Rgba); + encoder.set_depth(png::BitDepth::Eight); + + let mut writer = encoder.write_header().unwrap(); + writer.write_image_data(&self.raw).unwrap(); + } + + png + } } diff --git a/src/platform_impl/gtk/mod.rs b/src/platform_impl/gtk/mod.rs index 7a9875ab..6f694ee0 100644 --- a/src/platform_impl/gtk/mod.rs +++ b/src/platform_impl/gtk/mod.rs @@ -2,9 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +mod about_dialog; mod accelerator; mod icon; +pub use about_dialog::AboutDialog; pub(crate) use icon::PlatformIcon; use crate::{ @@ -17,7 +19,7 @@ use crate::{ }; use accelerator::{from_gtk_mnemonic, parse_accelerator, to_gtk_mnemonic}; use glib::translate::ToGlibPtr; -use gtk::{gdk, glib, prelude::*, AboutDialog, Container, Orientation}; +use gtk::{gdk, glib, prelude::*, Container, Orientation}; use std::{ cell::RefCell, collections::{hash_map::Entry, HashMap}, @@ -408,14 +410,14 @@ pub struct MenuChild { gtk_accelerator: Option<(gdk::ModifierType, u32)>, // predefined menu item fields - predefined_item_type: Option, + pub(crate) predefined_item_type: Option, // check menu item fields checked: Option>, is_syncing_checked_state: Option>, // icon menu item fields - icon: Option, + pub(crate) icon: Option, // submenu fields pub children: Option>>>, @@ -1144,42 +1146,8 @@ impl MenuChild { let item = make_item(); register_accel(&item); item.connect_activate(move |_| { - if let Some(metadata) = &metadata { - let mut builder = AboutDialog::builder().modal(true).resizable(false); - - if let Some(name) = &metadata.name { - builder = builder.program_name(name); - } - if let Some(version) = &metadata.full_version() { - builder = builder.version(version); - } - if let Some(authors) = &metadata.authors { - builder = builder.authors(authors.clone()); - } - if let Some(comments) = &metadata.comments { - builder = builder.comments(comments); - } - if let Some(copyright) = &metadata.copyright { - builder = builder.copyright(copyright); - } - if let Some(license) = &metadata.license { - builder = builder.license(license); - } - if let Some(website) = &metadata.website { - builder = builder.website(website); - } - if let Some(website_label) = &metadata.website_label { - builder = builder.website_label(website_label); - } - if let Some(icon) = &metadata.icon { - builder = builder.logo(&icon.inner.to_pixbuf()); - } - - let about = builder.build(); - about.run(); - unsafe { - about.destroy(); - } + if let Some(metadata) = metadata.clone() { + AboutDialog::new(metadata).show(); } }); item diff --git a/src/platform_impl/macos/mod.rs b/src/platform_impl/macos/mod.rs index 5c41a735..c5c07773 100644 --- a/src/platform_impl/macos/mod.rs +++ b/src/platform_impl/macos/mod.rs @@ -200,13 +200,13 @@ pub struct MenuChild { accelerator: Option, // predefined menu item fields - predefined_item_type: Option, + pub(crate) predefined_item_type: Option, // check menu item fields checked: Cell, // icon menu item fields - icon: Option, + pub(crate) icon: Option, native_icon: Option, // submenu fields diff --git a/src/platform_impl/mod.rs b/src/platform_impl/mod.rs index c6abb720..f978298d 100644 --- a/src/platform_impl/mod.rs +++ b/src/platform_impl/mod.rs @@ -12,6 +12,9 @@ mod platform; #[path = "macos/mod.rs"] mod platform; +#[cfg(target_os = "linux")] +pub use platform::AboutDialog; + use std::{ cell::{Ref, RefCell, RefMut}, rc::Rc, diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 67920ce6..78b97b99 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -465,13 +465,13 @@ pub(crate) struct MenuChild { accelerator: Option, // predefined menu item fields - predefined_item_type: Option, + pub(crate) predefined_item_type: Option, // check menu item fields checked: bool, // icon menu item fields - icon: Option, + pub(crate) icon: Option, // submenu fields hmenu: HMENU, From 88ebf9e95b48862e4f8203eb2fa048ccae0266c6 Mon Sep 17 00:00:00 2001 From: Daniel Faust Date: Sun, 10 Nov 2024 15:22:34 +0100 Subject: [PATCH 02/13] Apply review suggestions --- Cargo.toml | 1 - src/icon.rs | 6 -- src/items/icon.rs | 12 +-- src/items/predefined.rs | 122 +++++++++++++++---------------- src/lib.rs | 2 +- src/platform_impl/gtk/icon.rs | 18 ----- src/platform_impl/gtk/mod.rs | 62 ++++++++-------- src/platform_impl/macos/mod.rs | 72 +++++++++--------- src/platform_impl/windows/mod.rs | 50 ++++++------- 9 files changed, 160 insertions(+), 185 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index afb764f7..4440677f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,6 @@ features = [ [target.'cfg(target_os = "linux")'.dependencies] gtk = "0.18" libxdo = { version = "0.6.0", optional = true } -png = "0.17" [target.'cfg(target_os = "macos")'.dependencies] objc2 = "0.5.2" diff --git a/src/icon.rs b/src/icon.rs index 25bc9ec1..bcaa8567 100644 --- a/src/icon.rs +++ b/src/icon.rs @@ -169,12 +169,6 @@ impl Icon { pub fn to_pixbuf(&self) -> gtk::gdk_pixbuf::Pixbuf { self.inner.to_pixbuf() } - - /// Convert the icon into PNG. - #[cfg(target_os = "linux")] - pub fn to_png(&self) -> Vec { - self.inner.to_png() - } } /// A native Icon to be used for the menu item diff --git a/src/items/icon.rs b/src/items/icon.rs index daf04442..5f879b87 100644 --- a/src/items/icon.rs +++ b/src/items/icon.rs @@ -145,24 +145,24 @@ impl IconMenuItem { &self.id } - /// Get the text for this menu item. + /// Get the text for this icon menu item. pub fn text(&self) -> String { self.inner.borrow().text() } - /// Set the text for this menu item. `text` could optionally contain + /// Set the text for this icon menu item. `text` could optionally contain /// an `&` before a character to assign this character as the mnemonic - /// for this menu item. To display a `&` without assigning a mnemenonic, use `&&`. + /// for this icon menu item. To display a `&` without assigning a mnemenonic, use `&&`. pub fn set_text>(&self, text: S) { self.inner.borrow_mut().set_text(text.as_ref()) } - /// Get whether this menu item is enabled or not. + /// Get whether this icon menu item is enabled or not. pub fn is_enabled(&self) -> bool { self.inner.borrow().is_enabled() } - /// Enable or disable this menu item. + /// Enable or disable this icon menu item. pub fn set_enabled(&self, enabled: bool) { self.inner.borrow_mut().set_enabled(enabled) } @@ -172,7 +172,7 @@ impl IconMenuItem { self.inner.borrow_mut().set_accelerator(accelerator) } - /// Get the icon for this menu item. + /// Get the icon for this icon menu item. pub fn icon(&self) -> Option { self.inner.borrow().icon.clone() } diff --git a/src/items/predefined.rs b/src/items/predefined.rs index 53035548..ba0acceb 100644 --- a/src/items/predefined.rs +++ b/src/items/predefined.rs @@ -34,34 +34,34 @@ impl IsMenuItem for PredefinedMenuItem { } impl PredefinedMenuItem { - /// The type of predefined menu item - pub fn predefined_item_type(&self) -> Option { - self.inner.borrow().predefined_item_type.clone() + /// The kind of predefined menu item + pub fn predefined_item_kind(&self) -> Option { + self.inner.borrow().predefined_item_kind.clone() } /// Separator menu item pub fn separator() -> PredefinedMenuItem { - PredefinedMenuItem::new::<&str>(PredefinedMenuItemType::Separator, None) + PredefinedMenuItem::new::<&str>(PredefinedMenuItemKind::Separator, None) } /// Copy menu item pub fn copy(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::Copy, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::Copy, text) } /// Cut menu item pub fn cut(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::Cut, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::Cut, text) } /// Paste menu item pub fn paste(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::Paste, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::Paste, text) } /// SelectAll menu item pub fn select_all(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::SelectAll, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::SelectAll, text) } /// Undo menu item @@ -70,7 +70,7 @@ impl PredefinedMenuItem { /// /// - **Windows / Linux:** Unsupported. pub fn undo(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::Undo, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::Undo, text) } /// Redo menu item /// @@ -78,7 +78,7 @@ impl PredefinedMenuItem { /// /// - **Windows / Linux:** Unsupported. pub fn redo(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::Redo, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::Redo, text) } /// Minimize window menu item @@ -87,7 +87,7 @@ impl PredefinedMenuItem { /// /// - **Linux:** Unsupported. pub fn minimize(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::Minimize, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::Minimize, text) } /// Maximize window menu item @@ -96,7 +96,7 @@ impl PredefinedMenuItem { /// /// - **Linux:** Unsupported. pub fn maximize(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::Maximize, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::Maximize, text) } /// Fullscreen menu item @@ -105,7 +105,7 @@ impl PredefinedMenuItem { /// /// - **Windows / Linux:** Unsupported. pub fn fullscreen(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::Fullscreen, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::Fullscreen, text) } /// Hide window menu item @@ -114,7 +114,7 @@ impl PredefinedMenuItem { /// /// - **Linux:** Unsupported. pub fn hide(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::Hide, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::Hide, text) } /// Hide other windows menu item @@ -123,7 +123,7 @@ impl PredefinedMenuItem { /// /// - **Linux:** Unsupported. pub fn hide_others(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::HideOthers, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::HideOthers, text) } /// Show all app windows menu item @@ -132,7 +132,7 @@ impl PredefinedMenuItem { /// /// - **Windows / Linux:** Unsupported. pub fn show_all(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::ShowAll, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::ShowAll, text) } /// Close window menu item @@ -141,7 +141,7 @@ impl PredefinedMenuItem { /// /// - **Linux:** Unsupported. pub fn close_window(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::CloseWindow, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::CloseWindow, text) } /// Quit app menu item @@ -150,12 +150,12 @@ impl PredefinedMenuItem { /// /// - **Linux:** Unsupported. pub fn quit(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::Quit, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::Quit, text) } /// About app menu item pub fn about(text: Option<&str>, metadata: Option) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::About(metadata), text) + PredefinedMenuItem::new(PredefinedMenuItemKind::About(metadata), text) } /// Services menu item @@ -164,7 +164,7 @@ impl PredefinedMenuItem { /// /// - **Windows / Linux:** Unsupported. pub fn services(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::Services, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::Services, text) } /// 'Bring all to front' menu item @@ -173,10 +173,10 @@ impl PredefinedMenuItem { /// /// - **Windows / Linux:** Unsupported. pub fn bring_all_to_front(text: Option<&str>) -> PredefinedMenuItem { - PredefinedMenuItem::new(PredefinedMenuItemType::BringAllToFront, text) + PredefinedMenuItem::new(PredefinedMenuItemKind::BringAllToFront, text) } - fn new>(item: PredefinedMenuItemType, text: Option) -> Self { + fn new>(item: PredefinedMenuItemKind, text: Option) -> Self { let item = crate::platform_impl::MenuChild::new_predefined( item, text.map(|t| t.as_ref().to_string()), @@ -246,7 +246,7 @@ fn test_about_metadata() { #[derive(Debug, Clone)] #[non_exhaustive] #[allow(clippy::large_enum_variant)] -pub enum PredefinedMenuItemType { +pub enum PredefinedMenuItemKind { Separator, Copy, Cut, @@ -268,85 +268,85 @@ pub enum PredefinedMenuItemType { None, } -impl Default for PredefinedMenuItemType { +impl Default for PredefinedMenuItemKind { fn default() -> Self { Self::None } } -impl PredefinedMenuItemType { +impl PredefinedMenuItemKind { pub(crate) fn text(&self) -> &str { match self { - PredefinedMenuItemType::Separator => "", - PredefinedMenuItemType::Copy => "&Copy", - PredefinedMenuItemType::Cut => "Cu&t", - PredefinedMenuItemType::Paste => "&Paste", - PredefinedMenuItemType::SelectAll => "Select &All", - PredefinedMenuItemType::Undo => "Undo", - PredefinedMenuItemType::Redo => "Redo", - PredefinedMenuItemType::Minimize => "&Minimize", + PredefinedMenuItemKind::Separator => "", + PredefinedMenuItemKind::Copy => "&Copy", + PredefinedMenuItemKind::Cut => "Cu&t", + PredefinedMenuItemKind::Paste => "&Paste", + PredefinedMenuItemKind::SelectAll => "Select &All", + PredefinedMenuItemKind::Undo => "Undo", + PredefinedMenuItemKind::Redo => "Redo", + PredefinedMenuItemKind::Minimize => "&Minimize", #[cfg(target_os = "macos")] - PredefinedMenuItemType::Maximize => "Zoom", + PredefinedMenuItemKind::Maximize => "Zoom", #[cfg(not(target_os = "macos"))] - PredefinedMenuItemType::Maximize => "Ma&ximize", - PredefinedMenuItemType::Fullscreen => "Toggle Full Screen", - PredefinedMenuItemType::Hide => "&Hide", - PredefinedMenuItemType::HideOthers => "Hide Others", - PredefinedMenuItemType::ShowAll => "Show All", + PredefinedMenuItemKind::Maximize => "Ma&ximize", + PredefinedMenuItemKind::Fullscreen => "Toggle Full Screen", + PredefinedMenuItemKind::Hide => "&Hide", + PredefinedMenuItemKind::HideOthers => "Hide Others", + PredefinedMenuItemKind::ShowAll => "Show All", #[cfg(windows)] - PredefinedMenuItemType::CloseWindow => "Close", + PredefinedMenuItemKind::CloseWindow => "Close", #[cfg(not(windows))] - PredefinedMenuItemType::CloseWindow => "C&lose Window", + PredefinedMenuItemKind::CloseWindow => "C&lose Window", #[cfg(windows)] - PredefinedMenuItemType::Quit => "&Exit", + PredefinedMenuItemKind::Quit => "&Exit", #[cfg(not(windows))] - PredefinedMenuItemType::Quit => "&Quit", - PredefinedMenuItemType::About(_) => "&About", - PredefinedMenuItemType::Services => "Services", - PredefinedMenuItemType::BringAllToFront => "Bring All to Front", - PredefinedMenuItemType::None => "", + PredefinedMenuItemKind::Quit => "&Quit", + PredefinedMenuItemKind::About(_) => "&About", + PredefinedMenuItemKind::Services => "Services", + PredefinedMenuItemKind::BringAllToFront => "Bring All to Front", + PredefinedMenuItemKind::None => "", } } pub(crate) fn accelerator(&self) -> Option { match self { - PredefinedMenuItemType::Copy => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyC)), - PredefinedMenuItemType::Cut => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyX)), - PredefinedMenuItemType::Paste => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyV)), - PredefinedMenuItemType::Undo => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyZ)), + PredefinedMenuItemKind::Copy => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyC)), + PredefinedMenuItemKind::Cut => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyX)), + PredefinedMenuItemKind::Paste => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyV)), + PredefinedMenuItemKind::Undo => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyZ)), #[cfg(target_os = "macos")] - PredefinedMenuItemType::Redo => Some(Accelerator::new( + PredefinedMenuItemKind::Redo => Some(Accelerator::new( Some(CMD_OR_CTRL | Modifiers::SHIFT), Code::KeyZ, )), #[cfg(not(target_os = "macos"))] - PredefinedMenuItemType::Redo => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyY)), - PredefinedMenuItemType::SelectAll => { + PredefinedMenuItemKind::Redo => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyY)), + PredefinedMenuItemKind::SelectAll => { Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyA)) } - PredefinedMenuItemType::Minimize => { + PredefinedMenuItemKind::Minimize => { Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyM)) } #[cfg(target_os = "macos")] - PredefinedMenuItemType::Fullscreen => Some(Accelerator::new( + PredefinedMenuItemKind::Fullscreen => Some(Accelerator::new( Some(Modifiers::META | Modifiers::CONTROL), Code::KeyF, )), - PredefinedMenuItemType::Hide => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyH)), - PredefinedMenuItemType::HideOthers => Some(Accelerator::new( + PredefinedMenuItemKind::Hide => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyH)), + PredefinedMenuItemKind::HideOthers => Some(Accelerator::new( Some(CMD_OR_CTRL | Modifiers::ALT), Code::KeyH, )), #[cfg(target_os = "macos")] - PredefinedMenuItemType::CloseWindow => { + PredefinedMenuItemKind::CloseWindow => { Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyW)) } #[cfg(not(target_os = "macos"))] - PredefinedMenuItemType::CloseWindow => { + PredefinedMenuItemKind::CloseWindow => { Some(Accelerator::new(Some(Modifiers::ALT), Code::F4)) } #[cfg(target_os = "macos")] - PredefinedMenuItemType::Quit => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyQ)), + PredefinedMenuItemKind::Quit => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyQ)), _ => None, } } diff --git a/src/lib.rs b/src/lib.rs index 135b1c40..3bb1bbd1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -391,7 +391,7 @@ pub trait ContextMenu { #[cfg(target_os = "linux")] fn gtk_context_menu(&self) -> gtk::Menu; - /// Get all menu items as a vector of `MenuItemKind` elements. + /// Get all menu items within this context menu. fn items(&self) -> Vec; /// Shows this menu as a context menu for the specified `NSView`. diff --git a/src/platform_impl/gtk/icon.rs b/src/platform_impl/gtk/icon.rs index 37ad54a5..31ddd003 100644 --- a/src/platform_impl/gtk/icon.rs +++ b/src/platform_impl/gtk/icon.rs @@ -2,8 +2,6 @@ // Copyright 2021-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 -use std::io::Cursor; - use gtk::gdk_pixbuf::{Colorspace, Pixbuf}; use crate::icon::BadIcon; @@ -64,20 +62,4 @@ impl PlatformIcon { .scale_simple(w, h, gtk::gdk_pixbuf::InterpType::Bilinear) .unwrap() } - - pub fn to_png(&self) -> Vec { - let mut png = Vec::new(); - - { - let mut encoder = - png::Encoder::new(Cursor::new(&mut png), self.width as _, self.height as _); - encoder.set_color(png::ColorType::Rgba); - encoder.set_depth(png::BitDepth::Eight); - - let mut writer = encoder.write_header().unwrap(); - writer.write_image_data(&self.raw).unwrap(); - } - - png - } } diff --git a/src/platform_impl/gtk/mod.rs b/src/platform_impl/gtk/mod.rs index 6f694ee0..ffde26cb 100644 --- a/src/platform_impl/gtk/mod.rs +++ b/src/platform_impl/gtk/mod.rs @@ -33,15 +33,15 @@ macro_rules! is_item_supported { ($item:tt) => {{ let child = $item.child(); let child_ = child.borrow(); - let supported = if let Some(predefined_item_type) = &child_.predefined_item_type { + let supported = if let Some(predefined_item_kind) = &child_.predefined_item_kind { matches!( - predefined_item_type, - PredefinedMenuItemType::Separator - | PredefinedMenuItemType::Copy - | PredefinedMenuItemType::Cut - | PredefinedMenuItemType::Paste - | PredefinedMenuItemType::SelectAll - | PredefinedMenuItemType::About(_) + predefined_item_kind, + PredefinedMenuItemKind::Separator + | PredefinedMenuItemKind::Copy + | PredefinedMenuItemKind::Cut + | PredefinedMenuItemKind::Paste + | PredefinedMenuItemKind::SelectAll + | PredefinedMenuItemKind::About(_) ) } else { true @@ -410,7 +410,7 @@ pub struct MenuChild { gtk_accelerator: Option<(gdk::ModifierType, u32)>, // predefined menu item fields - pub(crate) predefined_item_type: Option, + pub(crate) predefined_item_kind: Option, // check menu item fields checked: Option>, @@ -512,7 +512,7 @@ impl MenuChild { gtk_menus: None, icon: None, is_syncing_checked_state: None, - predefined_item_type: None, + predefined_item_kind: None, } } @@ -530,20 +530,20 @@ impl MenuChild { gtk_accelerator: None, icon: None, is_syncing_checked_state: None, - predefined_item_type: None, + predefined_item_kind: None, accelerator: None, checked: None, } } - pub(crate) fn new_predefined(item_type: PredefinedMenuItemType, text: Option) -> Self { + pub(crate) fn new_predefined(item_type: PredefinedMenuItemKind, text: Option) -> Self { Self { text: text.unwrap_or_else(|| item_type.text().to_string()), enabled: true, accelerator: item_type.accelerator(), id: MenuId(COUNTER.next().to_string()), item_type: MenuItemType::Predefined, - predefined_item_type: Some(item_type), + predefined_item_kind: Some(item_type), gtk_menu_items: Rc::new(RefCell::new(HashMap::new())), accel_group: None, checked: None, @@ -578,7 +578,7 @@ impl MenuChild { gtk_menu: None, gtk_menus: None, icon: None, - predefined_item_type: None, + predefined_item_kind: None, } } @@ -604,7 +604,7 @@ impl MenuChild { gtk_menu: None, gtk_menus: None, is_syncing_checked_state: None, - predefined_item_type: None, + predefined_item_kind: None, } } @@ -630,7 +630,7 @@ impl MenuChild { gtk_menus: None, icon: None, is_syncing_checked_state: None, - predefined_item_type: None, + predefined_item_kind: None, } } } @@ -1094,7 +1094,7 @@ impl MenuChild { .as_ref() .map(parse_accelerator) .transpose()?; - let predefined_item_type = self.predefined_item_type.clone().unwrap(); + let predefined_item_kind = self.predefined_item_kind.clone().unwrap(); let make_item = || { gtk::MenuItem::builder() @@ -1117,17 +1117,17 @@ impl MenuChild { } }; - let item = match predefined_item_type { - PredefinedMenuItemType::Separator => { + let item = match predefined_item_kind { + PredefinedMenuItemKind::Separator => { gtk::SeparatorMenuItem::new().upcast::() } - PredefinedMenuItemType::Copy - | PredefinedMenuItemType::Cut - | PredefinedMenuItemType::Paste - | PredefinedMenuItemType::SelectAll => { + PredefinedMenuItemKind::Copy + | PredefinedMenuItemKind::Cut + | PredefinedMenuItemKind::Paste + | PredefinedMenuItemKind::SelectAll => { let item = make_item(); let (mods, key) = - parse_accelerator(&predefined_item_type.accelerator().unwrap()).unwrap(); + parse_accelerator(&predefined_item_kind.accelerator().unwrap()).unwrap(); item.child() .unwrap() .downcast::() @@ -1137,12 +1137,12 @@ impl MenuChild { // TODO: wayland #[cfg(feature = "libxdo")] if let Ok(xdo) = libxdo::XDo::new(None) { - let _ = xdo.send_keysequence(predefined_item_type.xdo_keys(), 0); + let _ = xdo.send_keysequence(predefined_item_kind.xdo_keys(), 0); } }); item } - PredefinedMenuItemType::About(metadata) => { + PredefinedMenuItemKind::About(metadata) => { let item = make_item(); register_accel(&item); item.connect_activate(move |_| { @@ -1415,14 +1415,14 @@ fn show_context_menu( false } -impl PredefinedMenuItemType { +impl PredefinedMenuItemKind { #[cfg(feature = "libxdo")] fn xdo_keys(&self) -> &str { match self { - PredefinedMenuItemType::Copy => "ctrl+c", - PredefinedMenuItemType::Cut => "ctrl+X", - PredefinedMenuItemType::Paste => "ctrl+v", - PredefinedMenuItemType::SelectAll => "ctrl+a", + PredefinedMenuItemKind::Copy => "ctrl+c", + PredefinedMenuItemKind::Cut => "ctrl+X", + PredefinedMenuItemKind::Paste => "ctrl+v", + PredefinedMenuItemKind::SelectAll => "ctrl+a", _ => unreachable!(), } } diff --git a/src/platform_impl/macos/mod.rs b/src/platform_impl/macos/mod.rs index c5c07773..28170b4d 100644 --- a/src/platform_impl/macos/mod.rs +++ b/src/platform_impl/macos/mod.rs @@ -200,7 +200,7 @@ pub struct MenuChild { accelerator: Option, // predefined menu item fields - pub(crate) predefined_item_type: Option, + pub(crate) predefined_item_kind: Option, // check menu item fields checked: Cell, @@ -267,7 +267,7 @@ impl MenuChild { ns_menu: None, ns_menu_items: HashMap::new(), ns_menus: None, - predefined_item_type: None, + predefined_item_kind: None, } } @@ -295,11 +295,11 @@ impl MenuChild { native_icon: None, ns_menu_items: HashMap::new(), ns_menus: Some(HashMap::new()), - predefined_item_type: None, + predefined_item_kind: None, } } - pub(crate) fn new_predefined(item_type: PredefinedMenuItemType, text: Option) -> Self { + pub(crate) fn new_predefined(item_type: PredefinedMenuItemKind, text: Option) -> Self { let text = strip_mnemonic(text.unwrap_or_else(|| { // Gets the app's name from `NSRunningApplication::localizedName`. let app_name = || unsafe { @@ -308,11 +308,11 @@ impl MenuChild { }; match item_type { - PredefinedMenuItemType::About(_) => { + PredefinedMenuItemKind::About(_) => { format!("About {}", app_name()).trim().to_string() } - PredefinedMenuItemType::Hide => format!("Hide {}", app_name()).trim().to_string(), - PredefinedMenuItemType::Quit => format!("Quit {}", app_name()).trim().to_string(), + PredefinedMenuItemKind::Hide => format!("Hide {}", app_name()).trim().to_string(), + PredefinedMenuItemKind::Quit => format!("Quit {}", app_name()).trim().to_string(), _ => item_type.text().to_string(), } })); @@ -324,7 +324,7 @@ impl MenuChild { enabled: true, id: MenuId(COUNTER.next().to_string()), accelerator, - predefined_item_type: Some(item_type), + predefined_item_kind: Some(item_type), checked: Cell::new(false), children: None, icon: None, @@ -355,7 +355,7 @@ impl MenuChild { ns_menu: None, ns_menu_items: HashMap::new(), ns_menus: None, - predefined_item_type: None, + predefined_item_kind: None, } } @@ -379,7 +379,7 @@ impl MenuChild { ns_menu: None, ns_menu_items: HashMap::new(), ns_menus: None, - predefined_item_type: None, + predefined_item_kind: None, } } @@ -403,7 +403,7 @@ impl MenuChild { ns_menu: None, ns_menu_items: HashMap::new(), ns_menus: None, - predefined_item_type: None, + predefined_item_kind: None, } } } @@ -766,14 +766,14 @@ impl MenuChild { menu_id: u32, ) -> crate::Result> { let mtm = MainThreadMarker::new().expect("can only create menu item on the main thread"); - let item_type = self.predefined_item_type.as_ref().unwrap(); + let item_type = self.predefined_item_kind.as_ref().unwrap(); let ns_menu_item = match item_type { - PredefinedMenuItemType::Separator => NSMenuItem::separatorItem(mtm), + PredefinedMenuItemKind::Separator => NSMenuItem::separatorItem(mtm), _ => { let ns_menu_item = MenuItem::create(mtm, &self.text, item_type.selector(), &self.accelerator)?; - if let PredefinedMenuItemType::About(_) = item_type { + if let PredefinedMenuItemKind::About(_) = item_type { unsafe { ns_menu_item.setTarget(Some(&ns_menu_item)); @@ -789,7 +789,7 @@ impl MenuChild { unsafe { ns_menu_item.setEnabled(self.enabled); - if let PredefinedMenuItemType::Services = item_type { + if let PredefinedMenuItemKind::Services = item_type { // we have to assign an empty menu as the app's services menu, and macOS will populate it let services_menu = NSMenu::new(mtm); NSApplication::sharedApplication(mtm).setServicesMenu(Some(&services_menu)); @@ -883,29 +883,29 @@ impl MenuChild { } } -impl PredefinedMenuItemType { +impl PredefinedMenuItemKind { pub(crate) fn selector(&self) -> Option { match self { - PredefinedMenuItemType::Separator => None, - PredefinedMenuItemType::Copy => Some(sel!(copy:)), - PredefinedMenuItemType::Cut => Some(sel!(cut:)), - PredefinedMenuItemType::Paste => Some(sel!(paste:)), - PredefinedMenuItemType::SelectAll => Some(sel!(selectAll:)), - PredefinedMenuItemType::Undo => Some(sel!(undo:)), - PredefinedMenuItemType::Redo => Some(sel!(redo:)), - PredefinedMenuItemType::Minimize => Some(sel!(performMiniaturize:)), - PredefinedMenuItemType::Maximize => Some(sel!(performZoom:)), - PredefinedMenuItemType::Fullscreen => Some(sel!(toggleFullScreen:)), - PredefinedMenuItemType::Hide => Some(sel!(hide:)), - PredefinedMenuItemType::HideOthers => Some(sel!(hideOtherApplications:)), - PredefinedMenuItemType::ShowAll => Some(sel!(unhideAllApplications:)), - PredefinedMenuItemType::CloseWindow => Some(sel!(performClose:)), - PredefinedMenuItemType::Quit => Some(sel!(terminate:)), + PredefinedMenuItemKind::Separator => None, + PredefinedMenuItemKind::Copy => Some(sel!(copy:)), + PredefinedMenuItemKind::Cut => Some(sel!(cut:)), + PredefinedMenuItemKind::Paste => Some(sel!(paste:)), + PredefinedMenuItemKind::SelectAll => Some(sel!(selectAll:)), + PredefinedMenuItemKind::Undo => Some(sel!(undo:)), + PredefinedMenuItemKind::Redo => Some(sel!(redo:)), + PredefinedMenuItemKind::Minimize => Some(sel!(performMiniaturize:)), + PredefinedMenuItemKind::Maximize => Some(sel!(performZoom:)), + PredefinedMenuItemKind::Fullscreen => Some(sel!(toggleFullScreen:)), + PredefinedMenuItemKind::Hide => Some(sel!(hide:)), + PredefinedMenuItemKind::HideOthers => Some(sel!(hideOtherApplications:)), + PredefinedMenuItemKind::ShowAll => Some(sel!(unhideAllApplications:)), + PredefinedMenuItemKind::CloseWindow => Some(sel!(performClose:)), + PredefinedMenuItemKind::Quit => Some(sel!(terminate:)), // manual implementation in `fire_menu_item_click` - PredefinedMenuItemType::About(_) => Some(sel!(fireMenuItemAction:)), - PredefinedMenuItemType::Services => None, - PredefinedMenuItemType::BringAllToFront => Some(sel!(arrangeInFront:)), - PredefinedMenuItemType::None => None, + PredefinedMenuItemKind::About(_) => Some(sel!(fireMenuItemAction:)), + PredefinedMenuItemKind::Services => None, + PredefinedMenuItemKind::BringAllToFront => Some(sel!(arrangeInFront:)), + PredefinedMenuItemKind::None => None, } } } @@ -973,7 +973,7 @@ impl MenuItem { let item = unsafe { self.ivars().get().as_ref() }.expect("MenuItem's MenuChild pointer was unset"); - if let Some(PredefinedMenuItemType::About(about_meta)) = &item.predefined_item_type { + if let Some(PredefinedMenuItemKind::About(about_meta)) = &item.predefined_item_kind { match about_meta { Some(about_meta) => { let mut keys: Vec<&NSString> = Default::default(); diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 78b97b99..18170ed4 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -14,7 +14,7 @@ use crate::{ accelerator::Accelerator, dpi::Position, icon::{Icon, NativeIcon}, - items::PredefinedMenuItemType, + items::PredefinedMenuItemKind, util::{AddOp, Counter}, AboutMetadata, IsMenuItem, MenuEvent, MenuId, MenuItemKind, MenuItemType, MenuTheme, }; @@ -67,9 +67,9 @@ macro_rules! inner_menu_child_and_flags { MenuItemKind::Predefined(i) => { let child = i.inner; let child_ = child.borrow(); - match child_.predefined_item_type.as_ref().unwrap() { - PredefinedMenuItemType::None => return Ok(()), - PredefinedMenuItemType::Separator => { + match child_.predefined_item_kind.as_ref().unwrap() { + PredefinedMenuItemKind::None => return Ok(()), + PredefinedMenuItemKind::Separator => { flags |= MF_SEPARATOR; } _ => { @@ -465,7 +465,7 @@ pub(crate) struct MenuChild { accelerator: Option, // predefined menu item fields - pub(crate) predefined_item_type: Option, + pub(crate) predefined_item_kind: Option, // check menu item fields checked: bool, @@ -514,7 +514,7 @@ impl MenuChild { id: id.unwrap_or_else(|| MenuId::new(internal_id.to_string())), accelerator, root_menu_haccel_stores: HashMap::new(), - predefined_item_type: None, + predefined_item_kind: None, icon: None, checked: false, children: None, @@ -536,14 +536,14 @@ impl MenuChild { id: id.unwrap_or_else(|| MenuId::new(internal_id.to_string())), hpopupmenu: unsafe { CreatePopupMenu() }, root_menu_haccel_stores: HashMap::new(), - predefined_item_type: None, + predefined_item_kind: None, icon: None, checked: false, accelerator: None, } } - pub fn new_predefined(item_type: PredefinedMenuItemType, text: Option) -> Self { + pub fn new_predefined(item_type: PredefinedMenuItemKind, text: Option) -> Self { let internal_id = COUNTER.next(); Self { item_type: MenuItemType::Predefined, @@ -553,7 +553,7 @@ impl MenuChild { internal_id, id: MenuId::new(internal_id.to_string()), accelerator: item_type.accelerator(), - predefined_item_type: Some(item_type), + predefined_item_kind: Some(item_type), root_menu_haccel_stores: HashMap::new(), icon: None, checked: false, @@ -581,7 +581,7 @@ impl MenuChild { accelerator, checked, root_menu_haccel_stores: HashMap::new(), - predefined_item_type: None, + predefined_item_kind: None, icon: None, children: None, hmenu: std::ptr::null_mut(), @@ -607,7 +607,7 @@ impl MenuChild { accelerator, icon, root_menu_haccel_stores: HashMap::new(), - predefined_item_type: None, + predefined_item_kind: None, checked: false, children: None, hmenu: std::ptr::null_mut(), @@ -632,7 +632,7 @@ impl MenuChild { id: id.unwrap_or_else(|| MenuId::new(internal_id.to_string())), accelerator, root_menu_haccel_stores: HashMap::new(), - predefined_item_type: None, + predefined_item_kind: None, icon: None, checked: false, children: None, @@ -1194,31 +1194,31 @@ unsafe fn menu_selected(hwnd: windows_sys::Win32::Foundation::HWND, item: &mut M item.set_checked(checked); } MenuItemType::Predefined => { - if let Some(predefined_item_type) = &item.predefined_item_type { - match predefined_item_type { - PredefinedMenuItemType::Copy => execute_edit_command(EditCommand::Copy), - PredefinedMenuItemType::Cut => execute_edit_command(EditCommand::Cut), - PredefinedMenuItemType::Paste => execute_edit_command(EditCommand::Paste), - PredefinedMenuItemType::SelectAll => { + if let Some(predefined_item_kind) = &item.predefined_item_kind { + match predefined_item_kind { + PredefinedMenuItemKind::Copy => execute_edit_command(EditCommand::Copy), + PredefinedMenuItemKind::Cut => execute_edit_command(EditCommand::Cut), + PredefinedMenuItemKind::Paste => execute_edit_command(EditCommand::Paste), + PredefinedMenuItemKind::SelectAll => { execute_edit_command(EditCommand::SelectAll) } - PredefinedMenuItemType::Separator => {} - PredefinedMenuItemType::Minimize => { + PredefinedMenuItemKind::Separator => {} + PredefinedMenuItemKind::Minimize => { ShowWindow(hwnd, SW_MINIMIZE); } - PredefinedMenuItemType::Maximize => { + PredefinedMenuItemKind::Maximize => { ShowWindow(hwnd, SW_MAXIMIZE); } - PredefinedMenuItemType::Hide => { + PredefinedMenuItemKind::Hide => { ShowWindow(hwnd, SW_HIDE); } - PredefinedMenuItemType::CloseWindow => { + PredefinedMenuItemKind::CloseWindow => { SendMessageW(hwnd, WM_CLOSE, 0, 0); } - PredefinedMenuItemType::Quit => { + PredefinedMenuItemKind::Quit => { PostQuitMessage(0); } - PredefinedMenuItemType::About(Some(ref metadata)) => { + PredefinedMenuItemKind::About(Some(ref metadata)) => { show_about_dialog(hwnd as _, metadata) } From 2ea8af714758a06863eefacde8212f53415fcb78 Mon Sep 17 00:00:00 2001 From: Daniel Faust Date: Sat, 16 Nov 2024 19:14:48 +0100 Subject: [PATCH 03/13] Add compat menu items and menu update channel --- Cargo.toml | 2 + src/items/check.rs | 84 ++++++++++++++++---- src/items/compat.rs | 119 ++++++++++++++++++++++++++++ src/items/icon.rs | 147 +++++++++++++++++++++++++++-------- src/items/mod.rs | 6 ++ src/items/normal.rs | 79 +++++++++++++++---- src/items/predefined.rs | 56 +++++++++++-- src/items/submenu.rs | 138 ++++++++++++++++++++++++++------ src/lib.rs | 39 +++++++++- src/menu.rs | 11 ++- src/platform_impl/gtk/mod.rs | 68 ++++++++++------ src/platform_impl/mod.rs | 63 +++++---------- 12 files changed, 653 insertions(+), 159 deletions(-) create mode 100644 src/items/compat.rs diff --git a/Cargo.toml b/Cargo.toml index 4440677f..1c11964e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,8 +16,10 @@ default = ["libxdo"] libxdo = ["dep:libxdo"] common-controls-v6 = [] serde = ["dep:serde", "dpi/serde"] +ksni = ["arc-swap"] [dependencies] +arc-swap = { version = "1.7.1", optional = true } crossbeam-channel = "0.5" keyboard-types = "0.7" once_cell = "1" diff --git a/src/items/check.rs b/src/items/check.rs index 8ab4a056..f1189093 100644 --- a/src/items/check.rs +++ b/src/items/check.rs @@ -4,6 +4,12 @@ use std::{cell::RefCell, mem, rc::Rc}; +#[cfg(feature = "ksni")] +use std::sync::Arc; + +#[cfg(feature = "ksni")] +use arc_swap::ArcSwap; + use crate::{accelerator::Accelerator, sealed::IsMenuItemBase, IsMenuItem, MenuId, MenuItemKind}; /// A check menu item inside a [`Menu`] or [`Submenu`] @@ -12,10 +18,12 @@ use crate::{accelerator::Accelerator, sealed::IsMenuItemBase, IsMenuItem, MenuId /// /// [`Menu`]: crate::Menu /// [`Submenu`]: crate::Submenu -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct CheckMenuItem { pub(crate) id: Rc, pub(crate) inner: Rc>, + #[cfg(feature = "ksni")] + pub(crate) compat: Arc>, } impl IsMenuItemBase for CheckMenuItem {} @@ -34,6 +42,18 @@ impl IsMenuItem for CheckMenuItem { } impl CheckMenuItem { + #[cfg(feature = "ksni")] + pub(crate) fn compat_menu_item( + item: &crate::platform_impl::MenuChild, + ) -> crate::CompatMenuItem { + crate::CompatCheckmarkItem { + id: item.id().0.clone(), + label: super::strip_accelerator(item.text()), + enabled: item.is_enabled(), + checked: item.is_checked(), + }.into() + } + /// Create a new check menu item. /// /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic @@ -44,16 +64,22 @@ impl CheckMenuItem { checked: bool, accelerator: Option, ) -> Self { - let item = crate::platform_impl::MenuChild::new_check( + let inner = crate::platform_impl::MenuChild::new_check( text.as_ref(), enabled, checked, accelerator, None, ); + + #[cfg(feature = "ksni")] + let compat = Self::compat_menu_item(&inner); + Self { - id: Rc::new(item.id().clone()), - inner: Rc::new(RefCell::new(item)), + id: Rc::new(inner.id().clone()), + inner: Rc::new(RefCell::new(inner)), + #[cfg(feature = "ksni")] + compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -69,15 +95,22 @@ impl CheckMenuItem { accelerator: Option, ) -> Self { let id = id.into(); + let inner = crate::platform_impl::MenuChild::new_check( + text.as_ref(), + enabled, + checked, + accelerator, + Some(id.clone()), + ); + + #[cfg(feature = "ksni")] + let compat = Self::compat_menu_item(&inner); + Self { - id: Rc::new(id.clone()), - inner: Rc::new(RefCell::new(crate::platform_impl::MenuChild::new_check( - text.as_ref(), - enabled, - checked, - accelerator, - Some(id), - ))), + id: Rc::new(id), + inner: Rc::new(RefCell::new(inner)), + #[cfg(feature = "ksni")] + compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -95,7 +128,14 @@ impl CheckMenuItem { /// an `&` before a character to assign this character as the mnemonic /// for this check menu item. To display a `&` without assigning a mnemenonic, use `&&`. pub fn set_text>(&self, text: S) { - self.inner.borrow_mut().set_text(text.as_ref()) + let mut inner = self.inner.borrow_mut(); + inner.set_text(text.as_ref()); + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); } /// Get whether this check menu item is enabled or not. @@ -105,7 +145,14 @@ impl CheckMenuItem { /// Enable or disable this check menu item. pub fn set_enabled(&self, enabled: bool) { - self.inner.borrow_mut().set_enabled(enabled) + let mut inner = self.inner.borrow_mut(); + inner.set_enabled(enabled); + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); } /// Set this check menu item accelerator. @@ -120,7 +167,14 @@ impl CheckMenuItem { /// Check or Uncheck this check menu item. pub fn set_checked(&self, checked: bool) { - self.inner.borrow_mut().set_checked(checked) + let mut inner = self.inner.borrow_mut(); + inner.set_checked(checked); + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); } /// Convert this menu item into its menu ID. diff --git a/src/items/compat.rs b/src/items/compat.rs new file mode 100644 index 00000000..e6e8682b --- /dev/null +++ b/src/items/compat.rs @@ -0,0 +1,119 @@ +use std::sync::Arc; + +use arc_swap::ArcSwap; + +use crate::{ContextMenu, MenuItemKind, PredefinedMenuItemKind}; + +#[derive(Debug, Clone)] +pub struct CompatStandardItem { + pub id: String, + pub label: String, + pub enabled: bool, + pub icon: Option>, + pub predefined_menu_item_kind: Option, +} + +#[derive(Debug, Clone)] +pub struct CompatCheckmarkItem { + pub id: String, + pub label: String, + pub enabled: bool, + pub checked: bool, +} + +#[derive(Debug, Clone)] +pub struct CompatSubMenuItem { + pub label: String, + pub enabled: bool, + pub submenu: Vec>>, +} + +#[allow(clippy::large_enum_variant)] +#[derive(Debug, Clone)] +pub enum CompatMenuItem { + Standard(CompatStandardItem), + Checkmark(CompatCheckmarkItem), + SubMenu(CompatSubMenuItem), + Separator, +} + +impl From for CompatMenuItem { + fn from(item: CompatStandardItem) -> Self { + CompatMenuItem::Standard(item) + } +} + +impl From for CompatMenuItem { + fn from(item: CompatCheckmarkItem) -> Self { + CompatMenuItem::Checkmark(item) + } +} + +impl From for CompatMenuItem { + fn from(item: CompatSubMenuItem) -> Self { + CompatMenuItem::SubMenu(item) + } +} + +impl From for CompatMenuItem { + fn from(item: MenuItemKind) -> Self { + match item { + MenuItemKind::MenuItem(menu_item) => CompatStandardItem { + id: menu_item.id().0.clone(), + label: strip_accelerator(menu_item.text()), + enabled: menu_item.is_enabled(), + icon: None, + predefined_menu_item_kind: None, + } + .into(), + MenuItemKind::Submenu(submenu) => CompatSubMenuItem { + label: strip_accelerator(submenu.text()), + enabled: submenu.is_enabled(), + submenu: submenu.compat_items(), + } + .into(), + MenuItemKind::Predefined(predefined_menu_item) => { + match predefined_menu_item.predefined_item_kind() { + Some(PredefinedMenuItemKind::Separator) => CompatMenuItem::Separator, + Some(predefined_menu_item_kind) => CompatStandardItem { + id: predefined_menu_item.id().0.clone(), + label: strip_accelerator(predefined_menu_item.text()), + enabled: true, + icon: None, + predefined_menu_item_kind: Some(predefined_menu_item_kind), + } + .into(), + _ => CompatStandardItem { + id: predefined_menu_item.id().0.clone(), + label: strip_accelerator(predefined_menu_item.text()), + enabled: true, + icon: None, + predefined_menu_item_kind: None, + } + .into(), + } + } + MenuItemKind::Check(check_menu_item) => CompatCheckmarkItem { + id: check_menu_item.id().0.clone(), + label: strip_accelerator(check_menu_item.text()), + enabled: check_menu_item.is_enabled(), + checked: check_menu_item.is_checked(), + } + .into(), + MenuItemKind::Icon(icon_menu_item) => CompatStandardItem { + id: icon_menu_item.id().0.clone(), + label: strip_accelerator(icon_menu_item.text()), + enabled: icon_menu_item.is_enabled(), + icon: icon_menu_item + .icon() + .map(|icon| icon.to_pixbuf().save_to_bufferv("png", &[]).unwrap()), + predefined_menu_item_kind: None, + } + .into(), + } + } +} + +pub fn strip_accelerator(text: impl AsRef) -> String { + text.as_ref().replace('&', "") +} diff --git a/src/items/icon.rs b/src/items/icon.rs index 5f879b87..6d0f0c9f 100644 --- a/src/items/icon.rs +++ b/src/items/icon.rs @@ -4,6 +4,12 @@ use std::{cell::RefCell, mem, rc::Rc}; +#[cfg(feature = "ksni")] +use std::sync::Arc; + +#[cfg(feature = "ksni")] +use arc_swap::ArcSwap; + use crate::{ accelerator::Accelerator, icon::{Icon, NativeIcon}, @@ -16,10 +22,12 @@ use crate::{ /// /// [`Menu`]: crate::Menu /// [`Submenu`]: crate::Submenu -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct IconMenuItem { pub(crate) id: Rc, pub(crate) inner: Rc>, + #[cfg(feature = "ksni")] + pub(crate) compat: Arc>, } impl IsMenuItemBase for IconMenuItem {} @@ -38,6 +46,23 @@ impl IsMenuItem for IconMenuItem { } impl IconMenuItem { + #[cfg(feature = "ksni")] + pub(crate) fn compat_menu_item( + item: &crate::platform_impl::MenuChild, + ) -> crate::CompatMenuItem { + crate::CompatStandardItem { + id: item.id().0.clone(), + label: super::strip_accelerator(item.text()), + enabled: item.is_enabled(), + icon: item + .icon + .as_ref() + .map(|icon| icon.to_pixbuf().save_to_bufferv("png", &[]).unwrap()), + predefined_menu_item_kind: None, + } + .into() + } + /// Create a new icon menu item. /// /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic @@ -48,16 +73,22 @@ impl IconMenuItem { icon: Option, accelerator: Option, ) -> Self { - let item = crate::platform_impl::MenuChild::new_icon( + let inner = crate::platform_impl::MenuChild::new_icon( text.as_ref(), enabled, icon, accelerator, None, ); + + #[cfg(feature = "ksni")] + let compat = Self::compat_menu_item(&inner); + Self { - id: Rc::new(item.id().clone()), - inner: Rc::new(RefCell::new(item)), + id: Rc::new(inner.id().clone()), + inner: Rc::new(RefCell::new(inner)), + #[cfg(feature = "ksni")] + compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -73,15 +104,22 @@ impl IconMenuItem { accelerator: Option, ) -> Self { let id = id.into(); + let inner = crate::platform_impl::MenuChild::new_icon( + text.as_ref(), + enabled, + icon, + accelerator, + Some(id.clone()), + ); + + #[cfg(feature = "ksni")] + let compat = Self::compat_menu_item(&inner); + Self { - id: Rc::new(id.clone()), - inner: Rc::new(RefCell::new(crate::platform_impl::MenuChild::new_icon( - text.as_ref(), - enabled, - icon, - accelerator, - Some(id), - ))), + id: Rc::new(id), + inner: Rc::new(RefCell::new(inner)), + #[cfg(feature = "ksni")] + compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -98,16 +136,22 @@ impl IconMenuItem { native_icon: Option, accelerator: Option, ) -> Self { - let item = crate::platform_impl::MenuChild::new_native_icon( + let inner = crate::platform_impl::MenuChild::new_native_icon( text.as_ref(), enabled, native_icon, accelerator, None, ); + + #[cfg(feature = "ksni")] + let compat = Self::compat_menu_item(&inner); + Self { - id: Rc::new(item.id().clone()), - inner: Rc::new(RefCell::new(item)), + id: Rc::new(inner.id().clone()), + inner: Rc::new(RefCell::new(inner)), + #[cfg(feature = "ksni")] + compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -126,17 +170,22 @@ impl IconMenuItem { accelerator: Option, ) -> Self { let id = id.into(); + let inner = crate::platform_impl::MenuChild::new_native_icon( + text.as_ref(), + enabled, + native_icon, + accelerator, + Some(id.clone()), + ); + + #[cfg(feature = "ksni")] + let compat = Self::compat_menu_item(&inner); + Self { - id: Rc::new(id.clone()), - inner: Rc::new(RefCell::new( - crate::platform_impl::MenuChild::new_native_icon( - text.as_ref(), - enabled, - native_icon, - accelerator, - Some(id), - ), - )), + id: Rc::new(id), + inner: Rc::new(RefCell::new(inner)), + #[cfg(feature = "ksni")] + compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -154,7 +203,14 @@ impl IconMenuItem { /// an `&` before a character to assign this character as the mnemonic /// for this icon menu item. To display a `&` without assigning a mnemenonic, use `&&`. pub fn set_text>(&self, text: S) { - self.inner.borrow_mut().set_text(text.as_ref()) + let mut inner = self.inner.borrow_mut(); + inner.set_text(text.as_ref()); + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); } /// Get whether this icon menu item is enabled or not. @@ -164,7 +220,14 @@ impl IconMenuItem { /// Enable or disable this icon menu item. pub fn set_enabled(&self, enabled: bool) { - self.inner.borrow_mut().set_enabled(enabled) + let mut inner = self.inner.borrow_mut(); + inner.set_enabled(enabled); + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); } /// Set this icon menu item accelerator. @@ -179,7 +242,14 @@ impl IconMenuItem { /// Change this menu item icon or remove it. pub fn set_icon(&self, icon: Option) { - self.inner.borrow_mut().set_icon(icon) + let mut inner = self.inner.borrow_mut(); + inner.set_icon(icon); + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); } /// Change this menu item icon to a native image or remove it. @@ -187,11 +257,26 @@ impl IconMenuItem { /// ## Platform-specific: /// /// - **Windows / Linux**: Unsupported. - pub fn set_native_icon(&self, _icon: Option) { - #[cfg(target_os = "macos")] - self.inner.borrow_mut().set_native_icon(_icon) + #[cfg(target_os = "macos")] + pub fn set_native_icon(&self, icon: Option) { + let mut item = self.inner.borrow_mut(); + item.set_native_icon(icon); + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&item))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); } + /// Change this menu item icon to a native image or remove it. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux**: Unsupported. + #[cfg(not(target_os = "macos"))] + pub fn set_native_icon(&self, _icon: Option) {} + /// Convert this menu item into its menu ID. pub fn into_id(mut self) -> MenuId { // Note: `Rc::into_inner` is available from Rust 1.70 diff --git a/src/items/mod.rs b/src/items/mod.rs index 39c9b157..d118475d 100644 --- a/src/items/mod.rs +++ b/src/items/mod.rs @@ -8,12 +8,18 @@ mod normal; mod predefined; mod submenu; +#[cfg(feature = "ksni")] +mod compat; + pub use check::*; pub use icon::*; pub use normal::*; pub use predefined::*; pub use submenu::*; +#[cfg(feature = "ksni")] +pub use compat::*; + #[cfg(test)] mod test { use crate::{CheckMenuItem, IconMenuItem, MenuId, MenuItem, PredefinedMenuItem, Submenu}; diff --git a/src/items/normal.rs b/src/items/normal.rs index 7935e7f6..0d2b5bed 100644 --- a/src/items/normal.rs +++ b/src/items/normal.rs @@ -1,15 +1,25 @@ use std::{cell::RefCell, mem, rc::Rc}; -use crate::{accelerator::Accelerator, sealed::IsMenuItemBase, IsMenuItem, MenuId, MenuItemKind}; +#[cfg(feature = "ksni")] +use std::sync::Arc; + +#[cfg(feature = "ksni")] +use arc_swap::ArcSwap; + +use crate::{ + accelerator::Accelerator, sealed::IsMenuItemBase, IsMenuItem, MenuId, MenuItemKind, +}; /// A menu item inside a [`Menu`] or [`Submenu`] and contains only text. /// /// [`Menu`]: crate::Menu /// [`Submenu`]: crate::Submenu -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct MenuItem { pub(crate) id: Rc, pub(crate) inner: Rc>, + #[cfg(feature = "ksni")] + pub(crate) compat: Arc>, } impl IsMenuItemBase for MenuItem {} @@ -28,15 +38,35 @@ impl IsMenuItem for MenuItem { } impl MenuItem { + #[cfg(feature = "ksni")] + pub(crate) fn compat_menu_item( + item: &crate::platform_impl::MenuChild, + ) -> crate::CompatMenuItem { + crate::CompatStandardItem { + id: item.id().0.clone(), + label: super::strip_accelerator(item.text()), + enabled: item.is_enabled(), + icon: None, + predefined_menu_item_kind: None, + } + .into() + } + /// Create a new menu item. /// /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic /// for this menu item. To display a `&` without assigning a mnemenonic, use `&&`. pub fn new>(text: S, enabled: bool, accelerator: Option) -> Self { - let item = crate::platform_impl::MenuChild::new(text.as_ref(), enabled, accelerator, None); + let inner = crate::platform_impl::MenuChild::new(text.as_ref(), enabled, accelerator, None); + + #[cfg(feature = "ksni")] + let compat = Self::compat_menu_item(&inner); + Self { - id: Rc::new(item.id().clone()), - inner: Rc::new(RefCell::new(item)), + id: Rc::new(inner.id().clone()), + inner: Rc::new(RefCell::new(inner)), + #[cfg(feature = "ksni")] + compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -51,14 +81,21 @@ impl MenuItem { accelerator: Option, ) -> Self { let id = id.into(); + let inner = crate::platform_impl::MenuChild::new( + text.as_ref(), + enabled, + accelerator, + Some(id.clone()), + ); + + #[cfg(feature = "ksni")] + let compat = Self::compat_menu_item(&inner); + Self { - id: Rc::new(id.clone()), - inner: Rc::new(RefCell::new(crate::platform_impl::MenuChild::new( - text.as_ref(), - enabled, - accelerator, - Some(id), - ))), + id: Rc::new(id), + inner: Rc::new(RefCell::new(inner)), + #[cfg(feature = "ksni")] + compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -76,7 +113,14 @@ impl MenuItem { /// an `&` before a character to assign this character as the mnemonic /// for this menu item. To display a `&` without assigning a mnemenonic, use `&&`. pub fn set_text>(&self, text: S) { - self.inner.borrow_mut().set_text(text.as_ref()) + let mut inner = self.inner.borrow_mut(); + inner.set_text(text.as_ref()); + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); } /// Get whether this menu item is enabled or not. @@ -86,7 +130,14 @@ impl MenuItem { /// Enable or disable this menu item. pub fn set_enabled(&self, enabled: bool) { - self.inner.borrow_mut().set_enabled(enabled) + let mut inner = self.inner.borrow_mut(); + inner.set_enabled(enabled); + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); } /// Set this menu item accelerator. diff --git a/src/items/predefined.rs b/src/items/predefined.rs index ba0acceb..50f8f06f 100644 --- a/src/items/predefined.rs +++ b/src/items/predefined.rs @@ -4,6 +4,12 @@ use std::{cell::RefCell, mem, rc::Rc}; +#[cfg(feature = "ksni")] +use std::sync::Arc; + +#[cfg(feature = "ksni")] +use arc_swap::ArcSwap; + use crate::{ accelerator::{Accelerator, CMD_OR_CTRL}, sealed::IsMenuItemBase, @@ -12,10 +18,12 @@ use crate::{ use keyboard_types::{Code, Modifiers}; /// A predefined (native) menu item which has a predfined behavior by the OS or by this crate. -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct PredefinedMenuItem { pub(crate) id: Rc, pub(crate) inner: Rc>, + #[cfg(feature = "ksni")] + pub(crate) compat: Arc>, } impl IsMenuItemBase for PredefinedMenuItem {} @@ -34,6 +42,31 @@ impl IsMenuItem for PredefinedMenuItem { } impl PredefinedMenuItem { + #[cfg(feature = "ksni")] + pub(crate) fn compat_menu_item( + item: &crate::platform_impl::MenuChild, + ) -> crate::CompatMenuItem { + match &item.predefined_item_kind { + Some(PredefinedMenuItemKind::Separator) => crate::CompatMenuItem::Separator, + Some(predefined_menu_item_kind) => crate::CompatStandardItem { + id: item.id().0.clone(), + label: super::strip_accelerator(item.text()), + enabled: true, + icon: None, + predefined_menu_item_kind: Some(predefined_menu_item_kind.clone()), + } + .into(), + _ => crate::CompatStandardItem { + id: item.id().0.clone(), + label: super::strip_accelerator(item.text()), + enabled: true, + icon: None, + predefined_menu_item_kind: None, + } + .into(), + } + } + /// The kind of predefined menu item pub fn predefined_item_kind(&self) -> Option { self.inner.borrow().predefined_item_kind.clone() @@ -177,13 +210,19 @@ impl PredefinedMenuItem { } fn new>(item: PredefinedMenuItemKind, text: Option) -> Self { - let item = crate::platform_impl::MenuChild::new_predefined( + let inner = crate::platform_impl::MenuChild::new_predefined( item, text.map(|t| t.as_ref().to_string()), ); + + #[cfg(feature = "ksni")] + let compat = Self::compat_menu_item(&inner); + Self { - id: Rc::new(item.id().clone()), - inner: Rc::new(RefCell::new(item)), + id: Rc::new(inner.id().clone()), + inner: Rc::new(RefCell::new(inner)), + #[cfg(feature = "ksni")] + compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -199,7 +238,14 @@ impl PredefinedMenuItem { /// Set the text for this predefined menu item. pub fn set_text>(&self, text: S) { - self.inner.borrow_mut().set_text(text.as_ref()) + let mut inner = self.inner.borrow_mut(); + inner.set_text(text.as_ref()); + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); } /// Convert this menu item into its menu ID. diff --git a/src/items/submenu.rs b/src/items/submenu.rs index 15ceeef3..647d3357 100644 --- a/src/items/submenu.rs +++ b/src/items/submenu.rs @@ -4,6 +4,12 @@ use std::{cell::RefCell, mem, rc::Rc}; +#[cfg(feature = "ksni")] +use std::sync::Arc; + +#[cfg(feature = "ksni")] +use arc_swap::ArcSwap; + use crate::{ dpi::Position, sealed::IsMenuItemBase, util::AddOp, ContextMenu, IsMenuItem, MenuId, MenuItemKind, @@ -12,10 +18,12 @@ use crate::{ /// A menu that can be added to a [`Menu`] or another [`Submenu`]. /// /// [`Menu`]: crate::Menu -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct Submenu { pub(crate) id: Rc, pub(crate) inner: Rc>, + #[cfg(feature = "ksni")] + pub(crate) compat: Arc>, } impl IsMenuItemBase for Submenu {} @@ -34,15 +42,33 @@ impl IsMenuItem for Submenu { } impl Submenu { + #[cfg(feature = "ksni")] + pub(crate) fn compat_menu_item( + item: &crate::platform_impl::MenuChild, + ) -> crate::CompatMenuItem { + crate::CompatSubMenuItem { + label: super::strip_accelerator(item.text()), + enabled: item.is_enabled(), + submenu: item.compat_items(), + } + .into() + } + /// Create a new submenu. /// /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic /// for this submenu. To display a `&` without assigning a mnemenonic, use `&&`. pub fn new>(text: S, enabled: bool) -> Self { - let submenu = crate::platform_impl::MenuChild::new_submenu(text.as_ref(), enabled, None); + let item = crate::platform_impl::MenuChild::new_submenu(text.as_ref(), enabled, None); + + #[cfg(feature = "ksni")] + let compat = Self::compat_menu_item(&item); + Self { - id: Rc::new(submenu.id().clone()), - inner: Rc::new(RefCell::new(submenu)), + id: Rc::new(item.id().clone()), + inner: Rc::new(RefCell::new(item)), + #[cfg(feature = "ksni")] + compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -52,14 +78,17 @@ impl Submenu { /// for this submenu. To display a `&` without assigning a mnemenonic, use `&&`. pub fn with_id, S: AsRef>(id: I, text: S, enabled: bool) -> Self { let id = id.into(); + let item = + crate::platform_impl::MenuChild::new_submenu(text.as_ref(), enabled, Some(id.clone())); + + #[cfg(feature = "ksni")] + let compat = Self::compat_menu_item(&item); Self { - id: Rc::new(id.clone()), - inner: Rc::new(RefCell::new(crate::platform_impl::MenuChild::new_submenu( - text.as_ref(), - enabled, - Some(id), - ))), + id: Rc::new(id), + inner: Rc::new(RefCell::new(item)), + #[cfg(feature = "ksni")] + compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -93,7 +122,16 @@ impl Submenu { /// Add a menu item to the end of this menu. pub fn append(&self, item: &dyn IsMenuItem) -> crate::Result<()> { - self.inner.borrow_mut().add_menu_item(item, AddOp::Append) + let mut inner = self.inner.borrow_mut(); + inner.add_menu_item(item, AddOp::Append)?; + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); + + Ok(()) } /// Add menu items to the end of this submenu. It calls [`Submenu::append`] in a loop. @@ -107,9 +145,16 @@ impl Submenu { /// Add a menu item to the beginning of this submenu. pub fn prepend(&self, item: &dyn IsMenuItem) -> crate::Result<()> { - self.inner - .borrow_mut() - .add_menu_item(item, AddOp::Insert(0)) + let mut inner = self.inner.borrow_mut(); + inner.add_menu_item(item, AddOp::Insert(0))?; + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); + + Ok(()) } /// Add menu items to the beginning of this submenu. @@ -121,9 +166,16 @@ impl Submenu { /// Insert a menu item at the specified `postion` in the submenu. pub fn insert(&self, item: &dyn IsMenuItem, position: usize) -> crate::Result<()> { - self.inner - .borrow_mut() - .add_menu_item(item, AddOp::Insert(position)) + let mut inner = self.inner.borrow_mut(); + inner.add_menu_item(item, AddOp::Insert(position))?; + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); + + Ok(()) } /// Insert menu items at the specified `postion` in the submenu. @@ -137,7 +189,16 @@ impl Submenu { /// Remove a menu item from this submenu. pub fn remove(&self, item: &dyn IsMenuItem) -> crate::Result<()> { - self.inner.borrow_mut().remove(item) + let mut inner = self.inner.borrow_mut(); + inner.remove(item)?; + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); + + Ok(()) } /// Remove the menu item at the specified position from this submenu and returns it. @@ -166,7 +227,14 @@ impl Submenu { /// an `&` before a character to assign this character as the mnemonic /// for this submenu. To display a `&` without assigning a mnemenonic, use `&&`. pub fn set_text>(&self, text: S) { - self.inner.borrow_mut().set_text(text.as_ref()) + let mut inner = self.inner.borrow_mut(); + inner.set_text(text.as_ref()); + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); } /// Get whether this submenu is enabled or not. @@ -176,7 +244,14 @@ impl Submenu { /// Enable or disable this submenu. pub fn set_enabled(&self, enabled: bool) { - self.inner.borrow_mut().set_enabled(enabled) + let mut inner = self.inner.borrow_mut(); + inner.set_enabled(enabled); + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); } /// Set this submenu as the Window menu for the application on macOS. @@ -185,7 +260,14 @@ impl Submenu { /// certain other items to the menu. #[cfg(target_os = "macos")] pub fn set_as_windows_menu_for_nsapp(&self) { - self.inner.borrow_mut().set_as_windows_menu_for_nsapp() + let mut inner = self.inner.borrow_mut(); + inner.set_as_windows_menu_for_nsapp(); + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); } /// Set this submenu as the Help menu for the application on macOS. @@ -196,7 +278,14 @@ impl Submenu { /// which has a title matching the localized word "Help". #[cfg(target_os = "macos")] pub fn set_as_help_menu_for_nsapp(&self) { - self.inner.borrow_mut().set_as_help_menu_for_nsapp() + let mut inner = self.inner.borrow_mut(); + inner.set_as_help_menu_for_nsapp(); + + #[cfg(feature = "ksni")] + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + + #[cfg(feature = "ksni")] + crate::send_menu_update(); } /// Convert this submenu into its menu ID. @@ -249,8 +338,9 @@ impl ContextMenu for Submenu { self.inner.borrow_mut().gtk_context_menu() } - fn items(&self) -> Vec { - self.inner.borrow_mut().items() + #[cfg(feature = "ksni")] + fn compat_items(&self) -> Vec>> { + self.inner.borrow_mut().compat_items() } #[cfg(target_os = "macos")] diff --git a/src/lib.rs b/src/lib.rs index 3bb1bbd1..be9b56e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -153,6 +153,14 @@ //! [winit]: https://docs.rs/winit //! [tao]: https://docs.rs/tao +use std::{cell::RefCell, rc::Rc}; + +#[cfg(feature = "ksni")] +use std::sync::Arc; + +#[cfg(feature = "ksni")] +use arc_swap::ArcSwap; + use crossbeam_channel::{unbounded, Receiver, Sender}; use once_cell::sync::{Lazy, OnceCell}; @@ -179,9 +187,11 @@ pub use menu_id::MenuId; #[cfg(target_os = "linux")] pub use platform_impl::AboutDialog; +use platform_impl::MenuChild; + /// An enumeration of all available menu types, useful to match against /// the items returned from [`Menu::items`] or [`Submenu::items`] -#[derive(Clone)] +#[derive(Debug, Clone)] pub enum MenuItemKind { MenuItem(MenuItem), Submenu(Submenu), @@ -292,6 +302,17 @@ impl MenuItemKind { MenuItemKind::Icon(i) => i.into_id(), } } + + /// Get the menu items inner value + pub(crate) fn inner(&self) -> Rc> { + match self { + MenuItemKind::MenuItem(i) => i.inner.clone(), + MenuItemKind::Submenu(i) => i.inner.clone(), + MenuItemKind::Predefined(i) => i.inner.clone(), + MenuItemKind::Check(i) => i.inner.clone(), + MenuItemKind::Icon(i) => i.inner.clone(), + } + } } /// A trait that defines a generic item in a menu, which may be one of [`MenuItemKind`] @@ -392,7 +413,8 @@ pub trait ContextMenu { fn gtk_context_menu(&self) -> gtk::Menu; /// Get all menu items within this context menu. - fn items(&self) -> Vec; + #[cfg(feature = "ksni")] + fn compat_items(&self) -> Vec>>; /// Shows this menu as a context menu for the specified `NSView`. /// @@ -471,3 +493,16 @@ impl MenuEvent { } } } + +#[cfg(feature = "ksni")] +static MENU_UPDATE_CHANNEL: Lazy<(Sender<()>, Receiver<()>)> = Lazy::new(unbounded); + +#[cfg(feature = "ksni")] +pub fn recv_menu_update() -> std::result::Result<(), crossbeam_channel::RecvError> { + MENU_UPDATE_CHANNEL.1.recv() +} + +#[cfg(feature = "ksni")] +pub(crate) fn send_menu_update() { + let _ = MENU_UPDATE_CHANNEL.0.send(()); +} diff --git a/src/menu.rs b/src/menu.rs index d309d749..334d3346 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -4,6 +4,12 @@ use std::{cell::RefCell, rc::Rc}; +#[cfg(feature = "ksni")] +use std::sync::Arc; + +#[cfg(feature = "ksni")] +use arc_swap::ArcSwap; + use crate::{dpi::Position, util::AddOp, ContextMenu, IsMenuItem, MenuId, MenuItemKind}; /// A root menu that can be added to a Window on Windows and Linux @@ -407,8 +413,9 @@ impl ContextMenu for Menu { self.inner.borrow_mut().gtk_context_menu() } - fn items(&self) -> Vec { - self.inner.borrow_mut().items() + #[cfg(feature = "ksni")] + fn compat_items(&self) -> Vec>> { + self.inner.borrow_mut().compat_items() } #[cfg(target_os = "macos")] diff --git a/src/platform_impl/gtk/mod.rs b/src/platform_impl/gtk/mod.rs index ffde26cb..7a741119 100644 --- a/src/platform_impl/gtk/mod.rs +++ b/src/platform_impl/gtk/mod.rs @@ -27,6 +27,12 @@ use std::{ sync::atomic::{AtomicBool, Ordering}, }; +#[cfg(feature = "ksni")] +use std::sync::Arc; + +#[cfg(feature = "ksni")] +use arc_swap::ArcSwap; + static COUNTER: Counter = Counter::new(); macro_rules! is_item_supported { @@ -61,7 +67,7 @@ macro_rules! return_if_item_not_supported { pub struct Menu { id: MenuId, - children: Vec>>, + children: Vec, // TODO: maybe save a reference to the window? gtk_menubars: HashMap, accel_group: Option, @@ -123,8 +129,8 @@ impl Menu { } match op { - AddOp::Append => self.children.push(item.child()), - AddOp::Insert(position) => self.children.insert(position, item.child()), + AddOp::Append => self.children.push(item.kind()), + AddOp::Insert(position) => self.children.insert(position, item.kind()), } Ok(()) @@ -172,7 +178,7 @@ impl Menu { let index = self .children .iter() - .position(|e| e.borrow().id == item.id()) + .position(|e| e.id() == item.id()) .ok_or(crate::Error::NotAChildOfThisMenu)?; if remove_from_cache { self.children.remove(index) @@ -191,9 +197,8 @@ impl Menu { if id.map(|i| i == *menu_id).unwrap_or(true) { // bail this is not a supported item like a close_window predefined menu item if is_item_supported!(item) { - let mut child_ = child.borrow_mut(); - - if child_.item_type == MenuItemType::Submenu { + if let MenuItemKind::Submenu(child) = &child { + let mut child_ = child.inner.borrow_mut(); let menus = child_.gtk_menus.as_ref().unwrap().get(menu_id).cloned(); if let Some(menus) = menus { for (id, menu) in menus { @@ -208,6 +213,9 @@ impl Menu { child_.gtk_menus.as_mut().unwrap().remove(menu_id); } + let child = child.inner(); + let child_ = child.borrow(); + // remove all the gtk items that are related to this gtk menubar and destroy it if let Some(items) = child_.gtk_menu_items.borrow_mut().remove(menu_id) { for item in items { @@ -227,7 +235,8 @@ impl Menu { // remove from the gtk menu assigned to the context menu if remove_from_cache { if let (id, Some(menu)) = &self.gtk_menu { - let child_ = child.borrow_mut(); + let child = child.inner(); + let child_ = child.borrow(); if let Some(items) = child_.gtk_menu_items.borrow_mut().remove(id) { for item in items { menu.remove(&item); @@ -245,10 +254,13 @@ impl Menu { } pub fn items(&self) -> Vec { - self.children - .iter() - .map(|c| c.borrow().kind(c.clone())) - .collect() + self.children.to_vec() + } + + /// Returns a list of menu items that has been added to this menu. + #[cfg(feature = "ksni")] + pub fn compat_items(&self) -> Vec>> { + self.children.iter().map(MenuItemKind::compat_child).collect() } pub fn init_for_gtk_window( @@ -420,7 +432,7 @@ pub struct MenuChild { pub(crate) icon: Option, // submenu fields - pub children: Option>>>, + pub children: Option>, gtk_menus: Option>>, gtk_menu: Option<(u32, Option)>, // dedicated menu for tray or context menus accel_group: Option, @@ -458,9 +470,10 @@ impl Drop for MenuChild { fn drop_children_from_menu_and_destroy( id: u32, menu: &impl IsA, - children: &Vec>>, + children: &[MenuItemKind], ) { for child in children { + let child = child.inner(); let mut child_ = child.borrow_mut(); { let mut menu_items = child_.gtk_menu_items.borrow_mut(); @@ -809,12 +822,12 @@ impl MenuChild { } match op { - AddOp::Append => self.children.as_mut().unwrap().push(item.child()), + AddOp::Append => self.children.as_mut().unwrap().push(item.kind()), AddOp::Insert(position) => self .children .as_mut() .unwrap() - .insert(position, item.child()), + .insert(position, item.kind()), } Ok(()) @@ -866,7 +879,7 @@ impl MenuChild { .as_ref() .unwrap() .iter() - .position(|e| e.borrow().id == item.id()) + .position(|e| e.id() == item.id()) .ok_or(crate::Error::NotAChildOfThisMenu)?; if remove_from_cache { self.children.as_mut().unwrap().remove(index) @@ -886,9 +899,8 @@ impl MenuChild { if id.map(|i| i == *menu_id).unwrap_or(true) { // bail this is not a supported item like a close_window predefined menu item if is_item_supported!(item) { - let mut child_ = child.borrow_mut(); - - if child_.item_type == MenuItemType::Submenu { + if let MenuItemKind::Submenu(child) = &child { + let mut child_ = child.inner.borrow_mut(); let menus = child_.gtk_menus.as_ref().unwrap().get(menu_id).cloned(); if let Some(menus) = menus { for (id, menu) in menus { @@ -903,6 +915,9 @@ impl MenuChild { child_.gtk_menus.as_mut().unwrap().remove(menu_id); } + let child = child.inner(); + let child_ = child.borrow(); + // remove all the gtk items that are related to this gtk menu and destroy it if let Some(items) = child_.gtk_menu_items.borrow_mut().remove(menu_id) { for item in items { @@ -923,7 +938,8 @@ impl MenuChild { // remove from the gtk menu assigned to the context menu if remove_from_cache { if let (id, Some(menu)) = self.gtk_menu.as_ref().unwrap() { - let child_ = child.borrow_mut(); + let child = child.inner(); + let child_ = child.borrow(); if let Some(items) = child_.gtk_menu_items.borrow_mut().remove(id) { for item in items { menu.remove(&item); @@ -942,11 +958,19 @@ impl MenuChild { } pub fn items(&self) -> Vec { + self.children + .as_ref() + .unwrap() + .to_vec() + } + + #[cfg(feature = "ksni")] + pub fn compat_items(&self) -> Vec>> { self.children .as_ref() .unwrap() .iter() - .map(|c| c.borrow().kind(c.clone())) + .map(MenuItemKind::compat_child) .collect() } diff --git a/src/platform_impl/mod.rs b/src/platform_impl/mod.rs index f978298d..93e64078 100644 --- a/src/platform_impl/mod.rs +++ b/src/platform_impl/mod.rs @@ -20,7 +20,13 @@ use std::{ rc::Rc, }; -use crate::{items::*, IsMenuItem, MenuItemKind, MenuItemType}; +#[cfg(feature = "ksni")] +use std::sync::Arc; + +#[cfg(feature = "ksni")] +use arc_swap::ArcSwap; + +use crate::{IsMenuItem, MenuItemKind}; pub(crate) use self::platform::*; @@ -36,49 +42,6 @@ impl dyn IsMenuItem + '_ { } } -/// Internal utilities -impl MenuChild { - fn kind(&self, c: Rc>) -> MenuItemKind { - match self.item_type() { - MenuItemType::Submenu => { - let id = c.borrow().id().clone(); - MenuItemKind::Submenu(Submenu { - id: Rc::new(id), - inner: c, - }) - } - MenuItemType::MenuItem => { - let id = c.borrow().id().clone(); - MenuItemKind::MenuItem(MenuItem { - id: Rc::new(id), - inner: c, - }) - } - MenuItemType::Predefined => { - let id = c.borrow().id().clone(); - MenuItemKind::Predefined(PredefinedMenuItem { - id: Rc::new(id), - inner: c, - }) - } - MenuItemType::Check => { - let id = c.borrow().id().clone(); - MenuItemKind::Check(CheckMenuItem { - id: Rc::new(id), - inner: c, - }) - } - MenuItemType::Icon => { - let id = c.borrow().id().clone(); - MenuItemKind::Icon(IconMenuItem { - id: Rc::new(id), - inner: c, - }) - } - } - } -} - #[allow(unused)] impl MenuItemKind { pub(crate) fn as_ref(&self) -> &dyn IsMenuItem { @@ -110,4 +73,16 @@ impl MenuItemKind { MenuItemKind::Icon(i) => i.inner.borrow_mut(), } } + + #[cfg(feature = "ksni")] + pub(crate) fn compat_child(&self) -> Arc> { + use crate::items::*; + match self { + MenuItemKind::MenuItem(i) => i.compat.clone(), + MenuItemKind::Submenu(i) => i.compat.clone(), + MenuItemKind::Predefined(i) => i.compat.clone(), + MenuItemKind::Check(i) => i.compat.clone(), + MenuItemKind::Icon(i) => i.compat.clone(), + } + } } From 5b9b0fe267c240c6db1fac0e83990582fa00b62a Mon Sep 17 00:00:00 2001 From: Daniel Faust Date: Wed, 11 Dec 2024 20:52:58 +0100 Subject: [PATCH 04/13] Add send_menu_shutdown function and remove unused code --- src/items/compat.rs | 61 +-------------------------------------------- src/items/icon.rs | 6 ----- src/lib.rs | 13 +++++++--- 3 files changed, 10 insertions(+), 70 deletions(-) diff --git a/src/items/compat.rs b/src/items/compat.rs index e6e8682b..85b78935 100644 --- a/src/items/compat.rs +++ b/src/items/compat.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use arc_swap::ArcSwap; -use crate::{ContextMenu, MenuItemKind, PredefinedMenuItemKind}; +use crate::PredefinedMenuItemKind; #[derive(Debug, Clone)] pub struct CompatStandardItem { @@ -55,65 +55,6 @@ impl From for CompatMenuItem { } } -impl From for CompatMenuItem { - fn from(item: MenuItemKind) -> Self { - match item { - MenuItemKind::MenuItem(menu_item) => CompatStandardItem { - id: menu_item.id().0.clone(), - label: strip_accelerator(menu_item.text()), - enabled: menu_item.is_enabled(), - icon: None, - predefined_menu_item_kind: None, - } - .into(), - MenuItemKind::Submenu(submenu) => CompatSubMenuItem { - label: strip_accelerator(submenu.text()), - enabled: submenu.is_enabled(), - submenu: submenu.compat_items(), - } - .into(), - MenuItemKind::Predefined(predefined_menu_item) => { - match predefined_menu_item.predefined_item_kind() { - Some(PredefinedMenuItemKind::Separator) => CompatMenuItem::Separator, - Some(predefined_menu_item_kind) => CompatStandardItem { - id: predefined_menu_item.id().0.clone(), - label: strip_accelerator(predefined_menu_item.text()), - enabled: true, - icon: None, - predefined_menu_item_kind: Some(predefined_menu_item_kind), - } - .into(), - _ => CompatStandardItem { - id: predefined_menu_item.id().0.clone(), - label: strip_accelerator(predefined_menu_item.text()), - enabled: true, - icon: None, - predefined_menu_item_kind: None, - } - .into(), - } - } - MenuItemKind::Check(check_menu_item) => CompatCheckmarkItem { - id: check_menu_item.id().0.clone(), - label: strip_accelerator(check_menu_item.text()), - enabled: check_menu_item.is_enabled(), - checked: check_menu_item.is_checked(), - } - .into(), - MenuItemKind::Icon(icon_menu_item) => CompatStandardItem { - id: icon_menu_item.id().0.clone(), - label: strip_accelerator(icon_menu_item.text()), - enabled: icon_menu_item.is_enabled(), - icon: icon_menu_item - .icon() - .map(|icon| icon.to_pixbuf().save_to_bufferv("png", &[]).unwrap()), - predefined_menu_item_kind: None, - } - .into(), - } - } -} - pub fn strip_accelerator(text: impl AsRef) -> String { text.as_ref().replace('&', "") } diff --git a/src/items/icon.rs b/src/items/icon.rs index 6d0f0c9f..156d5765 100644 --- a/src/items/icon.rs +++ b/src/items/icon.rs @@ -261,12 +261,6 @@ impl IconMenuItem { pub fn set_native_icon(&self, icon: Option) { let mut item = self.inner.borrow_mut(); item.set_native_icon(icon); - - #[cfg(feature = "ksni")] - self.compat.store(Arc::new(Self::compat_menu_item(&item))); - - #[cfg(feature = "ksni")] - crate::send_menu_update(); } /// Change this menu item icon to a native image or remove it. diff --git a/src/lib.rs b/src/lib.rs index be9b56e5..6c236bae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -495,14 +495,19 @@ impl MenuEvent { } #[cfg(feature = "ksni")] -static MENU_UPDATE_CHANNEL: Lazy<(Sender<()>, Receiver<()>)> = Lazy::new(unbounded); +static MENU_UPDATE_CHANNEL: Lazy<(Sender>, Receiver>)> = Lazy::new(unbounded); #[cfg(feature = "ksni")] -pub fn recv_menu_update() -> std::result::Result<(), crossbeam_channel::RecvError> { +pub fn recv_menu_update() -> std::result::Result, crossbeam_channel::RecvError> { MENU_UPDATE_CHANNEL.1.recv() } #[cfg(feature = "ksni")] -pub(crate) fn send_menu_update() { - let _ = MENU_UPDATE_CHANNEL.0.send(()); +pub fn send_menu_update() { + let _ = MENU_UPDATE_CHANNEL.0.send(std::ops::ControlFlow::Continue(())); +} + +#[cfg(feature = "ksni")] +pub fn send_menu_shutdown() { + let _ = MENU_UPDATE_CHANNEL.0.send(std::ops::ControlFlow::Break(())); } From 9218b6dc83a4cb931646488e75cfeae8f85ca5c3 Mon Sep 17 00:00:00 2001 From: Daniel Faust Date: Thu, 12 Dec 2024 19:01:59 +0100 Subject: [PATCH 05/13] Remove ControlFlow from MENU_UPDATE_CHANNEL --- src/lib.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6c236bae..3980eda4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -495,19 +495,14 @@ impl MenuEvent { } #[cfg(feature = "ksni")] -static MENU_UPDATE_CHANNEL: Lazy<(Sender>, Receiver>)> = Lazy::new(unbounded); +static MENU_UPDATE_CHANNEL: Lazy<(Sender<()>, Receiver<()>)> = Lazy::new(unbounded); #[cfg(feature = "ksni")] -pub fn recv_menu_update() -> std::result::Result, crossbeam_channel::RecvError> { +pub fn recv_menu_update() -> std::result::Result<(), crossbeam_channel::RecvError> { MENU_UPDATE_CHANNEL.1.recv() } #[cfg(feature = "ksni")] pub fn send_menu_update() { - let _ = MENU_UPDATE_CHANNEL.0.send(std::ops::ControlFlow::Continue(())); -} - -#[cfg(feature = "ksni")] -pub fn send_menu_shutdown() { - let _ = MENU_UPDATE_CHANNEL.0.send(std::ops::ControlFlow::Break(())); + let _ = MENU_UPDATE_CHANNEL.0.send(()); } From 9a788cd2a5febe7b6202288ebc2279e7058216e8 Mon Sep 17 00:00:00 2001 From: Daniel Faust Date: Thu, 12 Dec 2024 19:02:25 +0100 Subject: [PATCH 06/13] Fix strip_accelerator and rename it to strip_mnemonic --- src/items/check.rs | 2 +- src/items/compat.rs | 7 +++++-- src/items/icon.rs | 2 +- src/items/normal.rs | 2 +- src/items/predefined.rs | 4 ++-- src/items/submenu.rs | 2 +- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/items/check.rs b/src/items/check.rs index f1189093..4a6dcb32 100644 --- a/src/items/check.rs +++ b/src/items/check.rs @@ -48,7 +48,7 @@ impl CheckMenuItem { ) -> crate::CompatMenuItem { crate::CompatCheckmarkItem { id: item.id().0.clone(), - label: super::strip_accelerator(item.text()), + label: super::strip_mnemonic(item.text()), enabled: item.is_enabled(), checked: item.is_checked(), }.into() diff --git a/src/items/compat.rs b/src/items/compat.rs index 85b78935..28797287 100644 --- a/src/items/compat.rs +++ b/src/items/compat.rs @@ -55,6 +55,9 @@ impl From for CompatMenuItem { } } -pub fn strip_accelerator(text: impl AsRef) -> String { - text.as_ref().replace('&', "") +pub fn strip_mnemonic(text: impl AsRef) -> String { + text.as_ref() + .replace("&&", "[~~]") + .replace('&', "") + .replace("[~~]", "&") } diff --git a/src/items/icon.rs b/src/items/icon.rs index 156d5765..10579526 100644 --- a/src/items/icon.rs +++ b/src/items/icon.rs @@ -52,7 +52,7 @@ impl IconMenuItem { ) -> crate::CompatMenuItem { crate::CompatStandardItem { id: item.id().0.clone(), - label: super::strip_accelerator(item.text()), + label: super::strip_mnemonic(item.text()), enabled: item.is_enabled(), icon: item .icon diff --git a/src/items/normal.rs b/src/items/normal.rs index 0d2b5bed..ce2d9b9f 100644 --- a/src/items/normal.rs +++ b/src/items/normal.rs @@ -44,7 +44,7 @@ impl MenuItem { ) -> crate::CompatMenuItem { crate::CompatStandardItem { id: item.id().0.clone(), - label: super::strip_accelerator(item.text()), + label: super::strip_mnemonic(item.text()), enabled: item.is_enabled(), icon: None, predefined_menu_item_kind: None, diff --git a/src/items/predefined.rs b/src/items/predefined.rs index 50f8f06f..86ed1b16 100644 --- a/src/items/predefined.rs +++ b/src/items/predefined.rs @@ -50,7 +50,7 @@ impl PredefinedMenuItem { Some(PredefinedMenuItemKind::Separator) => crate::CompatMenuItem::Separator, Some(predefined_menu_item_kind) => crate::CompatStandardItem { id: item.id().0.clone(), - label: super::strip_accelerator(item.text()), + label: super::strip_mnemonic(item.text()), enabled: true, icon: None, predefined_menu_item_kind: Some(predefined_menu_item_kind.clone()), @@ -58,7 +58,7 @@ impl PredefinedMenuItem { .into(), _ => crate::CompatStandardItem { id: item.id().0.clone(), - label: super::strip_accelerator(item.text()), + label: super::strip_mnemonic(item.text()), enabled: true, icon: None, predefined_menu_item_kind: None, diff --git a/src/items/submenu.rs b/src/items/submenu.rs index 647d3357..bed8e338 100644 --- a/src/items/submenu.rs +++ b/src/items/submenu.rs @@ -47,7 +47,7 @@ impl Submenu { item: &crate::platform_impl::MenuChild, ) -> crate::CompatMenuItem { crate::CompatSubMenuItem { - label: super::strip_accelerator(item.text()), + label: super::strip_mnemonic(item.text()), enabled: item.is_enabled(), submenu: item.compat_items(), } From b7993e6940c927e0c79acfa1ce602080cfdd3793 Mon Sep 17 00:00:00 2001 From: Daniel Faust Date: Thu, 12 Dec 2024 19:14:45 +0100 Subject: [PATCH 07/13] Add target_os = "linux" to feature = "ksni" cfg --- src/items/check.rs | 28 +++++++++++----------- src/items/icon.rs | 36 ++++++++++++++--------------- src/items/mod.rs | 4 ++-- src/items/normal.rs | 24 +++++++++---------- src/items/predefined.rs | 16 ++++++------- src/items/submenu.rs | 50 ++++++++++++++++++++-------------------- src/lib.rs | 12 +++++----- src/menu.rs | 6 ++--- src/platform_impl/mod.rs | 6 ++--- 9 files changed, 91 insertions(+), 91 deletions(-) diff --git a/src/items/check.rs b/src/items/check.rs index 4a6dcb32..f0fa5d6e 100644 --- a/src/items/check.rs +++ b/src/items/check.rs @@ -4,10 +4,10 @@ use std::{cell::RefCell, mem, rc::Rc}; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crate::{accelerator::Accelerator, sealed::IsMenuItemBase, IsMenuItem, MenuId, MenuItemKind}; @@ -22,7 +22,7 @@ use crate::{accelerator::Accelerator, sealed::IsMenuItemBase, IsMenuItem, MenuId pub struct CheckMenuItem { pub(crate) id: Rc, pub(crate) inner: Rc>, - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] pub(crate) compat: Arc>, } @@ -42,7 +42,7 @@ impl IsMenuItem for CheckMenuItem { } impl CheckMenuItem { - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] pub(crate) fn compat_menu_item( item: &crate::platform_impl::MenuChild, ) -> crate::CompatMenuItem { @@ -72,13 +72,13 @@ impl CheckMenuItem { None, ); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(inner.id().clone()), inner: Rc::new(RefCell::new(inner)), - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -103,13 +103,13 @@ impl CheckMenuItem { Some(id.clone()), ); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(id), inner: Rc::new(RefCell::new(inner)), - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -131,10 +131,10 @@ impl CheckMenuItem { let mut inner = self.inner.borrow_mut(); inner.set_text(text.as_ref()); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -148,10 +148,10 @@ impl CheckMenuItem { let mut inner = self.inner.borrow_mut(); inner.set_enabled(enabled); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -170,10 +170,10 @@ impl CheckMenuItem { let mut inner = self.inner.borrow_mut(); inner.set_checked(checked); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } diff --git a/src/items/icon.rs b/src/items/icon.rs index 10579526..456d1cc3 100644 --- a/src/items/icon.rs +++ b/src/items/icon.rs @@ -4,10 +4,10 @@ use std::{cell::RefCell, mem, rc::Rc}; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crate::{ @@ -26,7 +26,7 @@ use crate::{ pub struct IconMenuItem { pub(crate) id: Rc, pub(crate) inner: Rc>, - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] pub(crate) compat: Arc>, } @@ -46,7 +46,7 @@ impl IsMenuItem for IconMenuItem { } impl IconMenuItem { - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] pub(crate) fn compat_menu_item( item: &crate::platform_impl::MenuChild, ) -> crate::CompatMenuItem { @@ -81,13 +81,13 @@ impl IconMenuItem { None, ); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(inner.id().clone()), inner: Rc::new(RefCell::new(inner)), - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -112,13 +112,13 @@ impl IconMenuItem { Some(id.clone()), ); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(id), inner: Rc::new(RefCell::new(inner)), - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -144,13 +144,13 @@ impl IconMenuItem { None, ); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(inner.id().clone()), inner: Rc::new(RefCell::new(inner)), - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -178,13 +178,13 @@ impl IconMenuItem { Some(id.clone()), ); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(id), inner: Rc::new(RefCell::new(inner)), - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -206,10 +206,10 @@ impl IconMenuItem { let mut inner = self.inner.borrow_mut(); inner.set_text(text.as_ref()); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -223,10 +223,10 @@ impl IconMenuItem { let mut inner = self.inner.borrow_mut(); inner.set_enabled(enabled); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -245,10 +245,10 @@ impl IconMenuItem { let mut inner = self.inner.borrow_mut(); inner.set_icon(icon); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } diff --git a/src/items/mod.rs b/src/items/mod.rs index d118475d..23a4d847 100644 --- a/src/items/mod.rs +++ b/src/items/mod.rs @@ -8,7 +8,7 @@ mod normal; mod predefined; mod submenu; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] mod compat; pub use check::*; @@ -17,7 +17,7 @@ pub use normal::*; pub use predefined::*; pub use submenu::*; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] pub use compat::*; #[cfg(test)] diff --git a/src/items/normal.rs b/src/items/normal.rs index ce2d9b9f..a974f1b4 100644 --- a/src/items/normal.rs +++ b/src/items/normal.rs @@ -1,9 +1,9 @@ use std::{cell::RefCell, mem, rc::Rc}; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crate::{ @@ -18,7 +18,7 @@ use crate::{ pub struct MenuItem { pub(crate) id: Rc, pub(crate) inner: Rc>, - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] pub(crate) compat: Arc>, } @@ -38,7 +38,7 @@ impl IsMenuItem for MenuItem { } impl MenuItem { - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] pub(crate) fn compat_menu_item( item: &crate::platform_impl::MenuChild, ) -> crate::CompatMenuItem { @@ -59,13 +59,13 @@ impl MenuItem { pub fn new>(text: S, enabled: bool, accelerator: Option) -> Self { let inner = crate::platform_impl::MenuChild::new(text.as_ref(), enabled, accelerator, None); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(inner.id().clone()), inner: Rc::new(RefCell::new(inner)), - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -88,13 +88,13 @@ impl MenuItem { Some(id.clone()), ); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(id), inner: Rc::new(RefCell::new(inner)), - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -116,10 +116,10 @@ impl MenuItem { let mut inner = self.inner.borrow_mut(); inner.set_text(text.as_ref()); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -133,10 +133,10 @@ impl MenuItem { let mut inner = self.inner.borrow_mut(); inner.set_enabled(enabled); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } diff --git a/src/items/predefined.rs b/src/items/predefined.rs index 86ed1b16..7a1da4c8 100644 --- a/src/items/predefined.rs +++ b/src/items/predefined.rs @@ -4,10 +4,10 @@ use std::{cell::RefCell, mem, rc::Rc}; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crate::{ @@ -22,7 +22,7 @@ use keyboard_types::{Code, Modifiers}; pub struct PredefinedMenuItem { pub(crate) id: Rc, pub(crate) inner: Rc>, - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] pub(crate) compat: Arc>, } @@ -42,7 +42,7 @@ impl IsMenuItem for PredefinedMenuItem { } impl PredefinedMenuItem { - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] pub(crate) fn compat_menu_item( item: &crate::platform_impl::MenuChild, ) -> crate::CompatMenuItem { @@ -215,13 +215,13 @@ impl PredefinedMenuItem { text.map(|t| t.as_ref().to_string()), ); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(inner.id().clone()), inner: Rc::new(RefCell::new(inner)), - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -241,10 +241,10 @@ impl PredefinedMenuItem { let mut inner = self.inner.borrow_mut(); inner.set_text(text.as_ref()); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } diff --git a/src/items/submenu.rs b/src/items/submenu.rs index bed8e338..790f3dc8 100644 --- a/src/items/submenu.rs +++ b/src/items/submenu.rs @@ -4,10 +4,10 @@ use std::{cell::RefCell, mem, rc::Rc}; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crate::{ @@ -22,7 +22,7 @@ use crate::{ pub struct Submenu { pub(crate) id: Rc, pub(crate) inner: Rc>, - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] pub(crate) compat: Arc>, } @@ -42,7 +42,7 @@ impl IsMenuItem for Submenu { } impl Submenu { - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] pub(crate) fn compat_menu_item( item: &crate::platform_impl::MenuChild, ) -> crate::CompatMenuItem { @@ -61,13 +61,13 @@ impl Submenu { pub fn new>(text: S, enabled: bool) -> Self { let item = crate::platform_impl::MenuChild::new_submenu(text.as_ref(), enabled, None); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&item); Self { id: Rc::new(item.id().clone()), inner: Rc::new(RefCell::new(item)), - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -81,13 +81,13 @@ impl Submenu { let item = crate::platform_impl::MenuChild::new_submenu(text.as_ref(), enabled, Some(id.clone())); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&item); Self { id: Rc::new(id), inner: Rc::new(RefCell::new(item)), - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -125,10 +125,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.add_menu_item(item, AddOp::Append)?; - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); Ok(()) @@ -148,10 +148,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.add_menu_item(item, AddOp::Insert(0))?; - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); Ok(()) @@ -169,10 +169,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.add_menu_item(item, AddOp::Insert(position))?; - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); Ok(()) @@ -192,10 +192,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.remove(item)?; - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); Ok(()) @@ -230,10 +230,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.set_text(text.as_ref()); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -247,10 +247,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.set_enabled(enabled); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -263,10 +263,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.set_as_windows_menu_for_nsapp(); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -281,10 +281,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.set_as_help_menu_for_nsapp(); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -338,7 +338,7 @@ impl ContextMenu for Submenu { self.inner.borrow_mut().gtk_context_menu() } - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] fn compat_items(&self) -> Vec>> { self.inner.borrow_mut().compat_items() } diff --git a/src/lib.rs b/src/lib.rs index 3980eda4..27b21f50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -155,10 +155,10 @@ use std::{cell::RefCell, rc::Rc}; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crossbeam_channel::{unbounded, Receiver, Sender}; @@ -413,7 +413,7 @@ pub trait ContextMenu { fn gtk_context_menu(&self) -> gtk::Menu; /// Get all menu items within this context menu. - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] fn compat_items(&self) -> Vec>>; /// Shows this menu as a context menu for the specified `NSView`. @@ -494,15 +494,15 @@ impl MenuEvent { } } -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] static MENU_UPDATE_CHANNEL: Lazy<(Sender<()>, Receiver<()>)> = Lazy::new(unbounded); -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] pub fn recv_menu_update() -> std::result::Result<(), crossbeam_channel::RecvError> { MENU_UPDATE_CHANNEL.1.recv() } -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] pub fn send_menu_update() { let _ = MENU_UPDATE_CHANNEL.0.send(()); } diff --git a/src/menu.rs b/src/menu.rs index 334d3346..6ef0d7c6 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -4,10 +4,10 @@ use std::{cell::RefCell, rc::Rc}; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crate::{dpi::Position, util::AddOp, ContextMenu, IsMenuItem, MenuId, MenuItemKind}; @@ -413,7 +413,7 @@ impl ContextMenu for Menu { self.inner.borrow_mut().gtk_context_menu() } - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] fn compat_items(&self) -> Vec>> { self.inner.borrow_mut().compat_items() } diff --git a/src/platform_impl/mod.rs b/src/platform_impl/mod.rs index 93e64078..5e0c91cc 100644 --- a/src/platform_impl/mod.rs +++ b/src/platform_impl/mod.rs @@ -20,10 +20,10 @@ use std::{ rc::Rc, }; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(feature = "ksni")] +#[cfg(all(feature = "ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crate::{IsMenuItem, MenuItemKind}; @@ -74,7 +74,7 @@ impl MenuItemKind { } } - #[cfg(feature = "ksni")] + #[cfg(all(feature = "ksni", target_os = "linux"))] pub(crate) fn compat_child(&self) -> Arc> { use crate::items::*; match self { From 8a7212b2083b93eca659c1b4ecc693f161e4fb46 Mon Sep 17 00:00:00 2001 From: Daniel Faust Date: Thu, 12 Dec 2024 19:15:40 +0100 Subject: [PATCH 08/13] Combine platform-specific implementations of set_native_icon --- src/items/icon.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/items/icon.rs b/src/items/icon.rs index 456d1cc3..824b780a 100644 --- a/src/items/icon.rs +++ b/src/items/icon.rs @@ -257,20 +257,11 @@ impl IconMenuItem { /// ## Platform-specific: /// /// - **Windows / Linux**: Unsupported. - #[cfg(target_os = "macos")] - pub fn set_native_icon(&self, icon: Option) { - let mut item = self.inner.borrow_mut(); - item.set_native_icon(icon); + pub fn set_native_icon(&self, _icon: Option) { + #[cfg(target_os = "macos")] + self.inner.borrow_mut().set_native_icon(_icon); } - /// Change this menu item icon to a native image or remove it. - /// - /// ## Platform-specific: - /// - /// - **Windows / Linux**: Unsupported. - #[cfg(not(target_os = "macos"))] - pub fn set_native_icon(&self, _icon: Option) {} - /// Convert this menu item into its menu ID. pub fn into_id(mut self) -> MenuId { // Note: `Rc::into_inner` is available from Rust 1.70 From 33aa321b5580c54f91f0d86f9a0922f90a6fdcb4 Mon Sep 17 00:00:00 2001 From: Daniel Faust Date: Mon, 16 Dec 2024 11:58:49 +0100 Subject: [PATCH 09/13] cargo fmt --- src/items/check.rs | 9 +++++---- src/items/icon.rs | 6 +++--- src/items/normal.rs | 4 +--- src/items/predefined.rs | 2 +- src/items/submenu.rs | 16 ++++++++-------- src/platform_impl/gtk/mod.rs | 12 ++++++------ 6 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/items/check.rs b/src/items/check.rs index f0fa5d6e..dd64cedf 100644 --- a/src/items/check.rs +++ b/src/items/check.rs @@ -51,7 +51,8 @@ impl CheckMenuItem { label: super::strip_mnemonic(item.text()), enabled: item.is_enabled(), checked: item.is_checked(), - }.into() + } + .into() } /// Create a new check menu item. @@ -133,7 +134,7 @@ impl CheckMenuItem { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -150,7 +151,7 @@ impl CheckMenuItem { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -172,7 +173,7 @@ impl CheckMenuItem { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } diff --git a/src/items/icon.rs b/src/items/icon.rs index 824b780a..43351b3d 100644 --- a/src/items/icon.rs +++ b/src/items/icon.rs @@ -208,7 +208,7 @@ impl IconMenuItem { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -225,7 +225,7 @@ impl IconMenuItem { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -247,7 +247,7 @@ impl IconMenuItem { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } diff --git a/src/items/normal.rs b/src/items/normal.rs index a974f1b4..b584c3a9 100644 --- a/src/items/normal.rs +++ b/src/items/normal.rs @@ -6,9 +6,7 @@ use std::sync::Arc; #[cfg(all(feature = "ksni", target_os = "linux"))] use arc_swap::ArcSwap; -use crate::{ - accelerator::Accelerator, sealed::IsMenuItemBase, IsMenuItem, MenuId, MenuItemKind, -}; +use crate::{accelerator::Accelerator, sealed::IsMenuItemBase, IsMenuItem, MenuId, MenuItemKind}; /// A menu item inside a [`Menu`] or [`Submenu`] and contains only text. /// diff --git a/src/items/predefined.rs b/src/items/predefined.rs index 7a1da4c8..2ac9a458 100644 --- a/src/items/predefined.rs +++ b/src/items/predefined.rs @@ -243,7 +243,7 @@ impl PredefinedMenuItem { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } diff --git a/src/items/submenu.rs b/src/items/submenu.rs index 790f3dc8..86ce0061 100644 --- a/src/items/submenu.rs +++ b/src/items/submenu.rs @@ -127,7 +127,7 @@ impl Submenu { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); @@ -150,7 +150,7 @@ impl Submenu { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); @@ -171,7 +171,7 @@ impl Submenu { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); @@ -194,7 +194,7 @@ impl Submenu { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); @@ -232,7 +232,7 @@ impl Submenu { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -249,7 +249,7 @@ impl Submenu { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -265,7 +265,7 @@ impl Submenu { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -283,7 +283,7 @@ impl Submenu { #[cfg(all(feature = "ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - + #[cfg(all(feature = "ksni", target_os = "linux"))] crate::send_menu_update(); } diff --git a/src/platform_impl/gtk/mod.rs b/src/platform_impl/gtk/mod.rs index 7a741119..b61776f2 100644 --- a/src/platform_impl/gtk/mod.rs +++ b/src/platform_impl/gtk/mod.rs @@ -260,7 +260,10 @@ impl Menu { /// Returns a list of menu items that has been added to this menu. #[cfg(feature = "ksni")] pub fn compat_items(&self) -> Vec>> { - self.children.iter().map(MenuItemKind::compat_child).collect() + self.children + .iter() + .map(MenuItemKind::compat_child) + .collect() } pub fn init_for_gtk_window( @@ -917,7 +920,7 @@ impl MenuChild { let child = child.inner(); let child_ = child.borrow(); - + // remove all the gtk items that are related to this gtk menu and destroy it if let Some(items) = child_.gtk_menu_items.borrow_mut().remove(menu_id) { for item in items { @@ -958,10 +961,7 @@ impl MenuChild { } pub fn items(&self) -> Vec { - self.children - .as_ref() - .unwrap() - .to_vec() + self.children.as_ref().unwrap().to_vec() } #[cfg(feature = "ksni")] From ee486dd7415fd794d57a54680eac6a23fa06e342 Mon Sep 17 00:00:00 2001 From: Daniel Faust Date: Mon, 16 Dec 2024 12:05:31 +0100 Subject: [PATCH 10/13] Add back `MenuChild::kind` --- src/platform_impl/mod.rs | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/platform_impl/mod.rs b/src/platform_impl/mod.rs index 5e0c91cc..aeb751bd 100644 --- a/src/platform_impl/mod.rs +++ b/src/platform_impl/mod.rs @@ -42,6 +42,52 @@ impl dyn IsMenuItem + '_ { } } +/// Internal utilities +impl MenuChild { + #[cfg(not(target_os = "linux"))] + fn kind(&self, c: Rc>) -> MenuItemKind { + use crate::{items::*, MenuItemType}; + + match self.item_type() { + MenuItemType::Submenu => { + let id = c.borrow().id().clone(); + MenuItemKind::Submenu(Submenu { + id: Rc::new(id), + inner: c, + }) + } + MenuItemType::MenuItem => { + let id = c.borrow().id().clone(); + MenuItemKind::MenuItem(MenuItem { + id: Rc::new(id), + inner: c, + }) + } + MenuItemType::Predefined => { + let id = c.borrow().id().clone(); + MenuItemKind::Predefined(PredefinedMenuItem { + id: Rc::new(id), + inner: c, + }) + } + MenuItemType::Check => { + let id = c.borrow().id().clone(); + MenuItemKind::Check(CheckMenuItem { + id: Rc::new(id), + inner: c, + }) + } + MenuItemType::Icon => { + let id = c.borrow().id().clone(); + MenuItemKind::Icon(IconMenuItem { + id: Rc::new(id), + inner: c, + }) + } + } + } +} + #[allow(unused)] impl MenuItemKind { pub(crate) fn as_ref(&self) -> &dyn IsMenuItem { From 47ae86bb1080601d3d53bf5c1c7be8fcce7bd999 Mon Sep 17 00:00:00 2001 From: Daniel Faust Date: Wed, 8 Jan 2025 21:18:44 +0100 Subject: [PATCH 11/13] Rename feature ksni to linux-ksni --- Cargo.toml | 2 +- src/items/check.rs | 28 ++++++++++---------- src/items/icon.rs | 36 +++++++++++++------------- src/items/mod.rs | 4 +-- src/items/normal.rs | 24 ++++++++--------- src/items/predefined.rs | 16 ++++++------ src/items/submenu.rs | 50 ++++++++++++++++++------------------ src/lib.rs | 12 ++++----- src/menu.rs | 6 ++--- src/platform_impl/gtk/mod.rs | 8 +++--- src/platform_impl/mod.rs | 6 ++--- 11 files changed, 96 insertions(+), 96 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1c11964e..50fe00b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ default = ["libxdo"] libxdo = ["dep:libxdo"] common-controls-v6 = [] serde = ["dep:serde", "dpi/serde"] -ksni = ["arc-swap"] +linux-ksni = ["arc-swap"] [dependencies] arc-swap = { version = "1.7.1", optional = true } diff --git a/src/items/check.rs b/src/items/check.rs index dd64cedf..c0d4517c 100644 --- a/src/items/check.rs +++ b/src/items/check.rs @@ -4,10 +4,10 @@ use std::{cell::RefCell, mem, rc::Rc}; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crate::{accelerator::Accelerator, sealed::IsMenuItemBase, IsMenuItem, MenuId, MenuItemKind}; @@ -22,7 +22,7 @@ use crate::{accelerator::Accelerator, sealed::IsMenuItemBase, IsMenuItem, MenuId pub struct CheckMenuItem { pub(crate) id: Rc, pub(crate) inner: Rc>, - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] pub(crate) compat: Arc>, } @@ -42,7 +42,7 @@ impl IsMenuItem for CheckMenuItem { } impl CheckMenuItem { - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] pub(crate) fn compat_menu_item( item: &crate::platform_impl::MenuChild, ) -> crate::CompatMenuItem { @@ -73,13 +73,13 @@ impl CheckMenuItem { None, ); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(inner.id().clone()), inner: Rc::new(RefCell::new(inner)), - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -104,13 +104,13 @@ impl CheckMenuItem { Some(id.clone()), ); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(id), inner: Rc::new(RefCell::new(inner)), - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -132,10 +132,10 @@ impl CheckMenuItem { let mut inner = self.inner.borrow_mut(); inner.set_text(text.as_ref()); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -149,10 +149,10 @@ impl CheckMenuItem { let mut inner = self.inner.borrow_mut(); inner.set_enabled(enabled); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -171,10 +171,10 @@ impl CheckMenuItem { let mut inner = self.inner.borrow_mut(); inner.set_checked(checked); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); } diff --git a/src/items/icon.rs b/src/items/icon.rs index 43351b3d..a9ae2c9b 100644 --- a/src/items/icon.rs +++ b/src/items/icon.rs @@ -4,10 +4,10 @@ use std::{cell::RefCell, mem, rc::Rc}; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crate::{ @@ -26,7 +26,7 @@ use crate::{ pub struct IconMenuItem { pub(crate) id: Rc, pub(crate) inner: Rc>, - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] pub(crate) compat: Arc>, } @@ -46,7 +46,7 @@ impl IsMenuItem for IconMenuItem { } impl IconMenuItem { - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] pub(crate) fn compat_menu_item( item: &crate::platform_impl::MenuChild, ) -> crate::CompatMenuItem { @@ -81,13 +81,13 @@ impl IconMenuItem { None, ); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(inner.id().clone()), inner: Rc::new(RefCell::new(inner)), - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -112,13 +112,13 @@ impl IconMenuItem { Some(id.clone()), ); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(id), inner: Rc::new(RefCell::new(inner)), - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -144,13 +144,13 @@ impl IconMenuItem { None, ); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(inner.id().clone()), inner: Rc::new(RefCell::new(inner)), - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -178,13 +178,13 @@ impl IconMenuItem { Some(id.clone()), ); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(id), inner: Rc::new(RefCell::new(inner)), - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -206,10 +206,10 @@ impl IconMenuItem { let mut inner = self.inner.borrow_mut(); inner.set_text(text.as_ref()); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -223,10 +223,10 @@ impl IconMenuItem { let mut inner = self.inner.borrow_mut(); inner.set_enabled(enabled); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -245,10 +245,10 @@ impl IconMenuItem { let mut inner = self.inner.borrow_mut(); inner.set_icon(icon); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); } diff --git a/src/items/mod.rs b/src/items/mod.rs index 23a4d847..855d67c0 100644 --- a/src/items/mod.rs +++ b/src/items/mod.rs @@ -8,7 +8,7 @@ mod normal; mod predefined; mod submenu; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] mod compat; pub use check::*; @@ -17,7 +17,7 @@ pub use normal::*; pub use predefined::*; pub use submenu::*; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] pub use compat::*; #[cfg(test)] diff --git a/src/items/normal.rs b/src/items/normal.rs index b584c3a9..71e192f8 100644 --- a/src/items/normal.rs +++ b/src/items/normal.rs @@ -1,9 +1,9 @@ use std::{cell::RefCell, mem, rc::Rc}; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crate::{accelerator::Accelerator, sealed::IsMenuItemBase, IsMenuItem, MenuId, MenuItemKind}; @@ -16,7 +16,7 @@ use crate::{accelerator::Accelerator, sealed::IsMenuItemBase, IsMenuItem, MenuId pub struct MenuItem { pub(crate) id: Rc, pub(crate) inner: Rc>, - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] pub(crate) compat: Arc>, } @@ -36,7 +36,7 @@ impl IsMenuItem for MenuItem { } impl MenuItem { - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] pub(crate) fn compat_menu_item( item: &crate::platform_impl::MenuChild, ) -> crate::CompatMenuItem { @@ -57,13 +57,13 @@ impl MenuItem { pub fn new>(text: S, enabled: bool, accelerator: Option) -> Self { let inner = crate::platform_impl::MenuChild::new(text.as_ref(), enabled, accelerator, None); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(inner.id().clone()), inner: Rc::new(RefCell::new(inner)), - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -86,13 +86,13 @@ impl MenuItem { Some(id.clone()), ); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(id), inner: Rc::new(RefCell::new(inner)), - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -114,10 +114,10 @@ impl MenuItem { let mut inner = self.inner.borrow_mut(); inner.set_text(text.as_ref()); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -131,10 +131,10 @@ impl MenuItem { let mut inner = self.inner.borrow_mut(); inner.set_enabled(enabled); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); } diff --git a/src/items/predefined.rs b/src/items/predefined.rs index 2ac9a458..05ed7b0b 100644 --- a/src/items/predefined.rs +++ b/src/items/predefined.rs @@ -4,10 +4,10 @@ use std::{cell::RefCell, mem, rc::Rc}; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crate::{ @@ -22,7 +22,7 @@ use keyboard_types::{Code, Modifiers}; pub struct PredefinedMenuItem { pub(crate) id: Rc, pub(crate) inner: Rc>, - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] pub(crate) compat: Arc>, } @@ -42,7 +42,7 @@ impl IsMenuItem for PredefinedMenuItem { } impl PredefinedMenuItem { - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] pub(crate) fn compat_menu_item( item: &crate::platform_impl::MenuChild, ) -> crate::CompatMenuItem { @@ -215,13 +215,13 @@ impl PredefinedMenuItem { text.map(|t| t.as_ref().to_string()), ); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&inner); Self { id: Rc::new(inner.id().clone()), inner: Rc::new(RefCell::new(inner)), - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -241,10 +241,10 @@ impl PredefinedMenuItem { let mut inner = self.inner.borrow_mut(); inner.set_text(text.as_ref()); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); } diff --git a/src/items/submenu.rs b/src/items/submenu.rs index 86ce0061..21350e8b 100644 --- a/src/items/submenu.rs +++ b/src/items/submenu.rs @@ -4,10 +4,10 @@ use std::{cell::RefCell, mem, rc::Rc}; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crate::{ @@ -22,7 +22,7 @@ use crate::{ pub struct Submenu { pub(crate) id: Rc, pub(crate) inner: Rc>, - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] pub(crate) compat: Arc>, } @@ -42,7 +42,7 @@ impl IsMenuItem for Submenu { } impl Submenu { - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] pub(crate) fn compat_menu_item( item: &crate::platform_impl::MenuChild, ) -> crate::CompatMenuItem { @@ -61,13 +61,13 @@ impl Submenu { pub fn new>(text: S, enabled: bool) -> Self { let item = crate::platform_impl::MenuChild::new_submenu(text.as_ref(), enabled, None); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&item); Self { id: Rc::new(item.id().clone()), inner: Rc::new(RefCell::new(item)), - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -81,13 +81,13 @@ impl Submenu { let item = crate::platform_impl::MenuChild::new_submenu(text.as_ref(), enabled, Some(id.clone())); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] let compat = Self::compat_menu_item(&item); Self { id: Rc::new(id), inner: Rc::new(RefCell::new(item)), - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] compat: Arc::new(ArcSwap::from_pointee(compat)), } } @@ -125,10 +125,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.add_menu_item(item, AddOp::Append)?; - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); Ok(()) @@ -148,10 +148,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.add_menu_item(item, AddOp::Insert(0))?; - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); Ok(()) @@ -169,10 +169,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.add_menu_item(item, AddOp::Insert(position))?; - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); Ok(()) @@ -192,10 +192,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.remove(item)?; - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); Ok(()) @@ -230,10 +230,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.set_text(text.as_ref()); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -247,10 +247,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.set_enabled(enabled); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -263,10 +263,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.set_as_windows_menu_for_nsapp(); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -281,10 +281,10 @@ impl Submenu { let mut inner = self.inner.borrow_mut(); inner.set_as_help_menu_for_nsapp(); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] self.compat.store(Arc::new(Self::compat_menu_item(&inner))); - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] crate::send_menu_update(); } @@ -338,7 +338,7 @@ impl ContextMenu for Submenu { self.inner.borrow_mut().gtk_context_menu() } - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] fn compat_items(&self) -> Vec>> { self.inner.borrow_mut().compat_items() } diff --git a/src/lib.rs b/src/lib.rs index 27b21f50..9e9edd12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -155,10 +155,10 @@ use std::{cell::RefCell, rc::Rc}; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crossbeam_channel::{unbounded, Receiver, Sender}; @@ -413,7 +413,7 @@ pub trait ContextMenu { fn gtk_context_menu(&self) -> gtk::Menu; /// Get all menu items within this context menu. - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] fn compat_items(&self) -> Vec>>; /// Shows this menu as a context menu for the specified `NSView`. @@ -494,15 +494,15 @@ impl MenuEvent { } } -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] static MENU_UPDATE_CHANNEL: Lazy<(Sender<()>, Receiver<()>)> = Lazy::new(unbounded); -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] pub fn recv_menu_update() -> std::result::Result<(), crossbeam_channel::RecvError> { MENU_UPDATE_CHANNEL.1.recv() } -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] pub fn send_menu_update() { let _ = MENU_UPDATE_CHANNEL.0.send(()); } diff --git a/src/menu.rs b/src/menu.rs index 6ef0d7c6..05c872ec 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -4,10 +4,10 @@ use std::{cell::RefCell, rc::Rc}; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crate::{dpi::Position, util::AddOp, ContextMenu, IsMenuItem, MenuId, MenuItemKind}; @@ -413,7 +413,7 @@ impl ContextMenu for Menu { self.inner.borrow_mut().gtk_context_menu() } - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] fn compat_items(&self) -> Vec>> { self.inner.borrow_mut().compat_items() } diff --git a/src/platform_impl/gtk/mod.rs b/src/platform_impl/gtk/mod.rs index b61776f2..75ef60e8 100644 --- a/src/platform_impl/gtk/mod.rs +++ b/src/platform_impl/gtk/mod.rs @@ -27,10 +27,10 @@ use std::{ sync::atomic::{AtomicBool, Ordering}, }; -#[cfg(feature = "ksni")] +#[cfg(feature = "linux-ksni")] use std::sync::Arc; -#[cfg(feature = "ksni")] +#[cfg(feature = "linux-ksni")] use arc_swap::ArcSwap; static COUNTER: Counter = Counter::new(); @@ -258,7 +258,7 @@ impl Menu { } /// Returns a list of menu items that has been added to this menu. - #[cfg(feature = "ksni")] + #[cfg(feature = "linux-ksni")] pub fn compat_items(&self) -> Vec>> { self.children .iter() @@ -964,7 +964,7 @@ impl MenuChild { self.children.as_ref().unwrap().to_vec() } - #[cfg(feature = "ksni")] + #[cfg(feature = "linux-ksni")] pub fn compat_items(&self) -> Vec>> { self.children .as_ref() diff --git a/src/platform_impl/mod.rs b/src/platform_impl/mod.rs index aeb751bd..0f68c713 100644 --- a/src/platform_impl/mod.rs +++ b/src/platform_impl/mod.rs @@ -20,10 +20,10 @@ use std::{ rc::Rc, }; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use std::sync::Arc; -#[cfg(all(feature = "ksni", target_os = "linux"))] +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] use arc_swap::ArcSwap; use crate::{IsMenuItem, MenuItemKind}; @@ -120,7 +120,7 @@ impl MenuItemKind { } } - #[cfg(all(feature = "ksni", target_os = "linux"))] + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] pub(crate) fn compat_child(&self) -> Arc> { use crate::items::*; match self { From 33f0917e8d373bf74ddb643a2a62b9f6ccf98732 Mon Sep 17 00:00:00 2001 From: Daniel Faust Date: Wed, 8 Jan 2025 21:58:05 +0100 Subject: [PATCH 12/13] Fix ci pipeline --- src/items/check.rs | 21 +++++++++++++++------ src/platform_impl/windows/dark_menu_bar.rs | 12 +++++++++--- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/items/check.rs b/src/items/check.rs index c0d4517c..60ca9e83 100644 --- a/src/items/check.rs +++ b/src/items/check.rs @@ -168,14 +168,23 @@ impl CheckMenuItem { /// Check or Uncheck this check menu item. pub fn set_checked(&self, checked: bool) { - let mut inner = self.inner.borrow_mut(); - inner.set_checked(checked); + #[cfg(target_os = "macos")] + { + let inner = self.inner.borrow(); + inner.set_checked(checked); + } - #[cfg(all(feature = "linux-ksni", target_os = "linux"))] - self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + #[cfg(not(target_os = "macos"))] + { + let mut inner = self.inner.borrow_mut(); + inner.set_checked(checked); - #[cfg(all(feature = "linux-ksni", target_os = "linux"))] - crate::send_menu_update(); + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + { + self.compat.store(Arc::new(Self::compat_menu_item(&inner))); + crate::send_menu_update(); + } + } } /// Convert this menu item into its menu ID. diff --git a/src/platform_impl/windows/dark_menu_bar.rs b/src/platform_impl/windows/dark_menu_bar.rs index 558a4b1d..72afa627 100644 --- a/src/platform_impl/windows/dark_menu_bar.rs +++ b/src/platform_impl/windows/dark_menu_bar.rs @@ -6,7 +6,7 @@ #![allow(non_snake_case, clippy::upper_case_acronyms)] -use std::cell::Cell; +use std::cell::OnceCell; use once_cell::sync::Lazy; use windows_sys::{ @@ -94,7 +94,10 @@ fn background_brush() -> HBRUSH { static BACKGROUND_BRUSH: Win32Brush = const { Win32Brush::null() }; } const BACKGROUND_COLOR: u32 = 2829099; - BACKGROUND_BRUSH.with(|brush| brush.get_or_set(BACKGROUND_COLOR)) + static BACKGROUND_BRUSH: OnceCell = OnceCell::new(); + + let hbrush = BACKGROUND_BRUSH.get_or_init(|| HBrush(CreateSolidBrush(BACKGROUND_COLOR))); + hbrush.as_ref().unwrap().0 } fn selected_background_brush() -> HBRUSH { @@ -102,7 +105,10 @@ fn selected_background_brush() -> HBRUSH { static SELECTED_BACKGROUND_BRUSH: Win32Brush = const { Win32Brush::null() }; } const SELECTED_BACKGROUND_COLOR: u32 = 4276545; - SELECTED_BACKGROUND_BRUSH.with(|brush| brush.get_or_set(SELECTED_BACKGROUND_COLOR)) + static SELECTED_BACKGROUND_BRUSH: OnceCell = OnceCell::new(); + + let hbrush = SELECTED_BACKGROUND_BRUSH.get_or_init(|| HBrush(CreateSolidBrush(SELECTED_BACKGROUND_COLOR))); + hbrush.as_ref().unwrap().0 } /// Draws a dark menu bar if needed and returns whether it draws it or not From b6f8ebb1feaefc1ff4482ce3895e2c71499a4f8c Mon Sep 17 00:00:00 2001 From: Daniel Faust Date: Sat, 8 Feb 2025 14:44:13 +0100 Subject: [PATCH 13/13] cargo fmt --- Cargo.lock | 7 +++++++ src/platform_impl/windows/dark_menu_bar.rs | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 094da987..500064ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,6 +82,12 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arg_enum_proc_macro" version = "0.3.4" @@ -1771,6 +1777,7 @@ dependencies = [ name = "muda" version = "0.15.3" dependencies = [ + "arc-swap", "crossbeam-channel", "dpi", "gtk", diff --git a/src/platform_impl/windows/dark_menu_bar.rs b/src/platform_impl/windows/dark_menu_bar.rs index 72afa627..1f5b1502 100644 --- a/src/platform_impl/windows/dark_menu_bar.rs +++ b/src/platform_impl/windows/dark_menu_bar.rs @@ -107,7 +107,8 @@ fn selected_background_brush() -> HBRUSH { const SELECTED_BACKGROUND_COLOR: u32 = 4276545; static SELECTED_BACKGROUND_BRUSH: OnceCell = OnceCell::new(); - let hbrush = SELECTED_BACKGROUND_BRUSH.get_or_init(|| HBrush(CreateSolidBrush(SELECTED_BACKGROUND_COLOR))); + let hbrush = SELECTED_BACKGROUND_BRUSH + .get_or_init(|| HBrush(CreateSolidBrush(SELECTED_BACKGROUND_COLOR))); hbrush.as_ref().unwrap().0 }