diff --git a/packages/wm/src/common/commands/platform_sync.rs b/packages/wm/src/common/commands/platform_sync.rs index e9d0d053..ba41b26f 100644 --- a/packages/wm/src/common/commands/platform_sync.rs +++ b/packages/wm/src/common/commands/platform_sync.rs @@ -153,6 +153,18 @@ fn redraw_containers( ) { warn!("Failed to set window position: {}", err); } + + let taskbar_visibility = if config.value.general.show_all_in_taskbar { + true + } else { + is_visible + }; + + if let Err(err) = + window.native().set_taskbar_visibility(taskbar_visibility) + { + warn!("Failed to set taskbar visibility: {}", err); + } } Ok(()) diff --git a/packages/wm/src/common/platform/native_window.rs b/packages/wm/src/common/platform/native_window.rs index b75df34e..e0a1555e 100644 --- a/packages/wm/src/common/platform/native_window.rs +++ b/packages/wm/src/common/platform/native_window.rs @@ -10,12 +10,16 @@ use windows::{ DWMWA_WINDOW_CORNER_PREFERENCE, DWMWCP_DEFAULT, DWMWCP_DONOTROUND, DWMWCP_ROUND, DWMWCP_ROUNDSMALL, }, - System::Threading::{ - OpenProcess, QueryFullProcessImageNameW, PROCESS_NAME_WIN32, - PROCESS_QUERY_LIMITED_INFORMATION, + System::{ + Com::{CoCreateInstance, CLSCTX_SERVER}, + Threading::{ + OpenProcess, QueryFullProcessImageNameW, PROCESS_NAME_WIN32, + PROCESS_QUERY_LIMITED_INFORMATION, + }, }, UI::{ Input::KeyboardAndMouse::{SendInput, INPUT, INPUT_MOUSE}, + Shell::{ITaskbarList, TaskbarList}, WindowsAndMessaging::{ EnumWindows, GetClassNameW, GetWindow, GetWindowLongPtrW, GetWindowRect, GetWindowTextW, GetWindowThreadProcessId, IsIconic, @@ -567,6 +571,29 @@ impl NativeWindow { }) } + /// Adds or removes the window from the native taskbar. + /// + /// Hidden windows (SW_HIDE) cannot be forced to be shown in the taskbar. + /// Cloaked windows are normally always shown in the taskbar, but can be + /// manually toggled. + pub fn set_taskbar_visibility( + &self, + visible: bool, + ) -> anyhow::Result<()> { + COM_INIT.with(|_| -> anyhow::Result<()> { + let taskbar_list: ITaskbarList = + unsafe { CoCreateInstance(&TaskbarList, None, CLSCTX_SERVER)? }; + + if visible { + unsafe { taskbar_list.AddTab(HWND(self.handle))? }; + } else { + unsafe { taskbar_list.DeleteTab(HWND(self.handle))? }; + } + + Ok(()) + }) + } + pub fn set_position( &self, state: &WindowState, @@ -671,10 +698,8 @@ impl NativeWindow { } }; - // Whether to show or hide the window. - self.set_visible(is_visible, hide_method)?; - - Ok(()) + // Whether to hide or show the window. + self.set_visible(is_visible, hide_method) } } diff --git a/packages/wm/src/user_config.rs b/packages/wm/src/user_config.rs index 9802f5bd..72e390f2 100644 --- a/packages/wm/src/user_config.rs +++ b/packages/wm/src/user_config.rs @@ -417,6 +417,10 @@ pub struct GeneralConfig { /// How windows should be hidden when switching workspaces. #[serde(default)] pub hide_method: HideMethod, + + /// Affects which windows get shown in the native Windows taskbar. + #[serde(default = "default_bool::")] + pub show_all_in_taskbar: bool, } #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] diff --git a/resources/assets/sample-config.yaml b/resources/assets/sample-config.yaml index 7cf6785e..ea3de60d 100644 --- a/resources/assets/sample-config.yaml +++ b/resources/assets/sample-config.yaml @@ -28,12 +28,16 @@ general: trigger: 'monitor_focus' # How windows should be hidden when switching workspaces. - # - 'cloak': Recommended. Hides windows with no animation and keeps them - # visible in the taskbar. + # - 'cloak': Recommended. Hides windows with no animation. # - 'hide': Legacy method (v3.5 and earlier) that has a brief animation, # but has stability issues with some apps. hide_method: 'cloak' + # Affects which windows get shown in the native Windows taskbar. + # - 'true': Show all windows (regardless of workspace). + # - 'false': Only show windows from the currently shown workspaces. + show_all_in_taskbar: false + gaps: # Whether to scale the gaps with the DPI of the monitor. scale_with_dpi: true