Skip to content

Commit

Permalink
fix(windows): subscribe to taskbar restart event, closes #476 (#487)
Browse files Browse the repository at this point in the history
* fix(windows): subscribe to taskbar restart event, closes #476
  • Loading branch information
amrbashir authored Jul 21, 2022
1 parent feb2127 commit 9450329
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 35 deletions.
6 changes: 6 additions & 0 deletions .changes/taskbar-restart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"tao": "patch"
---

On Windows, subscribe to taskbar restart event and re-add the system tray icon.
Also skip the window from the taskbar if it was already skipped.
27 changes: 18 additions & 9 deletions src/platform_impl/windows/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ use crate::{
minimal_ime::is_msg_ime_related,
monitor::{self, MonitorHandle},
raw_input, util,
window::set_skip_taskbar,
window_state::{CursorFlags, WindowFlags, WindowState},
wrap_device_id, WindowId, DEVICE_ID,
},
Expand Down Expand Up @@ -540,16 +541,16 @@ impl<T: 'static> EventLoopProxy<T> {
type WaitUntilInstantBox = Box<Instant>;

lazy_static! {
// Message sent by the `EventLoopProxy` when we want to wake up the thread.
// WPARAM and LPARAM are unused.
/// Message sent by the `EventLoopProxy` when we want to wake up the thread.
/// WPARAM and LPARAM are unused.
static ref USER_EVENT_MSG_ID: u32 = {
unsafe {
RegisterWindowMessageA("Tao::WakeupMsg")
}
};
// Message sent when we want to execute a closure in the thread.
// WPARAM contains a Box<Box<dyn FnMut()>> that must be retrieved with `Box::from_raw`,
// and LPARAM is unused.
/// Message sent when we want to execute a closure in the thread.
/// WPARAM contains a Box<Box<dyn FnMut()>> that must be retrieved with `Box::from_raw`,
/// and LPARAM is unused.
static ref EXEC_MSG_ID: u32 = {
unsafe {
RegisterWindowMessageA("Tao::ExecMsg")
Expand Down Expand Up @@ -578,18 +579,23 @@ lazy_static! {
RegisterWindowMessageA("Tao::CancelWaitUntil")
}
};
// Message sent by a `Window` when it wants to be destroyed by the main thread.
// WPARAM and LPARAM are unused.
/// Message sent by a `Window` when it wants to be destroyed by the main thread.
/// WPARAM and LPARAM are unused.
pub static ref DESTROY_MSG_ID: u32 = {
unsafe {
RegisterWindowMessageA("Tao::DestroyMsg")
}
};
// WPARAM is a bool specifying the `WindowFlags::MARKER_RETAIN_STATE_ON_SIZE` flag. See the
// documentation in the `window_state` module for more information.
/// WPARAM is a bool specifying the `WindowFlags::MARKER_RETAIN_STATE_ON_SIZE` flag. See the
/// documentation in the `window_state` module for more information.
pub static ref SET_RETAIN_STATE_ON_SIZE_MSG_ID: u32 = unsafe {
RegisterWindowMessageA("Tao::SetRetainMaximized")
};
/// 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.
pub static ref S_U_TASKBAR_RESTART: u32 = unsafe {
RegisterWindowMessageA("TaskbarCreated")
};
static ref THREAD_EVENT_TARGET_WINDOW_CLASS: Vec<u16> = unsafe {
let class_name= util::encode_wide("Tao Thread Event Target");

Expand Down Expand Up @@ -2034,6 +2040,9 @@ unsafe fn public_window_callback_inner<T: 'static>(
f.set(WindowFlags::MARKER_RETAIN_STATE_ON_SIZE, wparam.0 != 0)
});
result = ProcResult::Value(LRESULT(0));
} else if msg == *S_U_TASKBAR_RESTART {
let window_state = subclass_input.window_state.lock();
set_skip_taskbar(window, window_state.skip_taskbar);
}
}
};
Expand Down
59 changes: 45 additions & 14 deletions src/platform_impl/windows/system_tray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

