// Copyright (c) Microsoft Corporation // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // Code forked from Betsegaw Tadele's https://github.com/betsegaw/windowwalker/ using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Threading; using Microsoft.CmdPal.Ext.WindowWalker.Helpers; namespace Microsoft.CmdPal.Ext.WindowWalker.Components; /// /// Class that represents the state of the desktops windows /// internal sealed class OpenWindows { /// /// Used to enforce single execution of EnumWindows /// private static readonly Lock EnumWindowsLock = new(); /// /// PowerLauncher main executable /// private static readonly string? PowerLauncherExe = Path.GetFileName(Environment.ProcessPath); /// /// List of all the open windows /// private readonly List _windows = []; /// /// An instance of the class OpenWindows /// private static OpenWindows? _instance; /// /// Gets the list of all open windows /// internal List Windows => [.._windows]; /// /// Gets an instance property of this class that makes sure that /// the first instance gets created and that all the requests /// end up at that one instance /// internal static OpenWindows Instance { get { _instance ??= new OpenWindows(); return _instance; } } /// /// Initializes a new instance of the class. /// Private constructor to make sure there is never /// more than one instance of this class /// private OpenWindows() { } /// /// Updates the list of open windows /// internal void UpdateOpenWindowsList(CancellationToken cancellationToken) { var tokenHandle = GCHandle.Alloc(cancellationToken); try { var tokenHandleParam = GCHandle.ToIntPtr(tokenHandle); lock (EnumWindowsLock) { _windows.Clear(); var callbackptr = new EnumWindowsProc(WindowEnumerationCallBack); _ = NativeMethods.EnumWindows(callbackptr, tokenHandleParam); } } finally { if (tokenHandle.IsAllocated) { tokenHandle.Free(); } } } /// /// Call back method for window enumeration /// /// The handle to the current window being enumerated /// Value being passed from the caller (we don't use this but might come in handy /// in the future /// true to make sure to continue enumeration internal bool WindowEnumerationCallBack(IntPtr hwnd, IntPtr lParam) { var tokenHandle = GCHandle.FromIntPtr(lParam); var target = (CancellationToken?)tokenHandle.Target ?? CancellationToken.None; var cancellationToken = target; if (cancellationToken.IsCancellationRequested) { // Stop enumeration return false; } var newWindow = new Window(hwnd); if (newWindow.IsWindow && newWindow.Visible && newWindow.IsOwner && (!newWindow.IsToolWindow || newWindow.IsAppWindow) && !newWindow.TaskListDeleted && (newWindow.Desktop.IsVisible || !SettingsManager.Instance.ResultsFromVisibleDesktopOnly || WindowWalkerCommandsProvider.VirtualDesktopHelperInstance.GetDesktopCount() < 2) && newWindow.ClassName != "Windows.UI.Core.CoreWindow" && newWindow.Process.Name != PowerLauncherExe) { // To hide (not add) preloaded uwp app windows that are invisible to the user and other cloaked windows, we check the cloak state. (Issue #13637.) // (If user asking to see cloaked uwp app windows again we can add an optional plugin setting in the future.) if (!newWindow.IsCloaked || newWindow.GetWindowCloakState() == Window.WindowCloakState.OtherDesktop) { _windows.Add(newWindow); } } return true; } }