2022-03-07 12:45:29 +01:00
// 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.
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.Runtime.InteropServices ;
2023-12-28 13:37:13 +03:00
using System.Text ;
2024-09-16 16:09:43 -04:00
2023-11-23 17:16:12 +01:00
using Common.UI ;
2022-03-07 12:45:29 +01:00
using Microsoft.Win32 ;
using Wox.Plugin.Common.VirtualDesktop.Interop ;
using Wox.Plugin.Common.Win32 ;
using Wox.Plugin.Logger ;
using Wox.Plugin.Properties ;
namespace Wox.Plugin.Common.VirtualDesktop.Helper
{
/// <summary>
/// Helper class to work with Virtual Desktops.
2023-10-04 11:07:40 +01:00
/// This helper uses only public available and documented COM-Interfaces or information from registry.
2022-03-07 12:45:29 +01:00
/// </summary>
/// <remarks>
/// To use this helper you have to create an instance of it and access the method via the helper instance.
/// We are only allowed to use public documented com interfaces.
/// </remarks>
2022-09-28 18:18:55 +02:00
/// <SeeAlso href="https://learn.microsoft.com/windows/win32/api/shobjidl_core/nn-shobjidl_core-ivirtualdesktopmanager">Documentation of IVirtualDesktopManager interface</SeeAlso>
/// <SeeAlso href="https://learn.microsoft.com/archive/blogs/winsdk/virtual-desktop-switching-in-windows-10">CSharp example code for IVirtualDesktopManager</SeeAlso>
2022-03-07 12:45:29 +01:00
public class VirtualDesktopHelper
{
2022-03-14 16:40:27 +01:00
/// <summary>
/// Are we running on Windows 11
/// </summary>
2023-11-23 17:16:12 +01:00
private readonly bool _isWindowsEleven ;
2022-03-14 16:40:27 +01:00
2022-03-07 12:45:29 +01:00
/// <summary>
/// Instance of "Virtual Desktop Manager"
/// </summary>
private readonly IVirtualDesktopManager _virtualDesktopManager ;
/// <summary>
/// Internal settings to enable automatic update of desktop list.
/// This will be off by default to avoid to many registry queries.
/// </summary>
private readonly bool _desktopListAutoUpdate ;
/// <summary>
/// List of all available Virtual Desktop in their real order
/// The order and list in the registry is always up to date
/// </summary>
2023-11-23 17:16:12 +01:00
private List < Guid > _availableDesktops = new List < Guid > ( ) ;
2022-03-07 12:45:29 +01:00
/// <summary>
/// Id of the current visible Desktop.
/// </summary>
2023-11-23 17:16:12 +01:00
private Guid _currentDesktop ;
2022-03-07 12:45:29 +01:00
2023-12-28 13:37:13 +03:00
private static readonly CompositeFormat VirtualDesktopHelperDesktop = System . Text . CompositeFormat . Parse ( Properties . Resources . VirtualDesktopHelper_Desktop ) ;
2022-03-07 12:45:29 +01:00
/// <summary>
/// Initializes a new instance of the <see cref="VirtualDesktopHelper"/> class.
/// </summary>
/// <param name="desktopListUpdate">Setting to configure if the list of available desktops should update automatically or only when calling <see cref="UpdateDesktopList"/>. Per default this is set to manual update (false) to have less registry queries.</param>
public VirtualDesktopHelper ( bool desktopListUpdate = false )
{
try
{
_virtualDesktopManager = ( IVirtualDesktopManager ) new CVirtualDesktopManager ( ) ;
}
catch ( COMException ex )
{
2022-03-14 16:40:27 +01:00
Log . Exception ( "Initialization of <VirtualDesktopHelper> failed: An exception was thrown when creating the instance of COM interface <IVirtualDesktopManager>." , ex , typeof ( VirtualDesktopHelper ) ) ;
2022-03-07 12:45:29 +01:00
return ;
}
2023-11-23 17:16:12 +01:00
_isWindowsEleven = OSVersionHelper . IsWindows11 ( ) ;
2022-03-07 12:45:29 +01:00
_desktopListAutoUpdate = desktopListUpdate ;
UpdateDesktopList ( ) ;
}
/// <summary>
/// Gets a value indicating whether the Virtual Desktop Manager is initialized successfully
/// </summary>
public bool VirtualDesktopManagerInitialized
{
get { return _virtualDesktopManager ! = null ; }
}
/// <summary>
/// Method to update the list of Virtual Desktops from Registry
/// The data in the registry are always up to date
/// </summary>
2024-12-06 06:33:08 -10:00
/// <remarks>If we cannot read from registry, we set the list/guid to empty values.</remarks>
2022-03-07 12:45:29 +01:00
public void UpdateDesktopList ( )
{
2022-03-14 16:40:27 +01:00
int userSessionId = Process . GetCurrentProcess ( ) . SessionId ;
2023-11-23 17:16:12 +01:00
string registrySessionVirtualDesktops = $"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SessionInfo\\{userSessionId}\\VirtualDesktops" ; // Windows 10
string registryExplorerVirtualDesktops = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops" ; // Windows 11
2022-03-07 12:45:29 +01:00
2022-03-14 16:40:27 +01:00
// List of all desktops
2023-11-23 17:16:12 +01:00
using RegistryKey virtualDesktopKey = Registry . CurrentUser . OpenSubKey ( registryExplorerVirtualDesktops , false ) ;
if ( virtualDesktopKey ! = null )
2022-03-07 12:45:29 +01:00
{
2023-11-23 17:16:12 +01:00
byte [ ] allDeskValue = ( byte [ ] ) virtualDesktopKey . GetValue ( "VirtualDesktopIDs" , null ) ;
if ( allDeskValue ! = null )
2022-03-07 12:45:29 +01:00
{
2023-11-23 17:16:12 +01:00
// We clear only, if we can read from registry. Otherwise we keep the existing values.
_availableDesktops . Clear ( ) ;
// Each guid has a length of 16 elements
int numberOfDesktops = allDeskValue . Length / 16 ;
for ( int i = 0 ; i < numberOfDesktops ; i + + )
{
byte [ ] guidArray = new byte [ 16 ] ;
Array . ConstrainedCopy ( allDeskValue , i * 16 , guidArray , 0 , 16 ) ;
_availableDesktops . Add ( new Guid ( guidArray ) ) ;
}
}
else
{
Log . Debug ( "VirtualDesktopHelper.UpdateDesktopList() failed to read the list of existing desktops form registry." , typeof ( VirtualDesktopHelper ) ) ;
2022-03-07 12:45:29 +01:00
}
}
// Guid for current desktop
2023-11-23 17:16:12 +01:00
var virtualDesktopsKeyName = _isWindowsEleven ? registryExplorerVirtualDesktops : registrySessionVirtualDesktops ;
using RegistryKey virtualDesktopsKey = Registry . CurrentUser . OpenSubKey ( virtualDesktopsKeyName , false ) ;
if ( virtualDesktopsKey ! = null )
2022-03-07 12:45:29 +01:00
{
2023-11-23 17:16:12 +01:00
var currentVirtualDesktopValue = virtualDesktopsKey . GetValue ( "CurrentVirtualDesktop" , null ) ;
if ( currentVirtualDesktopValue ! = null )
{
_currentDesktop = new Guid ( ( byte [ ] ) currentVirtualDesktopValue ) ;
}
else
{
// The registry value is missing when the user hasn't switched the desktop at least one time before reading the registry. In this case we can set it to desktop one.
// We can only set it to desktop one, if we have at least one desktop in the desktops list. Otherwise we keep the existing value.
Log . Debug ( "VirtualDesktopHelper.UpdateDesktopList() failed to read the id for the current desktop form registry." , typeof ( VirtualDesktopHelper ) ) ;
_currentDesktop = _availableDesktops . Count > = 1 ? _availableDesktops [ 0 ] : _currentDesktop ;
}
2022-03-07 12:45:29 +01:00
}
}
/// <summary>
/// Returns an ordered list with the ids of all existing desktops. The list is ordered in the same way as the existing desktops.
/// </summary>
/// <returns>List of desktop ids or an empty list on failure.</returns>
public List < Guid > GetDesktopIdList ( )
{
if ( _desktopListAutoUpdate )
{
UpdateDesktopList ( ) ;
}
2023-11-23 17:16:12 +01:00
return _availableDesktops ;
2022-03-07 12:45:29 +01:00
}
/// <summary>
/// Returns an ordered list with of all existing desktops and their properties. The list is ordered in the same way as the existing desktops.
/// </summary>
/// <returns>List of desktops or an empty list on failure.</returns>
public List < VDesktop > GetDesktopList ( )
{
if ( _desktopListAutoUpdate )
{
UpdateDesktopList ( ) ;
}
List < VDesktop > list = new List < VDesktop > ( ) ;
2023-11-23 17:16:12 +01:00
foreach ( Guid d in _availableDesktops )
2022-03-07 12:45:29 +01:00
{
list . Add ( CreateVDesktopInstance ( d ) ) ;
}
return list ;
}
/// <summary>
/// Returns the count of existing desktops
/// </summary>
/// <returns>Number of existing desktops or zero on failure.</returns>
public int GetDesktopCount ( )
{
if ( _desktopListAutoUpdate )
{
UpdateDesktopList ( ) ;
}
2023-11-23 17:16:12 +01:00
return _availableDesktops . Count ;
2022-03-07 12:45:29 +01:00
}
/// <summary>
/// Returns the id of the desktop that is currently visible to the user.
/// </summary>
2022-03-14 16:40:27 +01:00
/// <returns>The <see cref="Guid"/> of the current desktop. Or <see cref="Guid.Empty"/> on failure and if we don't know the current desktop.</returns>
2022-03-07 12:45:29 +01:00
public Guid GetCurrentDesktopId ( )
{
if ( _desktopListAutoUpdate )
{
UpdateDesktopList ( ) ;
}
2023-11-23 17:16:12 +01:00
return _currentDesktop ;
2022-03-07 12:45:29 +01:00
}
/// <summary>
/// Returns an instance of <see cref="VDesktop"/> for the desktop that is currently visible to the user.
/// </summary>
/// <returns>An instance of <see cref="VDesktop"/> for the current desktop, or an empty instance of <see cref="VDesktop"/> on failure.</returns>
public VDesktop GetCurrentDesktop ( )
{
if ( _desktopListAutoUpdate )
{
UpdateDesktopList ( ) ;
}
2023-11-23 17:16:12 +01:00
return CreateVDesktopInstance ( _currentDesktop ) ;
2022-03-07 12:45:29 +01:00
}
/// <summary>
/// Checks if a desktop is currently visible to the user.
/// </summary>
/// <param name="desktop">The guid of the desktop to check.</param>
2022-03-14 16:40:27 +01:00
/// <returns><see langword="True"/> if the guid belongs to the currently visible desktop. <see langword="False"/> if not or if we don't know the visible desktop.</returns>
2022-03-07 12:45:29 +01:00
public bool IsDesktopVisible ( Guid desktop )
{
if ( _desktopListAutoUpdate )
{
UpdateDesktopList ( ) ;
}
2023-11-23 17:16:12 +01:00
return _currentDesktop = = desktop ;
2022-03-07 12:45:29 +01:00
}
/// <summary>
/// Returns the number (position) of a desktop.
/// </summary>
/// <param name="desktop">The guid of the desktop.</param>
/// <returns>Number of the desktop, if found. Otherwise a value of zero.</returns>
public int GetDesktopNumber ( Guid desktop )
{
if ( _desktopListAutoUpdate )
{
UpdateDesktopList ( ) ;
}
// Adding +1 because index starts with zero and humans start counting with one.
2023-11-23 17:16:12 +01:00
return _availableDesktops . IndexOf ( desktop ) + 1 ;
2022-03-07 12:45:29 +01:00
}
/// <summary>
/// Returns the name of a desktop
/// </summary>
/// <param name="desktop">Guid of the desktop</param>
2022-03-14 16:40:27 +01:00
/// <returns>Returns the name of the desktop or <see cref="string.Empty"/> on failure.</returns>
2022-03-07 12:45:29 +01:00
public string GetDesktopName ( Guid desktop )
{
if ( desktop = = Guid . Empty | | ! GetDesktopIdList ( ) . Contains ( desktop ) )
{
2022-03-14 16:40:27 +01:00
Log . Debug ( $"VirtualDesktopHelper.GetDesktopName() failed. Parameter contains an invalid desktop guid ({desktop}) that doesn't belongs to an available desktop. Maybe the guid belongs to the generic 'AllDesktops' view." , typeof ( VirtualDesktopHelper ) ) ;
2022-03-07 12:45:29 +01:00
return string . Empty ;
}
// If the desktop name was not changed by the user, it isn't saved to the registry. Then we need the default name for the desktop.
2023-12-28 13:37:13 +03:00
var defaultName = string . Format ( System . Globalization . CultureInfo . InvariantCulture , VirtualDesktopHelperDesktop , GetDesktopNumber ( desktop ) ) ;
2022-03-07 12:45:29 +01:00
2022-03-08 18:23:45 +00:00
string registryPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops\\Desktops\\{" + desktop . ToString ( ) . ToUpper ( System . Globalization . CultureInfo . InvariantCulture ) + "}" ;
2023-11-23 17:16:12 +01:00
using RegistryKey deskSubKey = Registry . CurrentUser . OpenSubKey ( registryPath , false ) ;
2022-03-07 12:45:29 +01:00
var desktopName = deskSubKey ? . GetValue ( "Name" ) ;
return ( desktopName ! = null ) ? ( string ) desktopName : defaultName ;
}
/// <summary>
/// Returns the position type for a desktop.
/// </summary>
/// <param name="desktop">Guid of the desktop.</param>
2022-03-14 16:40:27 +01:00
/// <returns>Type of <see cref="VirtualDesktopPosition"/>. On failure we return <see cref="VirtualDesktopPosition.Unknown"/>.</returns>
2022-03-07 12:45:29 +01:00
public VirtualDesktopPosition GetDesktopPositionType ( Guid desktop )
{
int desktopNumber = GetDesktopNumber ( desktop ) ;
int desktopCount = GetDesktopCount ( ) ;
2022-03-14 16:40:27 +01:00
if ( desktopCount = = 0 | | desktop = = Guid . Empty )
{
// On failure or empty guid
return VirtualDesktopPosition . NotApplicable ;
}
else if ( desktopNumber = = 1 )
2022-03-07 12:45:29 +01:00
{
return VirtualDesktopPosition . FirstDesktop ;
}
else if ( desktopNumber = = desktopCount )
{
return VirtualDesktopPosition . LastDesktop ;
}
else if ( desktopNumber > 1 & desktopNumber < desktopCount )
{
return VirtualDesktopPosition . BetweenOtherDesktops ;
}
else
{
2022-03-14 16:40:27 +01:00
// All desktops view or a guid that doesn't belong to an existing desktop
2022-03-07 12:45:29 +01:00
return VirtualDesktopPosition . NotApplicable ;
}
}
/// <summary>
/// Returns the desktop id for a window.
/// </summary>
/// <param name="hWindow">Handle of the window.</param>
/// <param name="desktopId">The guid of the desktop, where the window is shown.</param>
2022-03-14 16:40:27 +01:00
/// <returns>HResult of the called method as integer.</returns>
2022-03-07 12:45:29 +01:00
public int GetWindowDesktopId ( IntPtr hWindow , out Guid desktopId )
{
if ( _virtualDesktopManager = = null )
{
2022-03-14 16:40:27 +01:00
Log . Error ( "VirtualDesktopHelper.GetWindowDesktopId() failed: The instance of <IVirtualDesktopHelper> isn't available." , typeof ( VirtualDesktopHelper ) ) ;
2022-03-07 12:45:29 +01:00
desktopId = Guid . Empty ;
return unchecked ( ( int ) HRESULT . E_UNEXPECTED ) ;
}
return _virtualDesktopManager . GetWindowDesktopId ( hWindow , out desktopId ) ;
}
/// <summary>
/// Returns an instance of <see cref="VDesktop"/> for the desktop where the window is assigned to.
/// </summary>
/// <param name="hWindow">Handle of the window.</param>
/// <returns>An instance of <see cref="VDesktop"/> for the desktop where the window is assigned to, or an empty instance of <see cref="VDesktop"/> on failure.</returns>
public VDesktop GetWindowDesktop ( IntPtr hWindow )
{
if ( _virtualDesktopManager = = null )
{
2022-03-14 16:40:27 +01:00
Log . Error ( "VirtualDesktopHelper.GetWindowDesktop() failed: The instance of <IVirtualDesktopHelper> isn't available." , typeof ( VirtualDesktopHelper ) ) ;
2022-03-07 12:45:29 +01:00
return CreateVDesktopInstance ( Guid . Empty ) ;
}
int hr = _virtualDesktopManager . GetWindowDesktopId ( hWindow , out Guid desktopId ) ;
return ( hr ! = ( int ) HRESULT . S_OK | | desktopId = = Guid . Empty ) ? VDesktop . Empty : CreateVDesktopInstance ( desktopId , hWindow ) ;
}
/// <summary>
/// Returns the desktop assignment type for a window.
/// </summary>
/// <param name="hWindow">Handle of the window.</param>
2022-03-14 16:40:27 +01:00
/// <param name="desktop">Optional the desktop id if known</param>
/// <returns>Type of <see cref="VirtualDesktopAssignmentType"/>.</returns>
public VirtualDesktopAssignmentType GetWindowDesktopAssignmentType ( IntPtr hWindow , Guid ? desktop = null )
2022-03-07 12:45:29 +01:00
{
if ( _virtualDesktopManager = = null )
{
2022-03-14 16:40:27 +01:00
Log . Error ( "VirtualDesktopHelper.GetWindowDesktopAssignmentType() failed: The instance of <IVirtualDesktopHelper> isn't available." , typeof ( VirtualDesktopHelper ) ) ;
2022-03-07 12:45:29 +01:00
return VirtualDesktopAssignmentType . Unknown ;
}
_ = _virtualDesktopManager . IsWindowOnCurrentVirtualDesktop ( hWindow , out int isOnCurrentDesktop ) ;
2022-03-14 16:40:27 +01:00
Guid windowDesktopId = desktop ? ? Guid . Empty ; // Prepare variable in case we have no input parameter for desktop
int hResult = desktop is null ? GetWindowDesktopId ( hWindow , out windowDesktopId ) : 0 ;
2022-03-07 12:45:29 +01:00
if ( hResult ! = ( int ) HRESULT . S_OK )
{
return VirtualDesktopAssignmentType . Unknown ;
}
else if ( windowDesktopId = = Guid . Empty )
{
return VirtualDesktopAssignmentType . NotAssigned ;
}
else if ( isOnCurrentDesktop = = 1 & & ! GetDesktopIdList ( ) . Contains ( windowDesktopId ) )
{
// These windows are marked as visible on the current desktop, but the desktop id doesn't belongs to an existing desktop.
// In this case the desktop id belongs to the generic view 'AllDesktops'.
return VirtualDesktopAssignmentType . AllDesktops ;
}
else if ( isOnCurrentDesktop = = 1 )
{
return VirtualDesktopAssignmentType . CurrentDesktop ;
}
else
{
return VirtualDesktopAssignmentType . OtherDesktop ;
}
}
/// <summary>
/// Returns a value indicating if the window is assigned to a currently visible desktop.
/// </summary>
/// <param name="hWindow">Handle to the top level window.</param>
2022-03-14 16:40:27 +01:00
/// <param name="desktop">Optional the desktop id if known</param>
/// <returns><see langword="True"/> if the desktop with the window is visible or if the window is assigned to all desktops. <see langword="False"/> if the desktop is not visible and on failure,</returns>
public bool IsWindowOnVisibleDesktop ( IntPtr hWindow , Guid ? desktop = null )
2022-03-07 12:45:29 +01:00
{
2022-03-14 16:40:27 +01:00
return GetWindowDesktopAssignmentType ( hWindow , desktop ) = = VirtualDesktopAssignmentType . CurrentDesktop | | GetWindowDesktopAssignmentType ( hWindow , desktop ) = = VirtualDesktopAssignmentType . AllDesktops ;
2022-03-07 12:45:29 +01:00
}
/// <summary>
/// Returns a value indicating if the window is cloaked by VirtualDesktopManager.
/// (A cloaked window is not visible to the user. But the window is still composed by DWM.)
/// </summary>
/// <param name="hWindow">Handle of the window.</param>
2022-03-14 16:40:27 +01:00
/// <param name="desktop">Optional the desktop id if known</param>
2022-07-01 10:09:41 -04:00
/// <returns>A value indicating if the window is cloaked by Virtual Desktop Manager, because it is moved to another desktop.</returns>
2022-03-14 16:40:27 +01:00
public bool IsWindowCloakedByVirtualDesktopManager ( IntPtr hWindow , Guid ? desktop = null )
2022-03-07 12:45:29 +01:00
{
2022-07-01 10:09:41 -04:00
// If a window is hidden because it is moved to another desktop, then DWM returns type "CloakedShell". If DWM returns another type the window is not cloaked by shell or VirtualDesktopManager.
2022-03-07 12:45:29 +01:00
_ = NativeMethods . DwmGetWindowAttribute ( hWindow , ( int ) DwmWindowAttributes . Cloaked , out int dwmCloakedState , sizeof ( uint ) ) ;
2022-03-14 16:40:27 +01:00
return GetWindowDesktopAssignmentType ( hWindow , desktop ) = = VirtualDesktopAssignmentType . OtherDesktop & & dwmCloakedState = = ( int ) DwmWindowCloakStates . CloakedShell ;
2022-03-07 12:45:29 +01:00
}
/// <summary>
/// Moves the window to a specific desktop.
/// </summary>
/// <param name="hWindow">Handle of the top level window.</param>
/// <param name="desktopId">Guid of the target desktop.</param>
2022-03-14 16:40:27 +01:00
/// <returns><see langword="True"/> on success and <see langword="false"/> on failure.</returns>
2022-03-07 12:45:29 +01:00
public bool MoveWindowToDesktop ( IntPtr hWindow , in Guid desktopId )
{
if ( _virtualDesktopManager = = null )
{
2022-03-14 16:40:27 +01:00
Log . Error ( "VirtualDesktopHelper.MoveWindowToDesktop() failed: The instance of <IVirtualDesktopHelper> isn't available." , typeof ( VirtualDesktopHelper ) ) ;
2022-03-07 12:45:29 +01:00
return false ;
}
int hr = _virtualDesktopManager . MoveWindowToDesktop ( hWindow , desktopId ) ;
if ( hr ! = ( int ) HRESULT . S_OK )
{
2022-07-01 10:09:41 -04:00
Log . Exception ( $"VirtualDesktopHelper.MoveWindowToDesktop() failed: An exception was thrown when moving the window ({hWindow}) to another desktop ({desktopId})." , Marshal . GetExceptionForHR ( hr ) , typeof ( VirtualDesktopHelper ) ) ;
2022-03-07 12:45:29 +01:00
return false ;
}
return true ;
}
/// <summary>
/// Move a window one desktop left.
/// </summary>
/// <param name="hWindow">Handle of the top level window.</param>
2022-03-14 16:40:27 +01:00
/// <returns><see langword="True"/> on success and <see langword="false"/> on failure.</returns>
2022-03-07 12:45:29 +01:00
public bool MoveWindowOneDesktopLeft ( IntPtr hWindow )
{
2022-03-14 16:40:27 +01:00
int hr = GetWindowDesktopId ( hWindow , out Guid windowDesktop ) ;
if ( hr ! = ( int ) HRESULT . S_OK )
2022-03-07 12:45:29 +01:00
{
2022-03-14 16:40:27 +01:00
Log . Error ( $"VirtualDesktopHelper.MoveWindowOneDesktopLeft() failed when moving the window ({hWindow}) one desktop left: Can't get current desktop of the window." , typeof ( VirtualDesktopHelper ) ) ;
2022-03-07 12:45:29 +01:00
return false ;
}
2022-03-14 16:40:27 +01:00
if ( GetDesktopIdList ( ) . Count = = 0 | | GetWindowDesktopAssignmentType ( hWindow , windowDesktop ) = = VirtualDesktopAssignmentType . Unknown | | GetWindowDesktopAssignmentType ( hWindow , windowDesktop ) = = VirtualDesktopAssignmentType . NotAssigned )
2022-03-07 12:45:29 +01:00
{
2022-03-14 16:40:27 +01:00
Log . Error ( $"VirtualDesktopHelper.MoveWindowOneDesktopLeft() failed when moving the window ({hWindow}) one desktop left: We can't find the target desktop. This can happen if the desktop list is empty or if the window isn't assigned to a specific desktop." , typeof ( VirtualDesktopHelper ) ) ;
2022-03-07 12:45:29 +01:00
return false ;
}
int windowDesktopNumber = GetDesktopIdList ( ) . IndexOf ( windowDesktop ) ;
if ( windowDesktopNumber = = 1 )
{
2022-03-14 16:40:27 +01:00
Log . Error ( $"VirtualDesktopHelper.MoveWindowOneDesktopLeft() failed when moving the window ({hWindow}) one desktop left: The window is on the first desktop." , typeof ( VirtualDesktopHelper ) ) ;
2022-03-07 12:45:29 +01:00
return false ;
}
2023-11-23 17:16:12 +01:00
Guid newDesktop = _availableDesktops [ windowDesktopNumber - 1 ] ;
2022-03-07 12:45:29 +01:00
return MoveWindowToDesktop ( hWindow , newDesktop ) ;
}
/// <summary>
/// Move a window one desktop right.
/// </summary>
/// <param name="hWindow">Handle of the top level window.</param>
2022-03-14 16:40:27 +01:00
/// <returns><see langword="True"/> on success and <see langword="false"/> on failure.</returns>
2022-03-07 12:45:29 +01:00
public bool MoveWindowOneDesktopRight ( IntPtr hWindow )
{
2022-03-14 16:40:27 +01:00
int hr = GetWindowDesktopId ( hWindow , out Guid windowDesktop ) ;
if ( hr ! = ( int ) HRESULT . S_OK )
2022-03-07 12:45:29 +01:00
{
2022-03-14 16:40:27 +01:00
Log . Error ( $"VirtualDesktopHelper.MoveWindowOneDesktopRight() failed when moving the window ({hWindow}) one desktop right: Can't get current desktop of the window." , typeof ( VirtualDesktopHelper ) ) ;
2022-03-07 12:45:29 +01:00
return false ;
}
2022-03-14 16:40:27 +01:00
if ( GetDesktopIdList ( ) . Count = = 0 | | GetWindowDesktopAssignmentType ( hWindow , windowDesktop ) = = VirtualDesktopAssignmentType . Unknown | | GetWindowDesktopAssignmentType ( hWindow , windowDesktop ) = = VirtualDesktopAssignmentType . NotAssigned )
2022-03-07 12:45:29 +01:00
{
2022-03-14 16:40:27 +01:00
Log . Error ( $"VirtualDesktopHelper.MoveWindowOneDesktopRight() failed when moving the window ({hWindow}) one desktop right: We can't find the target desktop. This can happen if the desktop list is empty or if the window isn't assigned to a specific desktop." , typeof ( VirtualDesktopHelper ) ) ;
2022-03-07 12:45:29 +01:00
return false ;
}
int windowDesktopNumber = GetDesktopIdList ( ) . IndexOf ( windowDesktop ) ;
if ( windowDesktopNumber = = GetDesktopCount ( ) )
{
2022-03-14 16:40:27 +01:00
Log . Error ( $"VirtualDesktopHelper.MoveWindowOneDesktopRight() failed when moving the window ({hWindow}) one desktop right: The window is on the last desktop." , typeof ( VirtualDesktopHelper ) ) ;
2022-03-07 12:45:29 +01:00
return false ;
}
2023-11-23 17:16:12 +01:00
Guid newDesktop = _availableDesktops [ windowDesktopNumber + 1 ] ;
2022-03-07 12:45:29 +01:00
return MoveWindowToDesktop ( hWindow , newDesktop ) ;
}
/// <summary>
2022-03-14 16:40:27 +01:00
/// Returns an instance of <see cref="VDesktop"/> for a Guid.
2022-03-07 12:45:29 +01:00
/// </summary>
/// <param name="desktop">Guid of the desktop.</param>
/// <param name="hWindow">Handle of the window shown on the desktop. If this parameter is set we can detect if it is the AllDesktops view.</param>
2022-03-14 16:40:27 +01:00
/// <returns>A <see cref="VDesktop"/> instance. If the parameter desktop is <see cref="Guid.Empty"/>, we return an empty <see cref="VDesktop"/> instance.</returns>
2022-03-07 12:45:29 +01:00
private VDesktop CreateVDesktopInstance ( Guid desktop , IntPtr hWindow = default )
{
2022-03-14 16:40:27 +01:00
if ( desktop = = Guid . Empty )
{
return VDesktop . Empty ;
}
2022-03-07 12:45:29 +01:00
// Can be only detected if method is invoked with window handle parameter.
2022-03-14 16:40:27 +01:00
VirtualDesktopAssignmentType desktopType = ( hWindow ! = default ) ? GetWindowDesktopAssignmentType ( hWindow , desktop ) : VirtualDesktopAssignmentType . Unknown ;
bool isAllDesktops = ( hWindow ! = default ) & & desktopType = = VirtualDesktopAssignmentType . AllDesktops ;
bool isDesktopVisible = ( hWindow ! = default ) ? ( isAllDesktops | | desktopType = = VirtualDesktopAssignmentType . CurrentDesktop ) : IsDesktopVisible ( desktop ) ;
2022-03-07 12:45:29 +01:00
return new VDesktop ( )
{
Id = desktop ,
Name = isAllDesktops ? Resources . VirtualDesktopHelper_AllDesktops : GetDesktopName ( desktop ) ,
Number = GetDesktopNumber ( desktop ) ,
2022-03-14 16:40:27 +01:00
IsVisible = isDesktopVisible | | isAllDesktops ,
2022-03-07 12:45:29 +01:00
IsAllDesktopsView = isAllDesktops ,
Position = GetDesktopPositionType ( desktop ) ,
} ;
}
}
/// <summary>
/// Enum to show in which way a window is assigned to a desktop
/// </summary>
public enum VirtualDesktopAssignmentType
{
Unknown = - 1 ,
NotAssigned = 0 ,
AllDesktops = 1 ,
CurrentDesktop = 2 ,
OtherDesktop = 3 ,
}
/// <summary>
/// Enum to show the position of a desktop in the list of all desktops
/// </summary>
public enum VirtualDesktopPosition
{
FirstDesktop ,
BetweenOtherDesktops ,
LastDesktop ,
2022-03-14 16:40:27 +01:00
NotApplicable , // If not applicable or unknown
2022-03-07 12:45:29 +01:00
}
}