From c92c62864691abfe9f9a0d05454af081f363e970 Mon Sep 17 00:00:00 2001 From: amrbashir Date: Tue, 1 Feb 2022 13:11:52 +0200 Subject: [PATCH 1/3] feat(Windows): add skip taskbar methods --- CHANGELOG.md | 1 + src/platform/windows.rs | 17 +++++++++++ src/platform_impl/windows/mod.rs | 2 ++ src/platform_impl/windows/window.rs | 44 +++++++++++++++++++++++++++-- 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34824dcf0c..7721b40e72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre # Unreleased +- On Widnows, added `WindowExtWindows::set_skip_taskbar` and `WindowBuilderExtWindows::with_skip_taskbar`. - **Breaking:** Bump `ndk` version to 0.6, ndk-sys to `v0.3`, `ndk-glue` to `0.6`. - Remove no longer needed `WINIT_LINK_COLORSYNC` environment variable. - **Breaking:** Rename the `Exit` variant of `ControlFlow` to `ExitWithCode`, which holds a value to control the exit code after running. Add an `Exit` constant which aliases to `ExitWithCode(0)` instead to avoid major breakage. This shouldn't affect most existing programs. diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 3499ba77fd..b1d0678380 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -97,6 +97,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 { @@ -124,6 +127,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. @@ -173,6 +181,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 { @@ -217,6 +228,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/mod.rs b/src/platform_impl/windows/mod.rs index 9215a92306..2020ceb0ac 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -30,6 +30,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 { @@ -41,6 +42,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 0617630488..50db74d08a 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -25,7 +25,7 @@ use winapi::{ objbase::COINIT_APARTMENTTHREADED, ole2, oleidl::LPDROPTARGET, - shobjidl_core::{CLSID_TaskbarList, ITaskbarList2}, + shobjidl_core::{CLSID_TaskbarList, ITaskbarList, ITaskbarList2}, wingdi::{CreateRectRgn, DeleteObject}, winnt::{LPCWSTR, SHORT}, winuser, @@ -651,6 +651,41 @@ 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() { + use winapi::{shared::winerror::S_OK, Interface}; + + let hr = combaseapi::CoCreateInstance( + &CLSID_TaskbarList, + ptr::null_mut(), + combaseapi::CLSCTX_ALL, + &ITaskbarList::uuidof(), + &mut task_bar_list as *mut _ as *mut _, + ); + + if hr != S_OK || (*task_bar_list).HrInit() != 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 { + (*task_bar_list).DeleteTab(self.window.0); + } else { + (*task_bar_list).AddTab(self.window.0); + } + }); + } + } + #[inline] pub fn focus_window(&self) { let window = self.window.clone(); @@ -828,6 +863,8 @@ impl<'a, T: 'static> InitData<'a, T> { DeleteObject(region as _); } + win.set_skip_taskbar(self.pl_attribs.skip_taskbar); + let attributes = self.attributes.clone(); // Set visible before setting the size to ensure the @@ -994,7 +1031,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() { @@ -1012,7 +1050,7 @@ pub fn com_initialized() { unsafe fn taskbar_mark_fullscreen(handle: HWND, fullscreen: bool) { com_initialized(); - TASKBAR_LIST.with(|task_bar_list_ptr| { + TASKBAR_LIST2.with(|task_bar_list_ptr| { let mut task_bar_list = task_bar_list_ptr.get(); if task_bar_list.is_null() { From 3c0b3916f8a29000bc4bd191a6627ae53f1af010 Mon Sep 17 00:00:00 2001 From: amrbashir Date: Tue, 1 Feb 2022 13:40:39 +0200 Subject: [PATCH 2/3] fix typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7721b40e72..51c0a8b4e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre # Unreleased -- On Widnows, added `WindowExtWindows::set_skip_taskbar` and `WindowBuilderExtWindows::with_skip_taskbar`. +- On Windows, added `WindowExtWindows::set_skip_taskbar` and `WindowBuilderExtWindows::with_skip_taskbar`. - **Breaking:** Bump `ndk` version to 0.6, ndk-sys to `v0.3`, `ndk-glue` to `0.6`. - Remove no longer needed `WINIT_LINK_COLORSYNC` environment variable. - **Breaking:** Rename the `Exit` variant of `ControlFlow` to `ExitWithCode`, which holds a value to control the exit code after running. Add an `Exit` constant which aliases to `ExitWithCode(0)` instead to avoid major breakage. This shouldn't affect most existing programs. From 17256104022fa2e7bff9848dea820985a7e3ee98 Mon Sep 17 00:00:00 2001 From: amrbashir Date: Tue, 29 Mar 2022 11:40:58 +0200 Subject: [PATCH 3/3] migrate to windows-sys --- src/platform_impl/windows/definitions.rs | 14 +++++++- src/platform_impl/windows/window.rs | 42 +++++++++++++----------- 2 files changed, 36 insertions(+), 20 deletions(-) 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/window.rs b/src/platform_impl/windows/window.rs index ddc82e2bee..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}, @@ -673,17 +675,17 @@ impl Window { let mut task_bar_list = task_bar_list_ptr.get(); if task_bar_list.is_null() { - use winapi::{shared::winerror::S_OK, Interface}; - - let hr = combaseapi::CoCreateInstance( + let hr = CoCreateInstance( &CLSID_TaskbarList, ptr::null_mut(), - combaseapi::CLSCTX_ALL, - &ITaskbarList::uuidof(), + CLSCTX_ALL, + &IID_ITaskbarList, &mut task_bar_list as *mut _ as *mut _, ); - if hr != S_OK || (*task_bar_list).HrInit() != S_OK { + 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; } @@ -692,9 +694,11 @@ impl Window { task_bar_list = task_bar_list_ptr.get(); if skip { - (*task_bar_list).DeleteTab(self.window.0); + let delete_tab = (*(*task_bar_list).lpVtbl).DeleteTab; + delete_tab(task_bar_list, self.window.0); } else { - (*task_bar_list).AddTab(self.window.0); + let add_tab = (*(*task_bar_list).lpVtbl).AddTab; + add_tab(task_bar_list, self.window.0); } }); } @@ -1055,30 +1059,30 @@ pub fn com_initialized() { unsafe fn taskbar_mark_fullscreen(handle: HWND, fullscreen: bool) { com_initialized(); - TASKBAR_LIST2.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 }); }) }