use super::{
event_loop::S_U_TASKBAR_RESTART,
menu::{subclass_proc as menu_subclass_proc, Menu, MenuHandler},
util, OsError,
};
Expand All @@ -27,12 +28,15 @@ use windows::{

const WM_USER_TRAYICON: u32 = 6001;
const WM_USER_UPDATE_TRAYMENU: u32 = 6002;
const TRAYICON_UID: u32 = 6003;
const TRAY_SUBCLASS_ID: usize = 6004;
const TRAY_MENU_SUBCLASS_ID: usize = 6005;
const WM_USER_UPDATE_TRAYICON: u32 = 6003;
const TRAYICON_UID: u32 = 6004;
const TRAY_SUBCLASS_ID: usize = 6005;
const TRAY_MENU_SUBCLASS_ID: usize = 6006;

struct TrayLoopData {
hwnd: HWND,
hmenu: Option<HMENU>,
icon: Icon,
sender: Box<dyn Fn(Event<'static, ()>)>,
}

Expand Down Expand Up @@ -81,34 +85,28 @@ impl SystemTrayBuilder {
hinstance,
std::ptr::null_mut(),
);

if !IsWindow(hwnd).as_bool() {
return Err(os_error!(OsError::CreationError(
"Unable to get valid mutable pointer for CreateWindowEx"
)));
}

let mut nid = NOTIFYICONDATAW {
uFlags: NIF_MESSAGE,
hWnd: hwnd,
uID: TRAYICON_UID,
uCallbackMessage: WM_USER_TRAYICON,
..std::mem::zeroed()
};
let hicon = self.icon.inner.as_raw_handle();

if !Shell_NotifyIconW(NIM_ADD, &mut nid as _).as_bool() {
if !register_tray_icon(hwnd, hicon) {
return Err(os_error!(OsError::CreationError(
"Error with shellapi::Shell_NotifyIconW"
)));
}

let mut system_tray = SystemTray { hwnd };
system_tray.set_icon(self.icon);
let system_tray = SystemTray { hwnd: hwnd.clone() };

// system_tray event handler
let event_loop_runner = window_target.p.runner_shared.clone();
let traydata = TrayLoopData {
hwnd,
hmenu,
icon: self.icon,
sender: Box::new(move |event| {
if let Ok(e) = event.map_nonuser_event() {
event_loop_runner.send_event(e)
Expand Down Expand Up @@ -162,6 +160,14 @@ impl SystemTray {
if !Shell_NotifyIconW(NIM_MODIFY, &mut nid as _).as_bool() {
debug!("Error setting icon");
}

// send the new icon to the subclass proc to store it in the tray data
SendMessageW(
self.hwnd,
WM_USER_UPDATE_TRAYICON,
WPARAM(Box::into_raw(Box::new(icon)) as _),
LPARAM(0),
);
}
}

Expand Down Expand Up @@ -217,6 +223,18 @@ unsafe extern "system" fn tray_subclass_proc(
subclass_input.hmenu = Some(HMENU(wparam.0 as _));
}

if msg == WM_USER_UPDATE_TRAYICON {
let icon = wparam.0 as *mut Icon;
subclass_input.icon = (*icon).clone();
}

if msg == *S_U_TASKBAR_RESTART {
register_tray_icon(
subclass_input.hwnd,
subclass_input.icon.inner.as_raw_handle(),
);
}

if msg == WM_USER_TRAYICON
&& matches!(
lparam.0 as u32,
Expand Down Expand Up @@ -295,3 +313,16 @@ unsafe fn show_tray_menu(hwnd: HWND, menu: HMENU, x: i32, y: i32) {
std::ptr::null_mut(),
);
}

unsafe fn register_tray_icon(hwnd: HWND, hicon: HICON) -> bool {
let mut nid = NOTIFYICONDATAW {
uFlags: NIF_MESSAGE | NIF_ICON,
hWnd: hwnd,
hIcon: hicon,
uID: TRAYICON_UID,
uCallbackMessage: WM_USER_TRAYICON,
..std::mem::zeroed()
};

Shell_NotifyIconW(NIM_ADD, &mut nid as _).as_bool()
}
25 changes: 13 additions & 12 deletions src/platform_impl/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -785,18 +785,8 @@ impl Window {

#[inline]
pub(crate) fn set_skip_taskbar(&self, skip: bool) {
unsafe {
com_initialized();
let taskbar_list: ITaskbarList =
CoCreateInstance(&TaskbarList, None, CLSCTX_SERVER).expect("failed to create TaskBarList");
if skip {
taskbar_list
.DeleteTab(self.hwnd())
.expect("DeleteTab failed");
} else {
taskbar_list.AddTab(self.hwnd()).expect("AddTab failed");
}
}
self.window_state.lock().skip_taskbar = skip;
unsafe { set_skip_taskbar(self.hwnd(), skip) };
}
}

Expand Down Expand Up @@ -1154,6 +1144,17 @@ unsafe fn force_window_active(handle: HWND) {
SetForegroundWindow(handle);
}

pub(crate) unsafe fn set_skip_taskbar(hwnd: HWND, skip: bool) {
com_initialized();
let taskbar_list: ITaskbarList =
CoCreateInstance(&TaskbarList, None, CLSCTX_SERVER).expect("failed to create TaskBarList");
if skip {
taskbar_list.DeleteTab(hwnd).expect("DeleteTab failed");
} else {
taskbar_list.AddTab(hwnd).expect("AddTab failed");
}
}

pub fn hit_test(hwnd: *mut libc::c_void, cx: i32, cy: i32) -> LRESULT {
let hwnd = HWND(hwnd as _);
let mut window_rect = RECT::default();
Expand Down
4 changes: 4 additions & 0 deletions src/platform_impl/windows/window_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub struct WindowState {
pub saved_window: Option<SavedWindow>,
pub scale_factor: f64,

pub skip_taskbar: bool,

pub modifiers_state: ModifiersState,
pub fullscreen: Option<Fullscreen>,
pub current_theme: Theme,
Expand Down Expand Up @@ -122,6 +124,8 @@ impl WindowState {
saved_window: None,
scale_factor,

skip_taskbar: false,

modifiers_state: ModifiersState::default(),
fullscreen: None,
current_theme,
Expand Down

0 comments on commit 9450329

Please sign in to comment.