diff --git a/native-windows-gui/src/controls/control_base.rs b/native-windows-gui/src/controls/control_base.rs index 3bf0cd19..c0b9b726 100644 --- a/native-windows-gui/src/controls/control_base.rs +++ b/native-windows-gui/src/controls/control_base.rs @@ -1,7 +1,7 @@ use winapi::shared::minwindef::DWORD; use winapi::shared::windef::{HWND}; use super::ControlHandle; -use crate::win32::window::{build_hwnd_control, build_timer, build_notice}; +use crate::win32::window::{build_hwnd_control, build_timer, build_notice, build_tray}; use crate::{NwgError}; #[cfg(feature = "menu")] use crate::win32::menu::build_hmenu_control; @@ -277,7 +277,7 @@ impl OtherBuilder { let handle = self.parent.expect("Internal error. Control without window parent"); let base = match self.ty { NOTICE => build_notice(handle), - TRAY => ControlHandle::SystemTray(handle), + TRAY => build_tray(handle), _ => unreachable!() }; diff --git a/native-windows-gui/src/controls/control_handle.rs b/native-windows-gui/src/controls/control_handle.rs index c563a1e6..d0c2f01b 100644 --- a/native-windows-gui/src/controls/control_handle.rs +++ b/native-windows-gui/src/controls/control_handle.rs @@ -27,7 +27,7 @@ pub enum ControlHandle { Timer(HWND, u32), /// System tray control - SystemTray(HWND) + SystemTray(HWND, u32), } impl ControlHandle { @@ -95,9 +95,9 @@ impl ControlHandle { } } - pub fn tray(&self) -> Option { + pub fn tray(&self) -> Option<(HWND, u32)> { match self { - &ControlHandle::SystemTray(h) => Some(h), + &ControlHandle::SystemTray(h, i) => Some((h, i)), _ => None, } } @@ -152,8 +152,8 @@ impl PartialEq for ControlHandle { _ => false }, // System tray - &ControlHandle::SystemTray(hwnd1) => match other { - &ControlHandle::SystemTray(hwnd2) => hwnd1 == hwnd2, + &ControlHandle::SystemTray(hwnd1, id1) => match other { + &ControlHandle::SystemTray(hwnd2, id2) => hwnd1 == hwnd2 && id1 == id2, _ => false } } diff --git a/native-windows-gui/src/controls/tray_notification.rs b/native-windows-gui/src/controls/tray_notification.rs index 7c704f15..122ce483 100644 --- a/native-windows-gui/src/controls/tray_notification.rs +++ b/native-windows-gui/src/controls/tray_notification.rs @@ -218,11 +218,11 @@ impl TrayNotification { fn notify_default(&self) -> NOTIFYICONDATAW { unsafe { - let parent = self.handle.tray().unwrap(); + let (parent, id) = self.handle.tray().unwrap(); NOTIFYICONDATAW { cbSize: mem::size_of::() as u32, hWnd: parent, - uID: 0, + uID: id, uFlags: 0, uCallbackMessage: 0, hIcon: ptr::null_mut(), @@ -332,7 +332,7 @@ impl<'a> TrayNotificationBuilder<'a> { pub fn build(self, out: &mut TrayNotification) -> Result<(), NwgError> { use winapi::um::shellapi::{NIM_ADD, NIF_ICON, NIF_TIP, NIF_SHOWTIP, NIF_INFO, NOTIFYICONDATAW_u, NOTIFYICON_VERSION_4, - NIF_REALTIME, NIF_MESSAGE, NIS_HIDDEN, NIF_STATE}; + NIF_REALTIME, NIF_MESSAGE, NIS_HIDDEN, NIF_STATE, NIM_SETVERSION}; use winapi::shared::windef::HICON; use winapi::um::winnt::WCHAR; @@ -379,6 +379,7 @@ impl<'a> TrayNotificationBuilder<'a> { let handle = ControlBase::build_tray_notification() .parent(parent) .build()?; + let id = handle.tray().unwrap().1; // Tips or infos let mut tip: [WCHAR; 128] = [0; 128]; @@ -411,12 +412,12 @@ impl<'a> TrayNotificationBuilder<'a> { // Creation unsafe { let mut u: NOTIFYICONDATAW_u = mem::zeroed(); - *u.uVersion_mut() = version; + *u.uTimeout_mut() = 0; let mut data = NOTIFYICONDATAW { cbSize: mem::size_of::() as u32, hWnd: parent, - uID: 0, + uID: id, uFlags: flags, uCallbackMessage: wh::NWG_TRAY, hIcon: icon, @@ -432,6 +433,10 @@ impl<'a> TrayNotificationBuilder<'a> { }; Shell_NotifyIconW(NIM_ADD, &mut data); + + // ensure that incoming messages follow the v4 format + *data.u.uVersion_mut() = version; + Shell_NotifyIconW(NIM_SETVERSION, &mut data); } diff --git a/native-windows-gui/src/win32/window.rs b/native-windows-gui/src/win32/window.rs index 115176bf..48a26634 100644 --- a/native-windows-gui/src/win32/window.rs +++ b/native-windows-gui/src/win32/window.rs @@ -22,6 +22,7 @@ use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering}; static TIMER_ID: AtomicU32 = AtomicU32::new(1); static NOTICE_ID: AtomicU32 = AtomicU32::new(1); +static TRAY_ID: AtomicU32 = AtomicU32::new(1); static EVENT_HANDLER_ID: AtomicUsize = AtomicUsize::new(1); const NO_DATA: EventData = EventData::NoData; @@ -70,6 +71,12 @@ pub unsafe fn build_timer(parent: HWND, interval: u32, stopped: bool) -> Control ControlHandle::Timer(parent, id) } + +pub fn build_tray(parent: HWND) -> ControlHandle { + let id = TRAY_ID.fetch_add(1, Ordering::SeqCst); + ControlHandle::SystemTray(parent, id) +} + /** Hook the window subclass with the default event dispatcher. The hook is applied to the window and all it's children (recursively). @@ -665,7 +672,8 @@ unsafe extern "system" fn process_events(hwnd: HWND, msg: UINT, w: WPARAM, l: LP }, NWG_TRAY => { let msg = LOWORD(l as u32) as u32; - let handle = ControlHandle::SystemTray(hwnd); + let icon_id = HIWORD(l as u32) as u32; + let handle = ControlHandle::SystemTray(hwnd, icon_id); match msg { NIN_BALLOONSHOW => callback(Event::OnTrayNotificationShow, NO_DATA, handle),