2019-09-05 00:26:26 +08:00
# include "pch.h"
2020-05-04 22:29:48 +08:00
2020-09-07 18:24:13 +08:00
# include <common/common.h>
2020-05-04 22:29:48 +08:00
# include <common/dpi_aware.h>
# include <common/on_thread_executor.h>
# include <common/window_helpers.h>
2019-09-05 00:26:26 +08:00
2019-12-17 16:21:46 +08:00
# include "FancyZones.h"
# include "lib/Settings.h"
# include "lib/ZoneWindow.h"
2020-07-22 16:39:13 +08:00
# include "lib/FancyZonesData.h"
2020-02-10 21:59:51 +08:00
# include "lib/ZoneSet.h"
2020-04-30 18:16:08 +08:00
# include "lib/WindowMoveHandler.h"
2020-05-04 22:29:48 +08:00
# include "lib/FancyZonesWinHookEventIDs.h"
# include "lib/util.h"
2019-12-17 16:21:46 +08:00
# include "trace.h"
2020-04-22 01:57:21 +08:00
# include "VirtualDesktopUtils.h"
2020-05-31 18:36:45 +08:00
# include "MonitorWorkAreaHandler.h"
2019-12-17 16:21:46 +08:00
2020-06-05 22:53:08 +08:00
# include <lib/SecondaryMouseButtonsHook.h>
2020-02-10 21:59:51 +08:00
2020-09-07 18:24:13 +08:00
extern " C " IMAGE_DOS_HEADER __ImageBase ;
2020-02-10 21:59:51 +08:00
enum class DisplayChangeType
{
WorkArea ,
DisplayChange ,
VirtualDesktop ,
Initialization
} ;
2019-12-12 17:10:55 +08:00
2020-07-08 16:37:42 +08:00
namespace
{
constexpr int CUSTOM_POSITIONING_LEFT_TOP_PADDING = 16 ;
}
2020-08-11 19:51:06 +08:00
// Non-localizable strings
namespace NonLocalizable
{
const wchar_t ToolWindowClassName [ ] = L " SuperFancyZones " ;
const wchar_t FZEditorExecutablePath [ ] = L " modules \\ FancyZones \\ FancyZonesEditor.exe " ;
const wchar_t SplashClassName [ ] = L " MsoSplash " ;
}
2019-09-05 00:26:26 +08:00
struct FancyZones : public winrt : : implements < FancyZones , IFancyZones , IFancyZonesCallback , IZoneWindowHost >
{
public :
2020-02-10 21:59:51 +08:00
FancyZones ( HINSTANCE hinstance , const winrt : : com_ptr < IFancyZonesSettings > & settings ) noexcept :
m_hinstance ( hinstance ) ,
2020-04-30 18:16:08 +08:00
m_settings ( settings ) ,
2020-08-24 15:19:39 +08:00
m_windowMoveHandler ( settings , [ this ] ( ) {
PostMessageW ( m_window , WM_PRIV_LOCATIONCHANGE , NULL , NULL ) ;
} )
2019-09-05 00:26:26 +08:00
{
m_settings - > SetCallback ( this ) ;
}
// IFancyZones
2020-02-17 23:28:49 +08:00
IFACEMETHODIMP_ ( void )
Run ( ) noexcept ;
IFACEMETHODIMP_ ( void )
Destroy ( ) noexcept ;
2019-09-05 00:26:26 +08:00
2020-05-05 02:10:23 +08:00
void MoveSizeStart ( HWND window , HMONITOR monitor , POINT const & ptScreen ) noexcept
2020-04-30 18:16:08 +08:00
{
std : : unique_lock writeLock ( m_lock ) ;
2020-08-07 16:06:25 +08:00
if ( m_settings - > GetSettings ( ) - > spanZonesAcrossMonitors )
{
monitor = NULL ;
}
2020-05-31 18:36:45 +08:00
m_windowMoveHandler . MoveSizeStart ( window , monitor , ptScreen , m_workAreaHandler . GetWorkAreasByDesktopId ( m_currentDesktopId ) ) ;
2020-04-30 18:16:08 +08:00
}
2020-05-27 22:52:59 +08:00
2020-05-05 02:10:23 +08:00
void MoveSizeUpdate ( HMONITOR monitor , POINT const & ptScreen ) noexcept
2020-04-30 18:16:08 +08:00
{
std : : unique_lock writeLock ( m_lock ) ;
2020-08-07 16:06:25 +08:00
if ( m_settings - > GetSettings ( ) - > spanZonesAcrossMonitors )
{
monitor = NULL ;
}
2020-05-31 18:36:45 +08:00
m_windowMoveHandler . MoveSizeUpdate ( monitor , ptScreen , m_workAreaHandler . GetWorkAreasByDesktopId ( m_currentDesktopId ) ) ;
2020-04-30 18:16:08 +08:00
}
2020-05-27 22:52:59 +08:00
2020-05-05 02:10:23 +08:00
void MoveSizeEnd ( HWND window , POINT const & ptScreen ) noexcept
2020-04-30 18:16:08 +08:00
{
std : : unique_lock writeLock ( m_lock ) ;
2020-05-31 18:36:45 +08:00
m_windowMoveHandler . MoveSizeEnd ( window , ptScreen , m_workAreaHandler . GetWorkAreasByDesktopId ( m_currentDesktopId ) ) ;
2020-05-04 22:29:48 +08:00
}
2020-06-05 22:53:08 +08:00
2020-05-04 22:29:48 +08:00
IFACEMETHODIMP_ ( void )
HandleWinHookEvent ( const WinHookEvent * data ) noexcept
{
const auto wparam = reinterpret_cast < WPARAM > ( data - > hwnd ) ;
const LONG lparam = 0 ;
std : : shared_lock readLock ( m_lock ) ;
switch ( data - > event )
{
case EVENT_SYSTEM_MOVESIZESTART :
PostMessageW ( m_window , WM_PRIV_MOVESIZESTART , wparam , lparam ) ;
break ;
case EVENT_SYSTEM_MOVESIZEEND :
PostMessageW ( m_window , WM_PRIV_MOVESIZEEND , wparam , lparam ) ;
break ;
case EVENT_OBJECT_LOCATIONCHANGE :
PostMessageW ( m_window , WM_PRIV_LOCATIONCHANGE , wparam , lparam ) ;
break ;
case EVENT_OBJECT_NAMECHANGE :
PostMessageW ( m_window , WM_PRIV_NAMECHANGE , wparam , lparam ) ;
break ;
case EVENT_OBJECT_UNCLOAKED :
case EVENT_OBJECT_SHOW :
case EVENT_OBJECT_CREATE :
if ( data - > idObject = = OBJID_WINDOW )
{
PostMessageW ( m_window , WM_PRIV_WINDOWCREATED , wparam , lparam ) ;
}
break ;
}
2020-04-30 18:16:08 +08:00
}
2020-05-04 22:29:48 +08:00
2020-02-17 23:28:49 +08:00
IFACEMETHODIMP_ ( void )
VirtualDesktopChanged ( ) noexcept ;
IFACEMETHODIMP_ ( void )
VirtualDesktopInitialize ( ) noexcept ;
IFACEMETHODIMP_ ( bool )
OnKeyDown ( PKBDLLHOOKSTRUCT info ) noexcept ;
IFACEMETHODIMP_ ( void )
ToggleEditor ( ) noexcept ;
IFACEMETHODIMP_ ( void )
SettingsChanged ( ) noexcept ;
2020-05-27 22:52:59 +08:00
2020-05-05 02:10:23 +08:00
void WindowCreated ( HWND window ) noexcept ;
2019-09-05 00:26:26 +08:00
// IZoneWindowHost
2020-02-17 23:28:49 +08:00
IFACEMETHODIMP_ ( void )
MoveWindowsOnActiveZoneSetChange ( ) noexcept ;
IFACEMETHODIMP_ ( COLORREF )
2020-03-25 22:38:44 +08:00
GetZoneColor ( ) noexcept
{
2020-09-02 23:34:17 +08:00
return ( FancyZonesUtils : : HexToRGB ( m_settings - > GetSettings ( ) - > zoneColor ) ) ;
2020-03-25 22:38:44 +08:00
}
IFACEMETHODIMP_ ( COLORREF )
GetZoneBorderColor ( ) noexcept
{
2020-09-02 23:34:17 +08:00
return ( FancyZonesUtils : : HexToRGB ( m_settings - > GetSettings ( ) - > zoneBorderColor ) ) ;
2020-03-25 22:38:44 +08:00
}
IFACEMETHODIMP_ ( COLORREF )
2020-02-17 23:28:49 +08:00
GetZoneHighlightColor ( ) noexcept
2019-09-05 00:26:26 +08:00
{
2020-09-02 23:34:17 +08:00
return ( FancyZonesUtils : : HexToRGB ( m_settings - > GetSettings ( ) - > zoneHighlightColor ) ) ;
2019-09-05 00:26:26 +08:00
}
2020-02-17 23:28:49 +08:00
IFACEMETHODIMP_ ( int )
GetZoneHighlightOpacity ( ) noexcept
2020-01-07 01:59:18 +08:00
{
2020-03-13 17:55:15 +08:00
return m_settings - > GetSettings ( ) - > zoneHighlightOpacity ;
2020-01-07 01:59:18 +08:00
}
2019-09-05 00:26:26 +08:00
2020-03-25 22:38:44 +08:00
IFACEMETHODIMP_ ( bool )
isMakeDraggedWindowTransparentActive ( ) noexcept
{
return m_settings - > GetSettings ( ) - > makeDraggedWindowTransparent ;
}
2020-05-22 22:42:29 +08:00
IFACEMETHODIMP_ ( bool )
InMoveSize ( ) noexcept
{
std : : shared_lock readLock ( m_lock ) ;
return m_windowMoveHandler . InMoveSize ( ) ;
}
2019-09-05 00:26:26 +08:00
LRESULT WndProc ( HWND , UINT , WPARAM , LPARAM ) noexcept ;
void OnDisplayChange ( DisplayChangeType changeType ) noexcept ;
void AddZoneWindow ( HMONITOR monitor , PCWSTR deviceId ) noexcept ;
2020-03-10 16:59:34 +08:00
2019-09-05 00:26:26 +08:00
protected :
static LRESULT CALLBACK s_WndProc ( HWND , UINT , WPARAM , LPARAM ) noexcept ;
private :
struct require_read_lock
{
template < typename T >
2020-02-10 21:59:51 +08:00
require_read_lock ( const std : : shared_lock < T > & lock )
{
lock ;
}
2019-09-05 00:26:26 +08:00
template < typename T >
2020-02-10 21:59:51 +08:00
require_read_lock ( const std : : unique_lock < T > & lock )
{
lock ;
}
2019-09-05 00:26:26 +08:00
} ;
struct require_write_lock
{
template < typename T >
2020-02-10 21:59:51 +08:00
require_write_lock ( const std : : unique_lock < T > & lock )
{
lock ;
}
2019-09-05 00:26:26 +08:00
} ;
void UpdateZoneWindows ( ) noexcept ;
2020-05-06 23:16:16 +08:00
void UpdateWindowsPositions ( ) noexcept ;
2019-09-05 00:26:26 +08:00
void CycleActiveZoneSet ( DWORD vkCode ) noexcept ;
2020-08-21 18:53:03 +08:00
bool OnSnapHotkeyBasedOnZoneNumber ( HWND window , DWORD vkCode ) noexcept ;
bool OnSnapHotkeyBasedOnPosition ( HWND window , DWORD vkCode ) noexcept ;
2020-02-06 20:12:59 +08:00
bool OnSnapHotkey ( DWORD vkCode ) noexcept ;
2020-09-11 17:32:45 +08:00
bool ProcessDirectedSnapHotkey ( HWND window , DWORD vkCode , bool cycle , winrt : : com_ptr < IZoneWindow > zoneWindow ) noexcept ;
2020-05-04 22:29:48 +08:00
2020-05-01 22:13:16 +08:00
void RegisterVirtualDesktopUpdates ( std : : vector < GUID > & ids ) noexcept ;
2020-05-27 22:52:59 +08:00
bool IsSplashScreen ( HWND window ) ;
2020-06-17 17:55:14 +08:00
bool ShouldProcessNewWindow ( HWND window ) noexcept ;
2020-08-24 20:39:34 +08:00
std : : vector < size_t > GetZoneIndexSetFromWorkAreaHistory ( HWND window , winrt : : com_ptr < IZoneWindow > workArea ) noexcept ;
std : : pair < winrt : : com_ptr < IZoneWindow > , std : : vector < size_t > > GetAppZoneHistoryInfo ( HWND window , HMONITOR monitor , std : : unordered_map < HMONITOR , winrt : : com_ptr < IZoneWindow > > & workAreaMap ) noexcept ;
std : : pair < winrt : : com_ptr < IZoneWindow > , std : : vector < size_t > > GetAppZoneHistoryInfo ( HWND window , HMONITOR monitor , bool isPrimaryMonitor ) noexcept ;
void MoveWindowIntoZone ( HWND window , winrt : : com_ptr < IZoneWindow > zoneWindow , const std : : vector < size_t > & zoneIndexSet ) noexcept ;
2020-05-27 22:52:59 +08:00
2020-02-10 21:59:51 +08:00
void OnEditorExitEvent ( ) noexcept ;
2020-08-21 18:53:03 +08:00
bool ShouldProcessSnapHotkey ( DWORD vkCode ) noexcept ;
2019-09-05 00:26:26 +08:00
2020-03-25 01:50:26 +08:00
std : : vector < std : : pair < HMONITOR , RECT > > GetRawMonitorData ( ) noexcept ;
std : : vector < HMONITOR > GetMonitorsSorted ( ) noexcept ;
2019-09-05 00:26:26 +08:00
const HINSTANCE m_hinstance { } ;
mutable std : : shared_mutex m_lock ;
HWND m_window { } ;
2020-04-30 18:16:08 +08:00
WindowMoveHandler m_windowMoveHandler ;
2020-05-31 18:36:45 +08:00
MonitorWorkAreaHandler m_workAreaHandler ;
2020-05-04 22:29:48 +08:00
2020-02-10 21:59:51 +08:00
winrt : : com_ptr < IFancyZonesSettings > m_settings { } ;
2020-05-31 18:36:45 +08:00
GUID m_previousDesktopId { } ; // UUID of previously active virtual desktop.
GUID m_currentDesktopId { } ; // UUID of the current virtual desktop.
2019-11-19 07:29:42 +08:00
wil : : unique_handle m_terminateEditorEvent ; // Handle of FancyZonesEditor.exe we launch and wait on
2019-12-12 17:10:55 +08:00
wil : : unique_handle m_terminateVirtualDesktopTrackerEvent ;
2019-09-05 00:26:26 +08:00
2019-11-08 02:56:32 +08:00
OnThreadExecutor m_dpiUnawareThread ;
2019-12-12 17:10:55 +08:00
OnThreadExecutor m_virtualDesktopTrackerThread ;
2019-11-08 02:56:32 +08:00
2020-05-05 02:10:23 +08:00
static UINT WM_PRIV_VD_INIT ; // Scheduled when FancyZones is initialized
static UINT WM_PRIV_VD_SWITCH ; // Scheduled when virtual desktop switch occurs
static UINT WM_PRIV_VD_UPDATE ; // Scheduled on virtual desktops update (creation/deletion)
static UINT WM_PRIV_EDITOR ; // Scheduled when the editor exits
static UINT WM_PRIV_LOWLEVELKB ; // Scheduled when we receive a key down press
2019-09-05 00:26:26 +08:00
2019-11-19 07:29:42 +08:00
// Did we terminate the editor or was it closed cleanly?
2019-09-05 00:26:26 +08:00
enum class EditorExitKind : byte
{
Exit ,
Terminate
} ;
} ;
2020-05-01 22:13:16 +08:00
UINT FancyZones : : WM_PRIV_VD_INIT = RegisterWindowMessage ( L " {469818a8-00fa-4069-b867-a1da484fcd9a} " ) ;
UINT FancyZones : : WM_PRIV_VD_SWITCH = RegisterWindowMessage ( L " {128c2cb0-6bdf-493e-abbe-f8705e04aa95} " ) ;
UINT FancyZones : : WM_PRIV_VD_UPDATE = RegisterWindowMessage ( L " {b8b72b46-f42f-4c26-9e20-29336cf2f22e} " ) ;
2019-09-05 00:26:26 +08:00
UINT FancyZones : : WM_PRIV_EDITOR = RegisterWindowMessage ( L " {87543824-7080-4e91-9d9c-0404642fc7b6} " ) ;
2020-05-05 02:10:23 +08:00
UINT FancyZones : : WM_PRIV_LOWLEVELKB = RegisterWindowMessage ( L " {763c03a3-03d9-4cde-8d71-f0358b0b4b52} " ) ;
2019-09-05 00:26:26 +08:00
// IFancyZones
2020-02-17 23:28:49 +08:00
IFACEMETHODIMP_ ( void )
FancyZones : : Run ( ) noexcept
2019-09-05 00:26:26 +08:00
{
std : : unique_lock writeLock ( m_lock ) ;
WNDCLASSEXW wcex { } ;
wcex . cbSize = sizeof ( WNDCLASSEX ) ;
wcex . lpfnWndProc = s_WndProc ;
wcex . hInstance = m_hinstance ;
2020-08-11 19:51:06 +08:00
wcex . lpszClassName = NonLocalizable : : ToolWindowClassName ;
2019-09-05 00:26:26 +08:00
RegisterClassExW ( & wcex ) ;
BufferedPaintInit ( ) ;
2020-08-11 19:51:06 +08:00
m_window = CreateWindowExW ( WS_EX_TOOLWINDOW , NonLocalizable : : ToolWindowClassName , L " " , WS_POPUP , 0 , 0 , 0 , 0 , nullptr , nullptr , m_hinstance , this ) ;
2020-02-10 21:59:51 +08:00
if ( ! m_window )
2020-08-11 19:51:06 +08:00
{
2020-02-10 21:59:51 +08:00
return ;
2020-08-11 19:51:06 +08:00
}
2019-09-05 00:26:26 +08:00
2020-03-13 17:55:15 +08:00
RegisterHotKey ( m_window , 1 , m_settings - > GetSettings ( ) - > editorHotkey . get_modifiers ( ) , m_settings - > GetSettings ( ) - > editorHotkey . get_code ( ) ) ;
2019-11-19 07:29:42 +08:00
2019-12-24 22:47:28 +08:00
VirtualDesktopInitialize ( ) ;
2019-11-08 02:56:32 +08:00
2020-02-10 21:59:51 +08:00
m_dpiUnawareThread . submit ( OnThreadExecutor : : task_t { [ ] {
SetThreadDpiAwarenessContext ( DPI_AWARENESS_CONTEXT_UNAWARE ) ;
SetThreadDpiHostingBehavior ( DPI_HOSTING_BEHAVIOR_MIXED ) ;
} } )
. wait ( ) ;
2019-12-12 17:10:55 +08:00
2020-05-01 22:13:16 +08:00
m_terminateVirtualDesktopTrackerEvent . reset ( CreateEvent ( nullptr , FALSE , FALSE , nullptr ) ) ;
2020-05-04 22:29:48 +08:00
m_virtualDesktopTrackerThread . submit ( OnThreadExecutor : : task_t { [ & ] { VirtualDesktopUtils : : HandleVirtualDesktopUpdates ( m_window , WM_PRIV_VD_UPDATE , m_terminateVirtualDesktopTrackerEvent . get ( ) ) ; } } ) ;
2019-09-05 00:26:26 +08:00
}
// IFancyZones
2020-02-17 23:28:49 +08:00
IFACEMETHODIMP_ ( void )
FancyZones : : Destroy ( ) noexcept
2019-09-05 00:26:26 +08:00
{
std : : unique_lock writeLock ( m_lock ) ;
2020-05-31 18:36:45 +08:00
m_workAreaHandler . Clear ( ) ;
2019-09-05 00:26:26 +08:00
BufferedPaintUnInit ( ) ;
if ( m_window )
{
DestroyWindow ( m_window ) ;
m_window = nullptr ;
}
2020-02-10 21:59:51 +08:00
if ( m_terminateVirtualDesktopTrackerEvent )
{
2019-12-12 17:10:55 +08:00
SetEvent ( m_terminateVirtualDesktopTrackerEvent . get ( ) ) ;
}
2019-09-05 00:26:26 +08:00
}
// IFancyZonesCallback
2020-02-17 23:28:49 +08:00
IFACEMETHODIMP_ ( void )
FancyZones : : VirtualDesktopChanged ( ) noexcept
2019-09-05 00:26:26 +08:00
{
2020-05-04 22:29:48 +08:00
// VirtualDesktopChanged is called from a reentrant WinHookProc function, therefore we must postpone the actual logic
// until we're in FancyZones::WndProc, which is not reentrant.
2020-05-01 22:13:16 +08:00
PostMessage ( m_window , WM_PRIV_VD_SWITCH , 0 , 0 ) ;
2019-09-05 00:26:26 +08:00
}
2019-12-24 22:47:28 +08:00
// IFancyZonesCallback
2020-02-17 23:28:49 +08:00
IFACEMETHODIMP_ ( void )
FancyZones : : VirtualDesktopInitialize ( ) noexcept
2019-12-24 22:47:28 +08:00
{
2020-05-01 22:13:16 +08:00
PostMessage ( m_window , WM_PRIV_VD_INIT , 0 , 0 ) ;
2019-12-24 22:47:28 +08:00
}
2020-06-17 17:55:14 +08:00
bool FancyZones : : ShouldProcessNewWindow ( HWND window ) noexcept
{
2020-08-28 21:00:21 +08:00
using namespace FancyZonesUtils ;
2020-06-17 17:55:14 +08:00
// Avoid processing splash screens, already stamped (zoned) windows, or those windows
// that belong to excluded applications list.
if ( IsSplashScreen ( window ) | |
2020-08-11 19:51:06 +08:00
( reinterpret_cast < size_t > ( : : GetProp ( window , ZonedWindowProperties : : PropertyMultipleZoneID ) ) ! = 0 ) | |
2020-08-28 21:00:21 +08:00
! IsCandidateForLastKnownZone ( window , m_settings - > GetSettings ( ) - > excludedAppsArray ) )
2020-06-17 17:55:14 +08:00
{
return false ;
}
return true ;
}
2020-08-24 20:39:34 +08:00
std : : vector < size_t > FancyZones : : GetZoneIndexSetFromWorkAreaHistory (
2020-07-31 19:06:13 +08:00
HWND window ,
winrt : : com_ptr < IZoneWindow > workArea ) noexcept
2020-06-17 17:55:14 +08:00
{
const auto activeZoneSet = workArea - > ActiveZoneSet ( ) ;
if ( activeZoneSet )
{
wil : : unique_cotaskmem_string zoneSetId ;
if ( SUCCEEDED ( StringFromCLSID ( activeZoneSet - > Id ( ) , & zoneSetId ) ) )
{
2020-07-22 16:39:13 +08:00
return FancyZonesDataInstance ( ) . GetAppLastZoneIndexSet ( window , workArea - > UniqueId ( ) , zoneSetId . get ( ) ) ;
2020-06-17 17:55:14 +08:00
}
}
return { } ;
}
2020-08-24 20:39:34 +08:00
std : : pair < winrt : : com_ptr < IZoneWindow > , std : : vector < size_t > > FancyZones : : GetAppZoneHistoryInfo (
2020-06-17 17:55:14 +08:00
HWND window ,
HMONITOR monitor ,
std : : unordered_map < HMONITOR , winrt : : com_ptr < IZoneWindow > > & workAreaMap ) noexcept
{
if ( workAreaMap . contains ( monitor ) )
{
auto workArea = workAreaMap [ monitor ] ;
workAreaMap . erase ( monitor ) ; // monitor processed, remove entry from the map
return { workArea , GetZoneIndexSetFromWorkAreaHistory ( window , workArea ) } ;
}
return { nullptr , { } } ;
}
2020-08-24 20:39:34 +08:00
std : : pair < winrt : : com_ptr < IZoneWindow > , std : : vector < size_t > > FancyZones : : GetAppZoneHistoryInfo ( HWND window , HMONITOR monitor , bool isPrimaryMonitor ) noexcept
2020-06-17 17:55:14 +08:00
{
2020-08-24 20:39:34 +08:00
std : : pair < winrt : : com_ptr < IZoneWindow > , std : : vector < size_t > > appZoneHistoryInfo { nullptr , { } } ;
2020-06-17 17:55:14 +08:00
auto workAreaMap = m_workAreaHandler . GetWorkAreasByDesktopId ( m_currentDesktopId ) ;
// Search application history on currently active monitor.
appZoneHistoryInfo = GetAppZoneHistoryInfo ( window , monitor , workAreaMap ) ;
if ( isPrimaryMonitor & & appZoneHistoryInfo . second . empty ( ) )
{
// No application history on primary monitor, search on remaining monitors.
for ( const auto & [ monitor , workArea ] : workAreaMap )
{
auto zoneIndexSet = GetZoneIndexSetFromWorkAreaHistory ( window , workArea ) ;
if ( ! zoneIndexSet . empty ( ) )
{
return { workArea , zoneIndexSet } ;
}
}
}
return appZoneHistoryInfo ;
}
2020-08-24 20:39:34 +08:00
void FancyZones : : MoveWindowIntoZone ( HWND window , winrt : : com_ptr < IZoneWindow > zoneWindow , const std : : vector < size_t > & zoneIndexSet ) noexcept
2020-06-17 17:55:14 +08:00
{
2020-07-22 16:39:13 +08:00
auto & fancyZonesData = FancyZonesDataInstance ( ) ;
2020-06-17 17:55:14 +08:00
if ( ! fancyZonesData . IsAnotherWindowOfApplicationInstanceZoned ( window , zoneWindow - > UniqueId ( ) ) )
{
m_windowMoveHandler . MoveWindowIntoZoneByIndexSet ( window , zoneIndexSet , zoneWindow ) ;
fancyZonesData . UpdateProcessIdToHandleMap ( window , zoneWindow - > UniqueId ( ) ) ;
}
}
2020-07-08 16:37:42 +08:00
inline int RectWidth ( const RECT & rect )
{
return rect . right - rect . left ;
}
inline int RectHeight ( const RECT & rect )
{
return rect . bottom - rect . top ;
}
RECT FitOnScreen ( const RECT & windowRect , const RECT & originMonitorRect , const RECT & destMonitorRect )
{
// New window position on active monitor. If window fits the screen, this will be final position.
int left = destMonitorRect . left + ( windowRect . left - originMonitorRect . left ) ;
int top = destMonitorRect . top + ( windowRect . top - originMonitorRect . top ) ;
int W = RectWidth ( windowRect ) ;
int H = RectHeight ( windowRect ) ;
if ( ( left < destMonitorRect . left ) | | ( left + W > destMonitorRect . right ) )
{
// Set left window border to left border of screen (add padding). Resize window width if needed.
left = destMonitorRect . left + CUSTOM_POSITIONING_LEFT_TOP_PADDING ;
W = min ( W , RectWidth ( destMonitorRect ) - CUSTOM_POSITIONING_LEFT_TOP_PADDING ) ;
}
if ( ( top < destMonitorRect . top ) | | ( top + H > destMonitorRect . bottom ) )
{
// Set top window border to top border of screen (add padding). Resize window height if needed.
top = destMonitorRect . top + CUSTOM_POSITIONING_LEFT_TOP_PADDING ;
H = min ( H , RectHeight ( destMonitorRect ) - CUSTOM_POSITIONING_LEFT_TOP_PADDING ) ;
}
2020-07-31 19:06:13 +08:00
return { . left = left ,
. top = top ,
. right = left + W ,
2020-07-08 16:37:42 +08:00
. bottom = top + H } ;
}
void OpenWindowOnActiveMonitor ( HWND window , HMONITOR monitor ) noexcept
{
// By default Windows opens new window on primary monitor.
// Try to preserve window width and height, adjust top-left corner if needed.
HMONITOR origin = MonitorFromWindow ( window , MONITOR_DEFAULTTOPRIMARY ) ;
if ( origin = = monitor )
{
// Certain applications by design open in last known position, regardless of FancyZones.
// If that position is on currently active monitor, skip custom positioning.
return ;
}
WINDOWPLACEMENT placement { } ;
if ( GetWindowPlacement ( window , & placement ) )
{
MONITORINFOEX originMi ;
originMi . cbSize = sizeof ( originMi ) ;
if ( GetMonitorInfo ( origin , & originMi ) )
{
MONITORINFOEX destMi ;
destMi . cbSize = sizeof ( destMi ) ;
if ( GetMonitorInfo ( monitor , & destMi ) )
{
RECT newPosition = FitOnScreen ( placement . rcNormalPosition , originMi . rcWork , destMi . rcWork ) ;
2020-08-25 01:38:15 +08:00
FancyZonesUtils : : SizeWindowToRect ( window , newPosition ) ;
2020-07-08 16:37:42 +08:00
}
}
}
}
2019-09-05 00:26:26 +08:00
// IFancyZonesCallback
2020-02-17 23:28:49 +08:00
IFACEMETHODIMP_ ( void )
FancyZones : : WindowCreated ( HWND window ) noexcept
2019-09-05 00:26:26 +08:00
{
2020-04-22 01:57:21 +08:00
std : : shared_lock readLock ( m_lock ) ;
2020-07-20 17:55:19 +08:00
GUID desktopId { } ;
if ( VirtualDesktopUtils : : GetWindowDesktopId ( window , & desktopId ) & & desktopId ! = m_currentDesktopId )
{
// Switch between virtual desktops results with posting same windows messages that also indicate
// creation of new window. We need to check if window being processed is on currently active desktop.
return ;
}
2020-07-31 19:06:13 +08:00
const bool moveToAppLastZone = m_settings - > GetSettings ( ) - > appLastZone_moveWindows ;
2020-07-08 16:37:42 +08:00
const bool openOnActiveMonitor = m_settings - > GetSettings ( ) - > openWindowOnActiveMonitor ;
if ( ( moveToAppLastZone | | openOnActiveMonitor ) & & ShouldProcessNewWindow ( window ) )
2019-09-05 00:26:26 +08:00
{
2020-06-17 17:55:14 +08:00
HMONITOR primary = MonitorFromWindow ( nullptr , MONITOR_DEFAULTTOPRIMARY ) ;
HMONITOR active = primary ;
POINT cursorPosition { } ;
if ( GetCursorPos ( & cursorPosition ) )
2019-09-05 00:26:26 +08:00
{
2020-06-17 17:55:14 +08:00
active = MonitorFromPoint ( cursorPosition , MONITOR_DEFAULTTOPRIMARY ) ;
}
2020-02-10 21:59:51 +08:00
2020-07-08 16:37:42 +08:00
bool windowZoned { false } ;
if ( moveToAppLastZone )
{
const bool primaryActive = ( primary = = active ) ;
2020-08-24 20:39:34 +08:00
std : : pair < winrt : : com_ptr < IZoneWindow > , std : : vector < size_t > > appZoneHistoryInfo = GetAppZoneHistoryInfo ( window , active , primaryActive ) ;
2020-07-08 16:37:42 +08:00
if ( ! appZoneHistoryInfo . second . empty ( ) )
{
MoveWindowIntoZone ( window , appZoneHistoryInfo . first , appZoneHistoryInfo . second ) ;
windowZoned = true ;
}
}
if ( ! windowZoned & & openOnActiveMonitor )
2020-06-17 17:55:14 +08:00
{
2020-07-08 16:37:42 +08:00
m_dpiUnawareThread . submit ( OnThreadExecutor : : task_t { [ & ] { OpenWindowOnActiveMonitor ( window , active ) ; } } ) . wait ( ) ;
2019-09-05 00:26:26 +08:00
}
}
}
// IFancyZonesCallback
2020-02-17 23:28:49 +08:00
IFACEMETHODIMP_ ( bool )
FancyZones : : OnKeyDown ( PKBDLLHOOKSTRUCT info ) noexcept
2019-09-05 00:26:26 +08:00
{
// Return true to swallow the keyboard event
bool const shift = GetAsyncKeyState ( VK_SHIFT ) & 0x8000 ;
2020-05-05 15:21:55 +08:00
bool const win = GetAsyncKeyState ( VK_LWIN ) & 0x8000 | | GetAsyncKeyState ( VK_RWIN ) & 0x8000 ;
2020-09-11 17:32:45 +08:00
bool const alt = GetAsyncKeyState ( VK_MENU ) & 0x8000 ;
bool const ctrl = GetAsyncKeyState ( VK_CONTROL ) & 0x8000 ;
if ( ( win & & ! shift & & ! ctrl ) | | ( win & & ctrl & & alt ) )
2019-09-05 00:26:26 +08:00
{
2020-09-11 17:32:45 +08:00
// Temporarily disable Win+Ctrl+Number functionality
// if (ctrl)
// {
// if ((info->vkCode >= '0') && (info->vkCode <= '9'))
// {
// // Win+Ctrl+Number will cycle through ZoneSets
// Trace::FancyZones::OnKeyDown(info->vkCode, win, ctrl, false /*inMoveSize*/);
// CycleActiveZoneSet(info->vkCode);
// return true;
// }
// }
// else
if ( ( info - > vkCode = = VK_RIGHT ) | | ( info - > vkCode = = VK_LEFT ) | | ( info - > vkCode = = VK_UP ) | | ( info - > vkCode = = VK_DOWN ) )
2019-09-05 00:26:26 +08:00
{
2020-08-21 18:53:03 +08:00
if ( ShouldProcessSnapHotkey ( info - > vkCode ) )
2019-11-19 07:29:42 +08:00
{
Trace : : FancyZones : : OnKeyDown ( info - > vkCode , win , ctrl , false /*inMoveSize*/ ) ;
2020-05-05 02:10:23 +08:00
// Win+Left, Win+Right will cycle through Zones in the active ZoneSet when WM_PRIV_LOWLEVELKB's handled
PostMessageW ( m_window , WM_PRIV_LOWLEVELKB , 0 , info - > vkCode ) ;
return true ;
2019-11-19 07:29:42 +08:00
}
2019-09-05 00:26:26 +08:00
}
}
2020-03-26 01:32:33 +08:00
// Temporarily disable Win+Ctrl+Number functionality
//else if (m_inMoveSize && (info->vkCode >= '0') && (info->vkCode <= '9'))
//{
// // This allows you to cycle through ZoneSets while dragging a window
// Trace::FancyZones::OnKeyDown(info->vkCode, win, false /*control*/, true /*inMoveSize*/);
// CycleActiveZoneSet(info->vkCode);
// return false;
//}
2020-04-30 18:16:08 +08:00
if ( m_windowMoveHandler . IsDragEnabled ( ) & & shift )
2020-03-05 15:01:58 +08:00
{
return true ;
}
2019-09-05 00:26:26 +08:00
return false ;
}
// IFancyZonesCallback
void FancyZones : : ToggleEditor ( ) noexcept
{
{
std : : shared_lock readLock ( m_lock ) ;
if ( m_terminateEditorEvent )
{
SetEvent ( m_terminateEditorEvent . get ( ) ) ;
return ;
}
}
{
std : : unique_lock writeLock ( m_lock ) ;
m_terminateEditorEvent . reset ( CreateEvent ( nullptr , true , false , nullptr ) ) ;
}
2019-09-28 22:29:29 +08:00
HMONITOR monitor { } ;
2019-11-08 02:56:32 +08:00
HWND foregroundWindow { } ;
2019-09-28 22:29:29 +08:00
2020-03-13 17:55:15 +08:00
const bool use_cursorpos_editor_startupscreen = m_settings - > GetSettings ( ) - > use_cursorpos_editor_startupscreen ;
2019-11-08 02:56:32 +08:00
POINT currentCursorPos { } ;
if ( use_cursorpos_editor_startupscreen )
2019-09-05 00:26:26 +08:00
{
2019-09-28 22:29:29 +08:00
GetCursorPos ( & currentCursorPos ) ;
monitor = MonitorFromPoint ( currentCursorPos , MONITOR_DEFAULTTOPRIMARY ) ;
}
else
{
2019-11-08 02:56:32 +08:00
foregroundWindow = GetForegroundWindow ( ) ;
2019-09-28 22:29:29 +08:00
monitor = MonitorFromWindow ( foregroundWindow , MONITOR_DEFAULTTOPRIMARY ) ;
}
if ( ! monitor )
{
return ;
}
2020-08-07 16:06:25 +08:00
winrt : : com_ptr < IZoneWindow > zoneWindow ;
2019-09-28 22:29:29 +08:00
std : : shared_lock readLock ( m_lock ) ;
2020-08-07 16:06:25 +08:00
if ( m_settings - > GetSettings ( ) - > spanZonesAcrossMonitors )
{
zoneWindow = m_workAreaHandler . GetWorkArea ( m_currentDesktopId , NULL ) ;
}
else
{
zoneWindow = m_workAreaHandler . GetWorkArea ( m_currentDesktopId , monitor ) ;
}
2020-05-31 18:36:45 +08:00
if ( ! zoneWindow )
2019-09-28 22:29:29 +08:00
{
return ;
}
2020-08-07 16:06:25 +08:00
std : : wstring editorLocation ;
2019-09-28 22:29:29 +08:00
2020-08-07 16:06:25 +08:00
if ( m_settings - > GetSettings ( ) - > spanZonesAcrossMonitors )
{
std : : vector < std : : pair < HMONITOR , RECT > > allMonitors ;
m_dpiUnawareThread . submit ( OnThreadExecutor : : task_t { [ & ] {
2020-08-25 01:38:15 +08:00
allMonitors = FancyZonesUtils : : GetAllMonitorRects < & MONITORINFOEX : : rcWork > ( ) ;
2020-08-07 16:06:25 +08:00
} } ) . wait ( ) ;
2020-09-07 18:24:13 +08:00
UINT currentDpi = 0 ;
for ( const auto & monitor : allMonitors )
{
UINT dpiX = 0 ;
UINT dpiY = 0 ;
if ( GetDpiForMonitor ( monitor . first , MDT_EFFECTIVE_DPI , & dpiX , & dpiY ) = = S_OK )
{
if ( currentDpi = = 0 )
{
currentDpi = dpiX ;
continue ;
}
if ( currentDpi ! = dpiX )
{
MessageBoxW ( NULL ,
GET_RESOURCE_STRING ( IDS_SPAN_ACROSS_ZONES_WARNING ) . c_str ( ) ,
GET_RESOURCE_STRING ( IDS_POWERTOYS_FANCYZONES ) . c_str ( ) ,
MB_OK | MB_ICONWARNING ) ;
break ;
}
}
}
2020-08-07 16:06:25 +08:00
for ( auto & [ monitor , workArea ] : allMonitors )
{
const auto x = workArea . left ;
const auto y = workArea . top ;
const auto width = workArea . right - workArea . left ;
const auto height = workArea . bottom - workArea . top ;
std : : wstring editorLocationPart =
std : : to_wstring ( x ) + L " _ " +
std : : to_wstring ( y ) + L " _ " +
std : : to_wstring ( width ) + L " _ " +
std : : to_wstring ( height ) ;
if ( editorLocation . empty ( ) )
{
editorLocation = std : : move ( editorLocationPart ) ;
}
else
{
editorLocation + = L ' / ' ;
editorLocation + = editorLocationPart ;
}
}
}
else
{
MONITORINFOEX mi ;
mi . cbSize = sizeof ( mi ) ;
2019-11-08 02:56:32 +08:00
2020-08-07 16:06:25 +08:00
m_dpiUnawareThread . submit ( OnThreadExecutor : : task_t { [ & ] {
GetMonitorInfo ( monitor , & mi ) ;
} } ) . wait ( ) ;
const auto x = mi . rcWork . left ;
const auto y = mi . rcWork . top ;
const auto width = mi . rcWork . right - mi . rcWork . left ;
const auto height = mi . rcWork . bottom - mi . rcWork . top ;
editorLocation =
std : : to_wstring ( x ) + L " _ " +
std : : to_wstring ( y ) + L " _ " +
std : : to_wstring ( width ) + L " _ " +
std : : to_wstring ( height ) ;
}
2019-09-28 22:29:29 +08:00
2020-07-22 16:39:13 +08:00
const auto & fancyZonesData = FancyZonesDataInstance ( ) ;
2020-06-04 19:01:42 +08:00
2020-07-22 16:39:13 +08:00
if ( ! fancyZonesData . SerializeDeviceInfoToTmpFile ( zoneWindow - > UniqueId ( ) ) )
2020-02-17 23:28:49 +08:00
{
return ;
}
2020-02-10 21:59:51 +08:00
2019-09-28 22:29:29 +08:00
const std : : wstring params =
2020-06-04 19:01:42 +08:00
/*1*/ editorLocation + L " " +
2020-07-06 23:40:25 +08:00
/*2*/ L " \" " + std : : to_wstring ( GetCurrentProcessId ( ) ) + L " \" " ;
2019-09-28 22:29:29 +08:00
SHELLEXECUTEINFO sei { sizeof ( sei ) } ;
sei . fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI } ;
2020-08-11 19:51:06 +08:00
sei . lpFile = NonLocalizable : : FZEditorExecutablePath ;
2019-09-28 22:29:29 +08:00
sei . lpParameters = params . c_str ( ) ;
sei . nShow = SW_SHOWNORMAL ;
ShellExecuteEx ( & sei ) ;
2020-03-26 18:54:12 +08:00
Trace : : FancyZones : : EditorLaunched ( 1 ) ;
2019-09-28 22:29:29 +08:00
// Launch the editor on a background thread
// Wait for the editor's process to exit
// Post back to the main thread to update
2020-02-10 21:59:51 +08:00
std : : thread waitForEditorThread ( [ window = m_window , processHandle = sei . hProcess , terminateEditorEvent = m_terminateEditorEvent . get ( ) ] ( ) {
2019-09-28 22:29:29 +08:00
HANDLE waitEvents [ 2 ] = { processHandle , terminateEditorEvent } ;
auto result = WaitForMultipleObjects ( 2 , waitEvents , false , INFINITE ) ;
if ( result = = WAIT_OBJECT_0 + 0 )
2019-09-05 00:26:26 +08:00
{
2019-09-28 22:29:29 +08:00
// Editor exited
// Update any changes it may have made
PostMessage ( window , WM_PRIV_EDITOR , 0 , static_cast < LPARAM > ( EditorExitKind : : Exit ) ) ;
2019-09-05 00:26:26 +08:00
}
2019-09-28 22:29:29 +08:00
else if ( result = = WAIT_OBJECT_0 + 1 )
{
// User hit Win+~ while editor is already running
// Shut it down
TerminateProcess ( processHandle , 2 ) ;
PostMessage ( window , WM_PRIV_EDITOR , 0 , static_cast < LPARAM > ( EditorExitKind : : Terminate ) ) ;
}
CloseHandle ( processHandle ) ;
} ) ;
waitForEditorThread . detach ( ) ;
2019-09-05 00:26:26 +08:00
}
2019-10-02 23:18:55 +08:00
void FancyZones : : SettingsChanged ( ) noexcept
{
// Update the hotkey
UnregisterHotKey ( m_window , 1 ) ;
2020-03-13 17:55:15 +08:00
RegisterHotKey ( m_window , 1 , m_settings - > GetSettings ( ) - > editorHotkey . get_modifiers ( ) , m_settings - > GetSettings ( ) - > editorHotkey . get_code ( ) ) ;
2020-08-07 16:06:25 +08:00
// Needed if we toggled spanZonesAcrossMonitors
m_workAreaHandler . Clear ( ) ;
OnDisplayChange ( DisplayChangeType : : Initialization ) ;
2019-10-02 23:18:55 +08:00
}
2019-09-05 00:26:26 +08:00
// IZoneWindowHost
2020-02-17 23:28:49 +08:00
IFACEMETHODIMP_ ( void )
FancyZones : : MoveWindowsOnActiveZoneSetChange ( ) noexcept
2019-09-05 00:26:26 +08:00
{
2020-03-13 17:55:15 +08:00
if ( m_settings - > GetSettings ( ) - > zoneSetChange_moveWindows )
2019-09-05 00:26:26 +08:00
{
2020-05-06 23:16:16 +08:00
UpdateWindowsPositions ( ) ;
2019-09-05 00:26:26 +08:00
}
}
LRESULT FancyZones : : WndProc ( HWND window , UINT message , WPARAM wparam , LPARAM lparam ) noexcept
{
switch ( message )
{
case WM_HOTKEY :
{
if ( wparam = = 1 )
{
2019-11-19 07:29:42 +08:00
ToggleEditor ( ) ;
2019-09-05 00:26:26 +08:00
}
}
break ;
case WM_SETTINGCHANGE :
{
if ( wparam = = SPI_SETWORKAREA )
{
2020-07-06 23:34:28 +08:00
// Changes in taskbar position resulted in different size of work area.
// Invalidate cached work-areas so they can be recreated with latest information.
m_workAreaHandler . Clear ( ) ;
2019-09-05 00:26:26 +08:00
OnDisplayChange ( DisplayChangeType : : WorkArea ) ;
}
}
break ;
case WM_DISPLAYCHANGE :
{
2020-07-06 23:34:28 +08:00
// Display resolution changed. Invalidate cached work-areas so they can be recreated with latest information.
m_workAreaHandler . Clear ( ) ;
2019-09-05 00:26:26 +08:00
OnDisplayChange ( DisplayChangeType : : DisplayChange ) ;
}
break ;
default :
{
2020-05-04 22:29:48 +08:00
POINT ptScreen ;
GetPhysicalCursorPos ( & ptScreen ) ;
2020-05-05 02:10:23 +08:00
if ( message = = WM_PRIV_LOWLEVELKB )
{
OnSnapHotkey ( static_cast < DWORD > ( lparam ) ) ;
}
else if ( message = = WM_PRIV_VD_INIT )
2020-05-01 22:13:16 +08:00
{
OnDisplayChange ( DisplayChangeType : : Initialization ) ;
}
else if ( message = = WM_PRIV_VD_SWITCH )
2019-09-05 00:26:26 +08:00
{
OnDisplayChange ( DisplayChangeType : : VirtualDesktop ) ;
}
2020-05-01 22:13:16 +08:00
else if ( message = = WM_PRIV_VD_UPDATE )
2019-12-24 22:47:28 +08:00
{
2020-05-01 22:13:16 +08:00
std : : vector < GUID > ids { } ;
2020-05-05 16:13:50 +08:00
if ( VirtualDesktopUtils : : GetVirtualDesktopIds ( ids ) )
2020-05-01 22:13:16 +08:00
{
RegisterVirtualDesktopUpdates ( ids ) ;
}
2019-12-24 22:47:28 +08:00
}
2019-09-05 00:26:26 +08:00
else if ( message = = WM_PRIV_EDITOR )
{
if ( lparam = = static_cast < LPARAM > ( EditorExitKind : : Exit ) )
{
2020-02-10 21:59:51 +08:00
OnEditorExitEvent ( ) ;
2019-09-05 00:26:26 +08:00
}
{
// Clean up the event either way
std : : unique_lock writeLock ( m_lock ) ;
m_terminateEditorEvent . release ( ) ;
}
}
2020-05-04 22:29:48 +08:00
else if ( message = = WM_PRIV_MOVESIZESTART )
{
auto hwnd = reinterpret_cast < HWND > ( wparam ) ;
if ( auto monitor = MonitorFromPoint ( ptScreen , MONITOR_DEFAULTTONULL ) )
{
MoveSizeStart ( hwnd , monitor , ptScreen ) ;
}
}
else if ( message = = WM_PRIV_MOVESIZEEND )
{
auto hwnd = reinterpret_cast < HWND > ( wparam ) ;
MoveSizeEnd ( hwnd , ptScreen ) ;
}
else if ( message = = WM_PRIV_LOCATIONCHANGE & & InMoveSize ( ) )
{
if ( auto monitor = MonitorFromPoint ( ptScreen , MONITOR_DEFAULTTONULL ) )
{
MoveSizeUpdate ( monitor , ptScreen ) ;
}
}
else if ( message = = WM_PRIV_WINDOWCREATED )
{
auto hwnd = reinterpret_cast < HWND > ( wparam ) ;
WindowCreated ( hwnd ) ;
}
2019-09-05 00:26:26 +08:00
else
{
return DefWindowProc ( window , message , wparam , lparam ) ;
}
}
break ;
}
return 0 ;
}
void FancyZones : : OnDisplayChange ( DisplayChangeType changeType ) noexcept
{
2019-12-24 22:47:28 +08:00
if ( changeType = = DisplayChangeType : : VirtualDesktop | |
changeType = = DisplayChangeType : : Initialization )
2019-09-05 00:26:26 +08:00
{
2020-05-31 18:36:45 +08:00
m_previousDesktopId = m_currentDesktopId ;
2019-09-05 00:26:26 +08:00
GUID currentVirtualDesktopId { } ;
2020-04-30 17:16:25 +08:00
if ( VirtualDesktopUtils : : GetCurrentVirtualDesktopId ( & currentVirtualDesktopId ) )
2019-09-05 00:26:26 +08:00
{
2020-05-31 18:36:45 +08:00
m_currentDesktopId = currentVirtualDesktopId ;
2020-06-16 01:44:07 +08:00
if ( m_previousDesktopId ! = GUID_NULL & & m_currentDesktopId ! = m_previousDesktopId )
{
Trace : : VirtualDesktopChanged ( ) ;
}
2020-05-05 16:13:50 +08:00
}
if ( changeType = = DisplayChangeType : : Initialization )
{
std : : vector < std : : wstring > ids { } ;
if ( VirtualDesktopUtils : : GetVirtualDesktopIds ( ids ) & & ! ids . empty ( ) )
2020-04-30 17:16:25 +08:00
{
2020-07-22 16:39:13 +08:00
FancyZonesDataInstance ( ) . UpdatePrimaryDesktopData ( ids [ 0 ] ) ;
FancyZonesDataInstance ( ) . RemoveDeletedDesktops ( ids ) ;
2020-04-30 17:16:25 +08:00
}
2019-09-05 00:26:26 +08:00
}
}
UpdateZoneWindows ( ) ;
if ( ( changeType = = DisplayChangeType : : WorkArea ) | | ( changeType = = DisplayChangeType : : DisplayChange ) )
{
2020-03-13 17:55:15 +08:00
if ( m_settings - > GetSettings ( ) - > displayChange_moveWindows )
2019-09-05 00:26:26 +08:00
{
2020-05-06 23:16:16 +08:00
UpdateWindowsPositions ( ) ;
2019-09-05 00:26:26 +08:00
}
}
}
void FancyZones : : AddZoneWindow ( HMONITOR monitor , PCWSTR deviceId ) noexcept
{
std : : unique_lock writeLock ( m_lock ) ;
2020-02-10 21:59:51 +08:00
2020-05-31 18:36:45 +08:00
if ( m_workAreaHandler . IsNewWorkArea ( m_currentDesktopId , monitor ) )
{
wil : : unique_cotaskmem_string virtualDesktopId ;
if ( SUCCEEDED ( StringFromCLSID ( m_currentDesktopId , & virtualDesktopId ) ) )
2019-09-05 00:26:26 +08:00
{
2020-08-07 16:06:25 +08:00
std : : wstring uniqueId ;
if ( monitor )
{
uniqueId = ZoneWindowUtils : : GenerateUniqueId ( monitor , deviceId , virtualDesktopId . get ( ) ) ;
}
else
{
uniqueId = ZoneWindowUtils : : GenerateUniqueIdAllMonitorsArea ( virtualDesktopId . get ( ) ) ;
}
2020-03-05 15:01:58 +08:00
2020-05-31 18:36:45 +08:00
// "Turning FLASHING_ZONE option off"
//const bool flash = m_settings->GetSettings()->zoneSetChange_flashZones;
const bool flash = false ;
std : : wstring parentId { } ;
auto parentArea = m_workAreaHandler . GetWorkArea ( m_previousDesktopId , monitor ) ;
if ( parentArea )
{
parentId = parentArea - > UniqueId ( ) ;
}
auto workArea = MakeZoneWindow ( this , m_hinstance , monitor , uniqueId , parentId , flash ) ;
if ( workArea )
{
m_workAreaHandler . AddWorkArea ( m_currentDesktopId , monitor , workArea ) ;
2020-07-22 16:39:13 +08:00
FancyZonesDataInstance ( ) . SaveFancyZonesData ( ) ;
2020-05-31 18:36:45 +08:00
}
2020-02-18 18:55:08 +08:00
}
2019-09-05 00:26:26 +08:00
}
}
LRESULT CALLBACK FancyZones : : s_WndProc ( HWND window , UINT message , WPARAM wparam , LPARAM lparam ) noexcept
{
auto thisRef = reinterpret_cast < FancyZones * > ( GetWindowLongPtr ( window , GWLP_USERDATA ) ) ;
if ( ! thisRef & & ( message = = WM_CREATE ) )
{
const auto createStruct = reinterpret_cast < LPCREATESTRUCT > ( lparam ) ;
thisRef = reinterpret_cast < FancyZones * > ( createStruct - > lpCreateParams ) ;
SetWindowLongPtr ( window , GWLP_USERDATA , reinterpret_cast < LONG_PTR > ( thisRef ) ) ;
}
return thisRef ? thisRef - > WndProc ( window , message , wparam , lparam ) :
2020-02-10 21:59:51 +08:00
DefWindowProc ( window , message , wparam , lparam ) ;
2019-09-05 00:26:26 +08:00
}
void FancyZones : : UpdateZoneWindows ( ) noexcept
{
2020-02-10 21:59:51 +08:00
auto callback = [ ] ( HMONITOR monitor , HDC , RECT * , LPARAM data ) - > BOOL {
2019-09-05 00:26:26 +08:00
MONITORINFOEX mi ;
mi . cbSize = sizeof ( mi ) ;
if ( GetMonitorInfo ( monitor , & mi ) )
{
DISPLAY_DEVICE displayDevice = { sizeof ( displayDevice ) } ;
PCWSTR deviceId = nullptr ;
bool validMonitor = true ;
if ( EnumDisplayDevices ( mi . szDevice , 0 , & displayDevice , 1 ) )
{
if ( WI_IsFlagSet ( displayDevice . StateFlags , DISPLAY_DEVICE_MIRRORING_DRIVER ) )
{
validMonitor = FALSE ;
}
else if ( displayDevice . DeviceID [ 0 ] ! = L ' \0 ' )
{
deviceId = displayDevice . DeviceID ;
}
}
if ( validMonitor )
{
if ( ! deviceId )
{
deviceId = GetSystemMetrics ( SM_REMOTESESSION ) ?
2020-02-10 21:59:51 +08:00
L " \\ \\ ? \\ DISPLAY#REMOTEDISPLAY# " :
L " \\ \\ ? \\ DISPLAY#LOCALDISPLAY# " ;
2019-09-05 00:26:26 +08:00
}
auto strongThis = reinterpret_cast < FancyZones * > ( data ) ;
strongThis - > AddZoneWindow ( monitor , deviceId ) ;
}
}
return TRUE ;
} ;
2020-08-07 16:06:25 +08:00
if ( m_settings - > GetSettings ( ) - > spanZonesAcrossMonitors )
{
AddZoneWindow ( nullptr , NULL ) ;
}
else
{
EnumDisplayMonitors ( nullptr , nullptr , callback , reinterpret_cast < LPARAM > ( this ) ) ;
}
2019-09-05 00:26:26 +08:00
}
2020-05-06 23:16:16 +08:00
void FancyZones : : UpdateWindowsPositions ( ) noexcept
2019-09-05 00:26:26 +08:00
{
2020-02-10 21:59:51 +08:00
auto callback = [ ] ( HWND window , LPARAM data ) - > BOOL {
2020-08-11 19:51:06 +08:00
size_t bitmask = reinterpret_cast < size_t > ( : : GetProp ( window , ZonedWindowProperties : : PropertyMultipleZoneID ) ) ;
2020-05-26 22:01:12 +08:00
if ( bitmask ! = 0 )
2019-09-05 00:26:26 +08:00
{
2020-08-24 20:39:34 +08:00
std : : vector < size_t > indexSet ;
2020-05-26 22:01:12 +08:00
for ( int i = 0 ; i < std : : numeric_limits < size_t > : : digits ; i + + )
{
if ( ( 1ull < < i ) & bitmask )
{
indexSet . push_back ( i ) ;
}
}
2019-09-05 00:26:26 +08:00
auto strongThis = reinterpret_cast < FancyZones * > ( data ) ;
2020-04-30 18:16:08 +08:00
std : : unique_lock writeLock ( strongThis - > m_lock ) ;
2020-05-31 18:36:45 +08:00
auto zoneWindow = strongThis - > m_workAreaHandler . GetWorkArea ( window ) ;
if ( zoneWindow )
{
strongThis - > m_windowMoveHandler . MoveWindowIntoZoneByIndexSet ( window , indexSet , zoneWindow ) ;
}
2019-09-05 00:26:26 +08:00
}
return TRUE ;
} ;
EnumWindows ( callback , reinterpret_cast < LPARAM > ( this ) ) ;
}
void FancyZones : : CycleActiveZoneSet ( DWORD vkCode ) noexcept
{
2020-02-03 16:32:38 +08:00
auto window = GetForegroundWindow ( ) ;
2020-08-28 21:00:21 +08:00
if ( FancyZonesUtils : : IsCandidateForZoning ( window , m_settings - > GetSettings ( ) - > excludedAppsArray ) )
2019-09-05 00:26:26 +08:00
{
2020-02-10 21:59:51 +08:00
const HMONITOR monitor = MonitorFromWindow ( window , MONITOR_DEFAULTTONULL ) ;
if ( monitor )
2019-09-05 00:26:26 +08:00
{
std : : shared_lock readLock ( m_lock ) ;
2020-02-10 21:59:51 +08:00
2020-05-31 18:36:45 +08:00
auto zoneWindow = m_workAreaHandler . GetWorkArea ( m_currentDesktopId , monitor ) ;
if ( zoneWindow )
2019-09-05 00:26:26 +08:00
{
2020-05-31 18:36:45 +08:00
zoneWindow - > CycleActiveZoneSet ( vkCode ) ;
2019-09-05 00:26:26 +08:00
}
}
}
}
2020-08-21 18:53:03 +08:00
bool FancyZones : : OnSnapHotkeyBasedOnZoneNumber ( HWND window , DWORD vkCode ) noexcept
2019-09-05 00:26:26 +08:00
{
2020-08-21 18:53:03 +08:00
HMONITOR current ;
if ( m_settings - > GetSettings ( ) - > spanZonesAcrossMonitors )
{
current = NULL ;
}
else
2019-09-05 00:26:26 +08:00
{
2020-08-21 18:53:03 +08:00
current = MonitorFromWindow ( window , MONITOR_DEFAULTTONULL ) ;
}
2020-08-07 16:06:25 +08:00
2020-08-21 18:53:03 +08:00
std : : vector < HMONITOR > monitorInfo = GetMonitorsSorted ( ) ;
if ( current & & monitorInfo . size ( ) > 1 & & m_settings - > GetSettings ( ) - > moveWindowAcrossMonitors )
{
// Multi monitor environment.
auto currMonitorInfo = std : : find ( std : : begin ( monitorInfo ) , std : : end ( monitorInfo ) , current ) ;
do
2020-08-07 16:06:25 +08:00
{
2020-08-21 18:53:03 +08:00
std : : unique_lock writeLock ( m_lock ) ;
if ( m_windowMoveHandler . MoveWindowIntoZoneByDirectionAndIndex ( window , vkCode , false /* cycle through zones */ , m_workAreaHandler . GetWorkArea ( m_currentDesktopId , * currMonitorInfo ) ) )
{
return true ;
}
// We iterated through all zones in current monitor zone layout, move on to next one (or previous depending on direction).
if ( vkCode = = VK_RIGHT )
{
currMonitorInfo = std : : next ( currMonitorInfo ) ;
if ( currMonitorInfo = = std : : end ( monitorInfo ) )
{
currMonitorInfo = std : : begin ( monitorInfo ) ;
}
}
else if ( vkCode = = VK_LEFT )
{
if ( currMonitorInfo = = std : : begin ( monitorInfo ) )
{
currMonitorInfo = std : : end ( monitorInfo ) ;
}
currMonitorInfo = std : : prev ( currMonitorInfo ) ;
}
} while ( * currMonitorInfo ! = current ) ;
}
else
{
// Single monitor environment, or combined multi-monitor environment.
std : : unique_lock writeLock ( m_lock ) ;
if ( m_settings - > GetSettings ( ) - > restoreSize )
{
bool moved = m_windowMoveHandler . MoveWindowIntoZoneByDirectionAndIndex ( window , vkCode , false /* cycle through zones */ , m_workAreaHandler . GetWorkArea ( m_currentDesktopId , current ) ) ;
if ( ! moved )
{
2020-08-25 01:38:15 +08:00
FancyZonesUtils : : RestoreWindowOrigin ( window ) ;
FancyZonesUtils : : RestoreWindowSize ( window ) ;
2020-08-21 18:53:03 +08:00
}
return true ;
2020-08-07 16:06:25 +08:00
}
else
{
2020-08-21 18:53:03 +08:00
return m_windowMoveHandler . MoveWindowIntoZoneByDirectionAndIndex ( window , vkCode , true /* cycle through zones */ , m_workAreaHandler . GetWorkArea ( m_currentDesktopId , current ) ) ;
}
}
2020-08-24 20:39:34 +08:00
return false ;
2020-08-21 18:53:03 +08:00
}
bool FancyZones : : OnSnapHotkeyBasedOnPosition ( HWND window , DWORD vkCode ) noexcept
{
HMONITOR current ;
if ( m_settings - > GetSettings ( ) - > spanZonesAcrossMonitors )
{
current = NULL ;
}
else
{
current = MonitorFromWindow ( window , MONITOR_DEFAULTTONULL ) ;
}
2020-08-25 01:38:15 +08:00
auto allMonitors = FancyZonesUtils : : GetAllMonitorRects < & MONITORINFOEX : : rcWork > ( ) ;
2020-08-21 18:53:03 +08:00
if ( current & & allMonitors . size ( ) > 1 & & m_settings - > GetSettings ( ) - > moveWindowAcrossMonitors )
{
// Multi monitor environment.
// First, try to stay on the same monitor
2020-09-11 17:32:45 +08:00
bool success = ProcessDirectedSnapHotkey ( window , vkCode , false , m_workAreaHandler . GetWorkArea ( m_currentDesktopId , current ) ) ;
2020-08-21 18:53:03 +08:00
if ( success )
{
return true ;
2020-08-07 16:06:25 +08:00
}
2020-08-21 18:53:03 +08:00
// If that didn't work, extract zones from all other monitors and target one of them
std : : vector < RECT > zoneRects ;
std : : vector < std : : pair < size_t , winrt : : com_ptr < IZoneWindow > > > zoneRectsInfo ;
RECT currentMonitorRect { . top = 0 , . bottom = - 1 } ;
for ( const auto & [ monitor , monitorRect ] : allMonitors )
2019-09-05 00:26:26 +08:00
{
2020-08-21 18:53:03 +08:00
if ( monitor = = current )
2019-09-05 00:26:26 +08:00
{
2020-08-21 18:53:03 +08:00
currentMonitorRect = monitorRect ;
}
else
{
auto workArea = m_workAreaHandler . GetWorkArea ( m_currentDesktopId , monitor ) ;
auto zoneSet = workArea - > ActiveZoneSet ( ) ;
if ( zoneSet )
2020-07-01 21:36:05 +08:00
{
2020-08-21 18:53:03 +08:00
auto zones = zoneSet - > GetZones ( ) ;
for ( size_t i = 0 ; i < zones . size ( ) ; i + + )
2020-07-01 21:36:05 +08:00
{
2020-08-21 18:53:03 +08:00
const auto & zone = zones [ i ] ;
RECT zoneRect = zone - > GetZoneRect ( ) ;
zoneRect . left + = monitorRect . left ;
zoneRect . right + = monitorRect . left ;
zoneRect . top + = monitorRect . top ;
zoneRect . bottom + = monitorRect . top ;
zoneRects . emplace_back ( zoneRect ) ;
zoneRectsInfo . emplace_back ( i , workArea ) ;
2020-07-01 21:36:05 +08:00
}
}
2020-08-21 18:53:03 +08:00
}
2020-08-07 16:06:25 +08:00
}
2020-08-21 18:53:03 +08:00
// Ensure we can get the windowRect, if not, just quit
RECT windowRect ;
if ( ! GetWindowRect ( window , & windowRect ) )
2020-08-07 16:06:25 +08:00
{
2020-08-21 18:53:03 +08:00
return false ;
}
2020-08-25 01:38:15 +08:00
size_t chosenIdx = FancyZonesUtils : : ChooseNextZoneByPosition ( vkCode , windowRect , zoneRects ) ;
2020-08-21 18:53:03 +08:00
if ( chosenIdx < zoneRects . size ( ) )
{
// Moving to another monitor succeeded
const auto & [ trueZoneIdx , zoneWindow ] = zoneRectsInfo [ chosenIdx ] ;
2020-08-24 20:39:34 +08:00
m_windowMoveHandler . MoveWindowIntoZoneByIndexSet ( window , { trueZoneIdx } , zoneWindow ) ;
2020-08-21 18:53:03 +08:00
return true ;
}
// We reached the end of all monitors.
// Try again, cycling on all monitors.
// First, add zones from the origin monitor to zoneRects
// Sanity check: the current monitor is valid
if ( currentMonitorRect . top < = currentMonitorRect . bottom )
{
auto workArea = m_workAreaHandler . GetWorkArea ( m_currentDesktopId , current ) ;
auto zoneSet = workArea - > ActiveZoneSet ( ) ;
if ( zoneSet )
2020-08-07 16:06:25 +08:00
{
2020-08-21 18:53:03 +08:00
auto zones = zoneSet - > GetZones ( ) ;
for ( size_t i = 0 ; i < zones . size ( ) ; i + + )
2020-07-01 21:36:05 +08:00
{
2020-08-21 18:53:03 +08:00
const auto & zone = zones [ i ] ;
RECT zoneRect = zone - > GetZoneRect ( ) ;
zoneRect . left + = currentMonitorRect . left ;
zoneRect . right + = currentMonitorRect . left ;
zoneRect . top + = currentMonitorRect . top ;
zoneRect . bottom + = currentMonitorRect . top ;
zoneRects . emplace_back ( zoneRect ) ;
zoneRectsInfo . emplace_back ( i , workArea ) ;
2020-07-01 21:36:05 +08:00
}
2019-09-05 00:26:26 +08:00
}
}
2020-08-21 18:53:03 +08:00
else
{
return false ;
}
2020-08-25 01:38:15 +08:00
RECT combinedRect = FancyZonesUtils : : GetAllMonitorsCombinedRect < & MONITORINFOEX : : rcWork > ( ) ;
windowRect = FancyZonesUtils : : PrepareRectForCycling ( windowRect , combinedRect , vkCode ) ;
chosenIdx = FancyZonesUtils : : ChooseNextZoneByPosition ( vkCode , windowRect , zoneRects ) ;
2020-08-21 18:53:03 +08:00
if ( chosenIdx < zoneRects . size ( ) )
{
// Moving to another monitor succeeded
const auto & [ trueZoneIdx , zoneWindow ] = zoneRectsInfo [ chosenIdx ] ;
2020-08-24 20:39:34 +08:00
m_windowMoveHandler . MoveWindowIntoZoneByIndexSet ( window , { trueZoneIdx } , zoneWindow ) ;
2020-08-21 18:53:03 +08:00
return true ;
}
else
{
// Giving up
return false ;
}
}
else
{
// Single monitor environment, or combined multi-monitor environment.
2020-09-11 17:32:45 +08:00
return ProcessDirectedSnapHotkey ( window , vkCode , true , m_workAreaHandler . GetWorkArea ( m_currentDesktopId , current ) ) ;
2020-08-21 18:53:03 +08:00
}
}
bool FancyZones : : OnSnapHotkey ( DWORD vkCode ) noexcept
{
auto window = GetForegroundWindow ( ) ;
2020-08-28 21:00:21 +08:00
if ( FancyZonesUtils : : IsCandidateForZoning ( window , m_settings - > GetSettings ( ) - > excludedAppsArray ) )
2020-08-21 18:53:03 +08:00
{
if ( m_settings - > GetSettings ( ) - > moveWindowsBasedOnPosition )
{
return OnSnapHotkeyBasedOnPosition ( window , vkCode ) ;
}
else
{
return ( vkCode = = VK_LEFT | | vkCode = = VK_RIGHT ) & & OnSnapHotkeyBasedOnZoneNumber ( window , vkCode ) ;
}
2019-09-05 00:26:26 +08:00
}
2020-02-06 20:12:59 +08:00
return false ;
2019-09-05 00:26:26 +08:00
}
2020-09-11 17:32:45 +08:00
bool FancyZones : : ProcessDirectedSnapHotkey ( HWND window , DWORD vkCode , bool cycle , winrt : : com_ptr < IZoneWindow > zoneWindow ) noexcept
{
// Check whether Alt is used in the shortcut key combination
if ( GetAsyncKeyState ( VK_MENU ) & 0x8000 )
{
return m_windowMoveHandler . ExtendWindowByDirectionAndPosition ( window , vkCode , zoneWindow ) ;
}
else
{
return m_windowMoveHandler . MoveWindowIntoZoneByDirectionAndPosition ( window , vkCode , cycle , zoneWindow ) ;
}
}
2020-05-01 22:13:16 +08:00
void FancyZones : : RegisterVirtualDesktopUpdates ( std : : vector < GUID > & ids ) noexcept
2020-02-18 18:55:08 +08:00
{
std : : unique_lock writeLock ( m_lock ) ;
2020-05-31 18:36:45 +08:00
2020-06-05 23:25:52 +08:00
m_workAreaHandler . RegisterUpdates ( ids ) ;
std : : vector < std : : wstring > active { } ;
if ( VirtualDesktopUtils : : GetVirtualDesktopIds ( active ) )
2020-02-18 18:55:08 +08:00
{
2020-07-22 16:39:13 +08:00
FancyZonesDataInstance ( ) . RemoveDeletedDesktops ( active ) ;
2020-02-18 18:55:08 +08:00
}
2019-12-12 17:10:55 +08:00
}
2020-05-27 22:52:59 +08:00
bool FancyZones : : IsSplashScreen ( HWND window )
{
wchar_t className [ MAX_PATH ] ;
if ( GetClassName ( window , className , MAX_PATH ) = = 0 )
{
return false ;
}
2020-08-11 19:51:06 +08:00
return wcscmp ( NonLocalizable : : SplashClassName , className ) = = 0 ;
2020-05-27 22:52:59 +08:00
}
2020-02-10 21:59:51 +08:00
void FancyZones : : OnEditorExitEvent ( ) noexcept
{
2020-05-26 22:56:25 +08:00
// Collect information about changes in zone layout after editor exited.
2020-07-22 16:39:13 +08:00
FancyZonesDataInstance ( ) . ParseDataFromTmpFiles ( ) ;
2020-05-31 18:36:45 +08:00
for ( auto workArea : m_workAreaHandler . GetAllWorkAreas ( ) )
2020-05-06 23:16:16 +08:00
{
2020-05-31 18:36:45 +08:00
workArea - > UpdateActiveZoneSet ( ) ;
2020-05-06 23:16:16 +08:00
}
if ( m_settings - > GetSettings ( ) - > zoneSetChange_moveWindows )
{
UpdateWindowsPositions ( ) ;
}
2020-02-10 21:59:51 +08:00
}
2020-08-21 18:53:03 +08:00
bool FancyZones : : ShouldProcessSnapHotkey ( DWORD vkCode ) noexcept
2020-05-25 16:15:42 +08:00
{
if ( m_settings - > GetSettings ( ) - > overrideSnapHotkeys )
{
2020-08-07 16:06:25 +08:00
HMONITOR monitor ;
if ( m_settings - > GetSettings ( ) - > spanZonesAcrossMonitors )
2020-05-25 16:15:42 +08:00
{
2020-08-07 16:06:25 +08:00
monitor = NULL ;
}
else
{
monitor = MonitorFromWindow ( GetForegroundWindow ( ) , MONITOR_DEFAULTTONULL ) ;
}
auto zoneWindow = m_workAreaHandler . GetWorkArea ( m_currentDesktopId , monitor ) ;
if ( zoneWindow - > ActiveZoneSet ( ) ! = nullptr )
{
2020-08-21 18:53:03 +08:00
if ( vkCode = = VK_UP | | vkCode = = VK_DOWN )
{
return m_settings - > GetSettings ( ) - > moveWindowsBasedOnPosition ;
}
else
{
return true ;
}
2020-05-25 16:15:42 +08:00
}
}
return false ;
}
2020-03-25 01:50:26 +08:00
std : : vector < HMONITOR > FancyZones : : GetMonitorsSorted ( ) noexcept
{
std : : shared_lock readLock ( m_lock ) ;
auto monitorInfo = GetRawMonitorData ( ) ;
2020-08-25 01:38:15 +08:00
FancyZonesUtils : : OrderMonitors ( monitorInfo ) ;
2020-03-25 01:50:26 +08:00
std : : vector < HMONITOR > output ;
std : : transform ( std : : begin ( monitorInfo ) , std : : end ( monitorInfo ) , std : : back_inserter ( output ) , [ ] ( const auto & info ) { return info . first ; } ) ;
return output ;
}
std : : vector < std : : pair < HMONITOR , RECT > > FancyZones : : GetRawMonitorData ( ) noexcept
{
std : : shared_lock readLock ( m_lock ) ;
std : : vector < std : : pair < HMONITOR , RECT > > monitorInfo ;
2020-05-31 18:36:45 +08:00
const auto & activeWorkAreaMap = m_workAreaHandler . GetWorkAreasByDesktopId ( m_currentDesktopId ) ;
for ( const auto & [ monitor , workArea ] : activeWorkAreaMap )
2020-03-25 01:50:26 +08:00
{
2020-05-31 18:36:45 +08:00
if ( workArea - > ActiveZoneSet ( ) ! = nullptr )
2020-03-25 01:50:26 +08:00
{
MONITORINFOEX mi ;
mi . cbSize = sizeof ( mi ) ;
GetMonitorInfo ( monitor , & mi ) ;
monitorInfo . push_back ( { monitor , mi . rcMonitor } ) ;
}
}
return monitorInfo ;
}
2020-02-10 21:59:51 +08:00
winrt : : com_ptr < IFancyZones > MakeFancyZones ( HINSTANCE hinstance , const winrt : : com_ptr < IFancyZonesSettings > & settings ) noexcept
2019-09-05 00:26:26 +08:00
{
2020-02-10 21:59:51 +08:00
if ( ! settings )
{
return nullptr ;
}
2019-09-05 00:26:26 +08:00
return winrt : : make_self < FancyZones > ( hinstance , settings ) ;
2020-03-24 22:17:25 +08:00
}