From 7b95e9b7b25134c12cd6b30f60d66a9ff68dcb0f Mon Sep 17 00:00:00 2001 From: amrbashir Date: Wed, 11 Jan 2023 18:57:13 +0200 Subject: [PATCH 1/2] feat: add `set_visible` --- .changes/visible.md | 5 +++ src/lib.rs | 7 +++- src/platform_impl/gtk/mod.rs | 10 +++++- src/platform_impl/macos/mod.rs | 14 ++++++-- src/platform_impl/windows/mod.rs | 57 ++++++++++++++++++++++++++------ 5 files changed, 78 insertions(+), 15 deletions(-) create mode 100644 .changes/visible.md diff --git a/.changes/visible.md b/.changes/visible.md new file mode 100644 index 0000000..977ceb3 --- /dev/null +++ b/.changes/visible.md @@ -0,0 +1,5 @@ +--- +"tray-icon": "patch" +--- + +Add `TrayIcon::set_visible`. \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 0cfe28f..aa51de4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -236,7 +236,7 @@ impl TrayIcon { self.id } - /// Set new tray icon. If `None` is provided, it will hide the icon. + /// Set new tray icon. If `None` is provided, it will remove the icon. pub fn set_icon(&mut self, icon: Option) -> Result<()> { self.tray.set_icon(icon) } @@ -273,6 +273,11 @@ impl TrayIcon { self.tray.set_title(title) } + /// Show or hide this tray icon + pub fn set_visible(&mut self, visible: bool) { + self.tray.set_visible(visible) + } + /// Sets the tray icon temp dir path. **Linux only**. /// /// On Linux, we need to write the icon to the disk and usually it will diff --git a/src/platform_impl/gtk/mod.rs b/src/platform_impl/gtk/mod.rs index a3c9372..50bf3bb 100644 --- a/src/platform_impl/gtk/mod.rs +++ b/src/platform_impl/gtk/mod.rs @@ -59,7 +59,7 @@ impl TrayIcon { self.indicator .set_icon_theme_path(&parent_path.to_string_lossy()); self.indicator - .set_icon_full(&icon_path.to_string_lossy(), "icon"); + .set_icon_full(&icon_path.to_string_lossy(), "tray icon"); self.path = icon_path; Ok(()) @@ -79,6 +79,14 @@ impl TrayIcon { .set_label(title.as_ref().map(|t| t.as_ref()).unwrap_or(""), ""); } + pub fn set_visible(&mut self, visible: bool) { + if visible { + self.indicator.set_status(AppIndicatorStatus::Passive); + } else { + self.indicator.set_status(AppIndicatorStatus::Active); + } + } + pub fn set_temp_dir_path>(&mut self, path: Option

) { self.temp_dir_path = path.map(|p| p.as_ref().to_path_buf()); } diff --git a/src/platform_impl/macos/mod.rs b/src/platform_impl/macos/mod.rs index b77a986..6737c2a 100644 --- a/src/platform_impl/macos/mod.rs +++ b/src/platform_impl/macos/mod.rs @@ -120,6 +120,14 @@ impl TrayIcon { } } + pub fn set_visible(&mut self, visible: bool) { + unsafe { + let button = self.ns_status_bar.button(); + let visible = !visible as i8; + let _: () = msg_send![button, setHidden: visible]; + } + } + pub fn set_icon_as_template(&mut self, is_template: bool) { unsafe { let button = self.ns_status_bar.button(); @@ -145,6 +153,8 @@ impl Drop for TrayIcon { } fn create_button_with_icon(ns_status_bar: id, icon: Option, icon_is_template: bool) { + let button = unsafe { ns_status_bar.button() }; + if let Some(icon) = icon { // The image is to the right of the title https://developer.apple.com/documentation/appkit/nscellimageposition/nsimageleft const NSIMAGE_LEFT: i32 = 2; @@ -157,8 +167,6 @@ fn create_button_with_icon(ns_status_bar: id, icon: Option, icon_is_templa let icon_width: f64 = (width as f64) / (height as f64 / icon_height); unsafe { - let button = ns_status_bar.button(); - // build our icon let nsdata = NSData::dataWithBytes_length_( nil, @@ -174,6 +182,8 @@ fn create_button_with_icon(ns_status_bar: id, icon: Option, icon_is_templa let _: () = msg_send![button, setImagePosition: NSIMAGE_LEFT]; let _: () = msg_send![nsimage, setTemplate: icon_is_template as i8]; } + } else { + button.setImage_(nil); } } diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index f66c209..d6ab5b3 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -36,7 +36,9 @@ const TRAY_SUBCLASS_ID: usize = 6001; const WM_USER_TRAYICON: u32 = 6002; const WM_USER_UPDATE_TRAYMENU: u32 = 6003; const WM_USER_UPDATE_TRAYICON: u32 = 6004; -const WM_USER_UPDATE_TRAYTOOLTIP: u32 = 6005; +const WM_USER_SHOW_TRAYICON: u32 = 6005; +const WM_USER_HIDE_TRAYICON: u32 = 6006; +const WM_USER_UPDATE_TRAYTOOLTIP: u32 = 6007; /// When the taskbar is created, it registers a message with the "TaskbarCreated" string and then broadcasts this message to all top-level windows /// When the application receives this message, it should assume that any taskbar icons it added have been removed and add them again. @@ -218,21 +220,27 @@ impl TrayIcon { } pub fn set_title>(&mut self, _title: Option) {} + + pub fn set_visible(&mut self, visible: bool) { + unsafe { + SendMessageW( + self.hwnd, + if visible { + WM_USER_SHOW_TRAYICON + } else { + WM_USER_HIDE_TRAYICON + }, + 0, + 0, + ); + } + } } impl Drop for TrayIcon { fn drop(&mut self) { unsafe { - // remove the icon from system tray - let mut nid = NOTIFYICONDATAW { - uFlags: NIF_ICON, - hWnd: self.hwnd, - uID: self.id, - ..std::mem::zeroed() - }; - if Shell_NotifyIconW(NIM_DELETE, &mut nid as _) == 0 { - eprintln!("Error removing system tray icon"); - } + remove_tray_icon(self.hwnd, self.id); if let Some(menu) = &self.menu { menu.detach_menu_subclass_from_hwnd(self.hwnd); @@ -267,6 +275,20 @@ unsafe extern "system" fn tray_subclass_proc( let icon = Box::from_raw(wparam as *mut Option); subclass_input.icon = *icon; } + WM_USER_SHOW_TRAYICON => { + register_tray_icon( + subclass_input.hwnd, + subclass_input.id, + &subclass_input + .icon + .as_ref() + .map(|i| i.inner.as_raw_handle()), + &subclass_input.tooltip, + ); + } + WM_USER_HIDE_TRAYICON => { + remove_tray_icon(subclass_input.hwnd, subclass_input.id); + } WM_USER_UPDATE_TRAYTOOLTIP => { let tooltip = Box::from_raw(wparam as *mut Option); subclass_input.tooltip = *tooltip; @@ -384,3 +406,16 @@ unsafe fn register_tray_icon( Shell_NotifyIconW(NIM_ADD, &mut nid as _) == 1 } + +unsafe fn remove_tray_icon(hwnd: HWND, id: u32) { + let mut nid = NOTIFYICONDATAW { + uFlags: NIF_ICON, + hWnd: hwnd, + uID: id, + ..std::mem::zeroed() + }; + + if Shell_NotifyIconW(NIM_DELETE, &mut nid as _) == 0 { + eprintln!("Error removing system tray icon"); + } +} From 69149697cc8b3d3fd409ff26d69e53df10b749ff Mon Sep 17 00:00:00 2001 From: amrbashir Date: Wed, 11 Jan 2023 19:16:44 +0200 Subject: [PATCH 2/2] fix macOS build --- src/platform_impl/macos/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform_impl/macos/mod.rs b/src/platform_impl/macos/mod.rs index 6737c2a..cd4047f 100644 --- a/src/platform_impl/macos/mod.rs +++ b/src/platform_impl/macos/mod.rs @@ -183,7 +183,7 @@ fn create_button_with_icon(ns_status_bar: id, icon: Option, icon_is_templa let _: () = msg_send![nsimage, setTemplate: icon_is_template as i8]; } } else { - button.setImage_(nil); + unsafe { button.setImage_(nil) }; } }