diff --git a/CHANGELOG.md b/CHANGELOG.md index c7d66aafb8..5798fe9c5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ And please only add new entries to the top of this list, right below the `# Unre # Unreleased -- On Windows, Added `EventLoopBuilderExtWindows::with_msg_hook` +- On Windows, added `WindowExtWindows::set_skip_taskbar` and `WindowBuilderExtWindows::with_skip_taskbar`. +- On Windows, added `EventLoopBuilderExtWindows::with_msg_hook`. - On Windows, remove internally unique DC per window. - macOS: Remove the need to call `set_ime_position` after moving the window. - Added `Window::is_visible`. diff --git a/src/platform/windows.rs b/src/platform/windows.rs index c10eb4bcb7..2e5d05a738 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -140,6 +140,9 @@ pub trait WindowExtWindows { /// Returns the current window theme. fn theme(&self) -> Theme; + + /// Whether to show or hide the window icon in the taskbar. + fn set_skip_taskbar(&self, skip: bool); } impl WindowExtWindows for Window { @@ -167,6 +170,11 @@ impl WindowExtWindows for Window { fn theme(&self) -> Theme { self.window.theme() } + + #[inline] + fn set_skip_taskbar(&self, skip: bool) { + self.window.set_skip_taskbar(skip) + } } /// Additional methods on `WindowBuilder` that are specific to Windows. @@ -218,6 +226,9 @@ pub trait WindowBuilderExtWindows { /// Forces a theme or uses the system settings if `None` was provided. fn with_theme(self, theme: Option) -> WindowBuilder; + + /// Whether show or hide the window icon in the taskbar. + fn with_skip_taskbar(self, skip: bool) -> WindowBuilder; } impl WindowBuilderExtWindows for WindowBuilder { @@ -262,6 +273,12 @@ impl WindowBuilderExtWindows for WindowBuilder { self.platform_specific.preferred_theme = theme; self } + + #[inline] + fn with_skip_taskbar(mut self, skip: bool) -> WindowBuilder { + self.platform_specific.skip_taskbar = skip; + self + } } /// Additional methods on `MonitorHandle` that are specific to Windows. diff --git a/src/platform_impl/windows/definitions.rs b/src/platform_impl/windows/definitions.rs index 66818f3dc5..b4a461c947 100644 --- a/src/platform_impl/windows/definitions.rs +++ b/src/platform_impl/windows/definitions.rs @@ -10,7 +10,6 @@ use windows_sys::{ System::Com::{ IAdviseSink, IDataObject, IEnumFORMATETC, IEnumSTATDATA, FORMATETC, STGMEDIUM, }, - UI::Shell::ITaskbarList, }, }; @@ -111,6 +110,11 @@ pub struct ITaskbarListVtbl { pub SetActiveAlt: unsafe extern "system" fn(This: *mut ITaskbarList, hwnd: HWND) -> HRESULT, } +#[repr(C)] +pub struct ITaskbarList { + pub lpVtbl: *const ITaskbarListVtbl, +} + #[repr(C)] pub struct ITaskbarList2Vtbl { pub parent: ITaskbarListVtbl, @@ -120,6 +124,7 @@ pub struct ITaskbarList2Vtbl { fFullscreen: BOOL, ) -> HRESULT, } + #[repr(C)] pub struct ITaskbarList2 { pub lpVtbl: *const ITaskbarList2Vtbl, @@ -132,6 +137,13 @@ pub const CLSID_TaskbarList: GUID = GUID { data4: [0x95, 0x8a, 0x00, 0x60, 0x97, 0xc9, 0xa0, 0x90], }; +pub const IID_ITaskbarList: GUID = GUID { + data1: 0x56FDF342, + data2: 0xFD6D, + data3: 0x11D0, + data4: [0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90], +}; + pub const IID_ITaskbarList2: GUID = GUID { data1: 0x602d4995, data2: 0xb13a, diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 67fc7a7666..56c83ce7a1 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -35,6 +35,7 @@ pub struct PlatformSpecificWindowBuilderAttributes { pub no_redirection_bitmap: bool, pub drag_and_drop: bool, pub preferred_theme: Option, + pub skip_taskbar: bool, } impl Default for PlatformSpecificWindowBuilderAttributes { @@ -46,6 +47,7 @@ impl Default for PlatformSpecificWindowBuilderAttributes { no_redirection_bitmap: false, drag_and_drop: true, preferred_theme: None, + skip_taskbar: false, } } } diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index d221f1f041..a8d502aac9 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -62,7 +62,9 @@ use crate::{ monitor::MonitorHandle as RootMonitorHandle, platform_impl::platform::{ dark_mode::try_theme, - definitions::{CLSID_TaskbarList, IID_ITaskbarList2, ITaskbarList2}, + definitions::{ + CLSID_TaskbarList, IID_ITaskbarList, IID_ITaskbarList2, ITaskbarList, ITaskbarList2, + }, dpi::{dpi_to_scale_factor, enable_non_client_dpi_scaling, hwnd_dpi}, drop_handler::FileDropHandler, event_loop::{self, EventLoopWindowTarget, DESTROY_MSG_ID}, @@ -665,6 +667,43 @@ impl Window { self.window_state.lock().current_theme } + #[inline] + pub fn set_skip_taskbar(&self, skip: bool) { + com_initialized(); + unsafe { + TASKBAR_LIST.with(|task_bar_list_ptr| { + let mut task_bar_list = task_bar_list_ptr.get(); + + if task_bar_list.is_null() { + let hr = CoCreateInstance( + &CLSID_TaskbarList, + ptr::null_mut(), + CLSCTX_ALL, + &IID_ITaskbarList, + &mut task_bar_list as *mut _ as *mut _, + ); + + let hr_init = (*(*task_bar_list).lpVtbl).HrInit; + + if hr != S_OK || hr_init(task_bar_list.cast()) != S_OK { + // In some old windows, the taskbar object could not be created, we just ignore it + return; + } + task_bar_list_ptr.set(task_bar_list) + } + + task_bar_list = task_bar_list_ptr.get(); + if skip { + let delete_tab = (*(*task_bar_list).lpVtbl).DeleteTab; + delete_tab(task_bar_list, self.window.0); + } else { + let add_tab = (*(*task_bar_list).lpVtbl).AddTab; + add_tab(task_bar_list, self.window.0); + } + }); + } + } + #[inline] pub fn focus_window(&self) { let window = self.window.clone(); @@ -839,6 +878,8 @@ impl<'a, T: 'static> InitData<'a, T> { DeleteObject(region); } + win.set_skip_taskbar(self.pl_attribs.skip_taskbar); + let attributes = self.attributes.clone(); // Set visible before setting the size to ensure the @@ -999,7 +1040,8 @@ thread_local! { } }; - static TASKBAR_LIST: Cell<*mut ITaskbarList2> = Cell::new(ptr::null_mut()); + static TASKBAR_LIST: Cell<*mut ITaskbarList> = Cell::new(ptr::null_mut()); + static TASKBAR_LIST2: Cell<*mut ITaskbarList2> = Cell::new(ptr::null_mut()); } pub fn com_initialized() { @@ -1017,30 +1059,30 @@ pub fn com_initialized() { unsafe fn taskbar_mark_fullscreen(handle: HWND, fullscreen: bool) { com_initialized(); - TASKBAR_LIST.with(|task_bar_list_ptr| { - let mut task_bar_list = task_bar_list_ptr.get(); + TASKBAR_LIST2.with(|task_bar_list2_ptr| { + let mut task_bar_list2 = task_bar_list2_ptr.get(); - if task_bar_list.is_null() { + if task_bar_list2.is_null() { let hr = CoCreateInstance( &CLSID_TaskbarList, ptr::null_mut(), CLSCTX_ALL, &IID_ITaskbarList2, - &mut task_bar_list as *mut _ as *mut _, + &mut task_bar_list2 as *mut _ as *mut _, ); - let hr_init = (*(*task_bar_list).lpVtbl).parent.HrInit; + let hr_init = (*(*task_bar_list2).lpVtbl).parent.HrInit; - if hr != S_OK || hr_init(task_bar_list.cast()) != S_OK { + if hr != S_OK || hr_init(task_bar_list2.cast()) != S_OK { // In some old windows, the taskbar object could not be created, we just ignore it return; } - task_bar_list_ptr.set(task_bar_list) + task_bar_list2_ptr.set(task_bar_list2) } - task_bar_list = task_bar_list_ptr.get(); - let mark_fullscreen_window = (*(*task_bar_list).lpVtbl).MarkFullscreenWindow; - mark_fullscreen_window(task_bar_list, handle, if fullscreen { 1 } else { 0 }); + task_bar_list2 = task_bar_list2_ptr.get(); + let mark_fullscreen_window = (*(*task_bar_list2).lpVtbl).MarkFullscreenWindow; + mark_fullscreen_window(task_bar_list2, handle, if fullscreen { 1 } else { 0 }); }) }