Skip to content

Commit

Permalink
feat: add set_visible (#14)
Browse files Browse the repository at this point in the history
* feat: add `set_visible`

* fix macOS build
  • Loading branch information
amrbashir authored Jan 12, 2023
1 parent 6df6fc7 commit ba4580e
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .changes/visible.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tray-icon": "patch"
---

Add `TrayIcon::set_visible`.
7 changes: 6 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Icon>) -> Result<()> {
self.tray.set_icon(icon)
}
Expand Down Expand Up @@ -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
Expand Down
10 changes: 9 additions & 1 deletion src/platform_impl/gtk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
Expand All @@ -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<P: AsRef<Path>>(&mut self, path: Option<P>) {
self.temp_dir_path = path.map(|p| p.as_ref().to_path_buf());
}
Expand Down
14 changes: 12 additions & 2 deletions src/platform_impl/macos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -145,6 +153,8 @@ impl Drop for TrayIcon {
}

fn create_button_with_icon(ns_status_bar: id, icon: Option<Icon>, 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;
Expand All @@ -157,8 +167,6 @@ fn create_button_with_icon(ns_status_bar: id, icon: Option<Icon>, 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,
Expand All @@ -174,6 +182,8 @@ fn create_button_with_icon(ns_status_bar: id, icon: Option<Icon>, icon_is_templa
let _: () = msg_send![button, setImagePosition: NSIMAGE_LEFT];
let _: () = msg_send![nsimage, setTemplate: icon_is_template as i8];
}
} else {
unsafe { button.setImage_(nil) };
}
}

Expand Down
57 changes: 46 additions & 11 deletions src/platform_impl/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -218,21 +220,27 @@ impl TrayIcon {
}

pub fn set_title<S: AsRef<str>>(&mut self, _title: Option<S>) {}

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);
Expand Down Expand Up @@ -267,6 +275,20 @@ unsafe extern "system" fn tray_subclass_proc(
let icon = Box::from_raw(wparam as *mut Option<Icon>);
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<String>);
subclass_input.tooltip = *tooltip;
Expand Down Expand Up @@ -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");
}
}

0 comments on commit ba4580e

Please sign in to comment.