[FancyZones] Feature to create zone layouts spanning multiple monitors (#5289)

* Added the setting

* Added a property to Editor Settings

This will be used later

* Fixed a bug in the previous commit

* Simplified a method

* Added snapping points to the editor

* Simplified a method in ZoneSet

* Updated ZoneSet testcases

* Add a method to FancyZones / ZoneWindowHost

* Almost works

* The editor now launches, but FZ does not understand the results

* Refactored some code

* Snapping to a zone by dragging seems to work

* Hotkeys seem to work

* Refresh the work area handler after changing settings

* Fixed zones not snapping to monitor edges when moved

* Remove unused method in FancyZones.h

* Fixed an issue with DPI awareness

* Renamed setting to spanZonesAcrossMonitors

* Renamed a function

* Fixed a bug with the magnetic effect

* Fix restoring window positions on layout changes
This commit is contained in:
Ivan Stošić 2020-08-07 10:06:25 +02:00 committed by GitHub
parent 26bf05dd7e
commit 8f98866d71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 469 additions and 170 deletions

View File

@ -24,6 +24,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
FancyzonesRestoreSize = new BoolProperty(); FancyzonesRestoreSize = new BoolProperty();
UseCursorposEditorStartupscreen = new BoolProperty(ConfigDefaults.DefaultUseCursorposEditorStartupscreen); UseCursorposEditorStartupscreen = new BoolProperty(ConfigDefaults.DefaultUseCursorposEditorStartupscreen);
FancyzonesShowOnAllMonitors = new BoolProperty(); FancyzonesShowOnAllMonitors = new BoolProperty();
FancyzonesSpanZonesAcrossMonitors = new BoolProperty();
FancyzonesZoneHighlightColor = new StringProperty(ConfigDefaults.DefaultFancyZonesZoneHighlightColor); FancyzonesZoneHighlightColor = new StringProperty(ConfigDefaults.DefaultFancyZonesZoneHighlightColor);
FancyzonesHighlightOpacity = new IntProperty(50); FancyzonesHighlightOpacity = new IntProperty(50);
FancyzonesEditorHotkey = new KeyboardKeysProperty(DefaultHotkeyValue); FancyzonesEditorHotkey = new KeyboardKeysProperty(DefaultHotkeyValue);
@ -66,6 +67,9 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
[JsonPropertyName("fancyzones_show_on_all_monitors")] [JsonPropertyName("fancyzones_show_on_all_monitors")]
public BoolProperty FancyzonesShowOnAllMonitors { get; set; } public BoolProperty FancyzonesShowOnAllMonitors { get; set; }
[JsonPropertyName("fancyzones_span_zones_across_monitors")]
public BoolProperty FancyzonesSpanZonesAcrossMonitors { get; set; }
[JsonPropertyName("fancyzones_makeDraggedWindowTransparent")] [JsonPropertyName("fancyzones_makeDraggedWindowTransparent")]
public BoolProperty FancyzonesMakeDraggedWindowTransparent { get; set; } public BoolProperty FancyzonesMakeDraggedWindowTransparent { get; set; }

View File

@ -642,4 +642,7 @@
<data name="About_PowerToys.Text" xml:space="preserve"> <data name="About_PowerToys.Text" xml:space="preserve">
<value>Microsoft PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity</value> <value>Microsoft PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity</value>
</data> </data>
<data name="FancyZones_SpanZonesAcrossMonitorsCheckBoxControl.Content" xml:space="preserve">
<value>Allow zones to span across monitors</value>
</data>
</root> </root>

View File

@ -45,11 +45,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
_restoreSize = Settings.Properties.FancyzonesRestoreSize.Value; _restoreSize = Settings.Properties.FancyzonesRestoreSize.Value;
_useCursorPosEditorStartupScreen = Settings.Properties.UseCursorposEditorStartupscreen.Value; _useCursorPosEditorStartupScreen = Settings.Properties.UseCursorposEditorStartupscreen.Value;
_showOnAllMonitors = Settings.Properties.FancyzonesShowOnAllMonitors.Value; _showOnAllMonitors = Settings.Properties.FancyzonesShowOnAllMonitors.Value;
_spanZonesAcrossMonitors = Settings.Properties.FancyzonesSpanZonesAcrossMonitors.Value;
_makeDraggedWindowTransparent = Settings.Properties.FancyzonesMakeDraggedWindowTransparent.Value; _makeDraggedWindowTransparent = Settings.Properties.FancyzonesMakeDraggedWindowTransparent.Value;
_highlightOpacity = Settings.Properties.FancyzonesHighlightOpacity.Value; _highlightOpacity = Settings.Properties.FancyzonesHighlightOpacity.Value;
_excludedApps = Settings.Properties.FancyzonesExcludedApps.Value; _excludedApps = Settings.Properties.FancyzonesExcludedApps.Value;
EditorHotkey = Settings.Properties.FancyzonesEditorHotkey.Value; EditorHotkey = Settings.Properties.FancyzonesEditorHotkey.Value;
string inactiveColor = Settings.Properties.FancyzonesInActiveColor.Value; string inactiveColor = Settings.Properties.FancyzonesInActiveColor.Value;
_zoneInActiveColor = inactiveColor != string.Empty ? inactiveColor.ToColor() : "#F5FCFF".ToColor(); _zoneInActiveColor = inactiveColor != string.Empty ? inactiveColor.ToColor() : "#F5FCFF".ToColor();
@ -82,6 +82,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private bool _zoneSetChangeMoveWindows; private bool _zoneSetChangeMoveWindows;
private bool _appLastZoneMoveWindows; private bool _appLastZoneMoveWindows;
private bool _openWindowOnActiveMonitor; private bool _openWindowOnActiveMonitor;
private bool _spanZonesAcrossMonitors;
private bool _restoreSize; private bool _restoreSize;
private bool _useCursorPosEditorStartupScreen; private bool _useCursorPosEditorStartupScreen;
private bool _showOnAllMonitors; private bool _showOnAllMonitors;
@ -314,6 +315,24 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
} }
} }
public bool SpanZonesAcrossMonitors
{
get
{
return _spanZonesAcrossMonitors;
}
set
{
if (value != _spanZonesAcrossMonitors)
{
_spanZonesAcrossMonitors = value;
Settings.Properties.FancyzonesSpanZonesAcrossMonitors.Value = value;
RaisePropertyChanged();
}
}
}
public bool MakeDraggedWindowsTransparent public bool MakeDraggedWindowsTransparent
{ {
get get

View File

@ -150,6 +150,11 @@
Margin="{StaticResource SmallTopMargin}" Margin="{StaticResource SmallTopMargin}"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"/> IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"/>
<CheckBox x:Uid="FancyZones_SpanZonesAcrossMonitorsCheckBoxControl"
IsChecked="{x:Bind Mode=TwoWay, Path=ViewModel.SpanZonesAcrossMonitors}"
Margin="{StaticResource SmallTopMargin}"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"/>
<CheckBox x:Uid="FancyZones_MakeDraggedWindowTransparentCheckBoxControl" <CheckBox x:Uid="FancyZones_MakeDraggedWindowTransparentCheckBoxControl"
IsChecked="{x:Bind Mode=TwoWay, Path=ViewModel.MakeDraggedWindowsTransparent}" IsChecked="{x:Bind Mode=TwoWay, Path=ViewModel.MakeDraggedWindowsTransparent}"
Margin="{StaticResource SmallTopMargin}" Margin="{StaticResource SmallTopMargin}"

View File

@ -266,6 +266,24 @@ namespace ViewModelTests
viewModel.ShowOnAllMonitors = true; viewModel.ShowOnAllMonitors = true;
} }
[TestMethod]
public void SpanZonesAcrossMonitors_ShouldSetValue2True_WhenSuccessful()
{
// arrange
FancyZonesViewModel viewModel = new FancyZonesViewModel();
Assert.IsFalse(viewModel.SpanZonesAcrossMonitors); // check if value was initialized to false.
// Assert
ShellPage.DefaultSndMSGCallback = msg =>
{
FancyZonesSettingsIPCMessage snd = JsonSerializer.Deserialize<FancyZonesSettingsIPCMessage>(msg);
Assert.IsTrue(snd.Powertoys.FancyZones.Properties.FancyzonesSpanZonesAcrossMonitors.Value);
};
// act
viewModel.SpanZonesAcrossMonitors = true;
}
[TestMethod] [TestMethod]
public void ZoneHighlightColor_ShouldSetColorValue2White_WhenSuccessful() public void ZoneHighlightColor_ShouldSetColorValue2White_WhenSuccessful()
{ {

View File

@ -60,8 +60,9 @@ namespace FancyZonesEditor
/// <param name="zoneIndex">The index of the zone to track</param> /// <param name="zoneIndex">The index of the zone to track</param>
/// <param name="isX"> Whether this is the X or Y SnappyHelper</param> /// <param name="isX"> Whether this is the X or Y SnappyHelper</param>
/// <param name="mode"> One of the three modes of operation (for example: tracking left/right/both edges)</param> /// <param name="mode"> One of the three modes of operation (for example: tracking left/right/both edges)</param>
/// <param name="screenAxisOrigin"> The origin (left/top) of the screen in this (X or Y) dimension</param>
/// <param name="screenAxisSize"> The size of the screen in this (X or Y) dimension</param> /// <param name="screenAxisSize"> The size of the screen in this (X or Y) dimension</param>
public SnappyHelperBase(IList<Int32Rect> zones, int zoneIndex, bool isX, ResizeMode mode, int screenAxisSize) public SnappyHelperBase(IList<Int32Rect> zones, int zoneIndex, bool isX, ResizeMode mode, int screenAxisOrigin, int screenAxisSize)
{ {
int zonePosition = isX ? zones[zoneIndex].X : zones[zoneIndex].Y; int zonePosition = isX ? zones[zoneIndex].X : zones[zoneIndex].Y;
int zoneAxisSize = isX ? zones[zoneIndex].Width : zones[zoneIndex].Height; int zoneAxisSize = isX ? zones[zoneIndex].Width : zones[zoneIndex].Height;
@ -83,6 +84,19 @@ namespace FancyZonesEditor
} }
} }
foreach (Rect singleMonitor in Settings.UsedWorkAreas)
{
int monitorPositionLow = (int)(isX ? singleMonitor.Left : singleMonitor.Top);
int monitorPositionHigh = (int)(isX ? singleMonitor.Right : singleMonitor.Bottom);
keyPositions.Add(monitorPositionLow - screenAxisOrigin);
keyPositions.Add(monitorPositionHigh - screenAxisOrigin);
if (mode == ResizeMode.BothEdges)
{
keyPositions.Add(monitorPositionLow - screenAxisOrigin - zoneAxisSize);
keyPositions.Add(monitorPositionHigh - screenAxisOrigin - zoneAxisSize);
}
}
// Remove duplicates and sort // Remove duplicates and sort
keyPositions.Sort(); keyPositions.Sort();
Snaps = new List<int>(); Snaps = new List<int>();
@ -143,8 +157,8 @@ namespace FancyZonesEditor
get => (int)(0.08 * ScreenW); get => (int)(0.08 * ScreenW);
} }
public SnappyHelperMagnetic(IList<Int32Rect> zones, int zoneIndex, bool isX, ResizeMode mode, int screenAxisSize) public SnappyHelperMagnetic(IList<Int32Rect> zones, int zoneIndex, bool isX, ResizeMode mode, int screenAxisOrigin, int screenAxisSize)
: base(zones, zoneIndex, isX, mode, screenAxisSize) : base(zones, zoneIndex, isX, mode, screenAxisOrigin, screenAxisSize)
{ {
freePosition = Position; freePosition = Position;
magnetZoneSizes = new List<int>(); magnetZoneSizes = new List<int>();
@ -197,9 +211,11 @@ namespace FancyZonesEditor
private SnappyHelperBase snappyX; private SnappyHelperBase snappyX;
private SnappyHelperBase snappyY; private SnappyHelperBase snappyY;
private SnappyHelperBase NewDefaultSnappyHelper(bool isX, ResizeMode mode, int screenAxisSize) private SnappyHelperBase NewDefaultSnappyHelper(bool isX, ResizeMode mode)
{ {
return new SnappyHelperMagnetic(Model.Zones, ZoneIndex, isX, mode, screenAxisSize); int screenAxisOrigin = (int)(isX ? Settings.WorkArea.Left : Settings.WorkArea.Top);
int screenAxisSize = (int)(isX ? Settings.WorkArea.Width : Settings.WorkArea.Height);
return new SnappyHelperMagnetic(Model.Zones, ZoneIndex, isX, mode, screenAxisOrigin, screenAxisSize);
} }
private void UpdateFromSnappyHelpers() private void UpdateFromSnappyHelpers()
@ -287,8 +303,8 @@ namespace FancyZonesEditor
// Corner dragging // Corner dragging
private void Caption_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e) private void Caption_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{ {
snappyX = NewDefaultSnappyHelper(true, ResizeMode.BothEdges, (int)Settings.WorkArea.Width); snappyX = NewDefaultSnappyHelper(true, ResizeMode.BothEdges);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.BothEdges, (int)Settings.WorkArea.Height); snappyY = NewDefaultSnappyHelper(false, ResizeMode.BothEdges);
} }
public CanvasLayoutModel Model { get => model; set => model = value; } public CanvasLayoutModel Model { get => model; set => model = value; }
@ -297,50 +313,50 @@ namespace FancyZonesEditor
private void NWResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e) private void NWResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{ {
snappyX = NewDefaultSnappyHelper(true, ResizeMode.BottomEdge, (int)Settings.WorkArea.Width); snappyX = NewDefaultSnappyHelper(true, ResizeMode.BottomEdge);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.BottomEdge, (int)Settings.WorkArea.Height); snappyY = NewDefaultSnappyHelper(false, ResizeMode.BottomEdge);
} }
private void NEResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e) private void NEResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{ {
snappyX = NewDefaultSnappyHelper(true, ResizeMode.TopEdge, (int)Settings.WorkArea.Width); snappyX = NewDefaultSnappyHelper(true, ResizeMode.TopEdge);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.BottomEdge, (int)Settings.WorkArea.Height); snappyY = NewDefaultSnappyHelper(false, ResizeMode.BottomEdge);
} }
private void SWResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e) private void SWResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{ {
snappyX = NewDefaultSnappyHelper(true, ResizeMode.BottomEdge, (int)Settings.WorkArea.Width); snappyX = NewDefaultSnappyHelper(true, ResizeMode.BottomEdge);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.TopEdge, (int)Settings.WorkArea.Height); snappyY = NewDefaultSnappyHelper(false, ResizeMode.TopEdge);
} }
private void SEResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e) private void SEResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{ {
snappyX = NewDefaultSnappyHelper(true, ResizeMode.TopEdge, (int)Settings.WorkArea.Width); snappyX = NewDefaultSnappyHelper(true, ResizeMode.TopEdge);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.TopEdge, (int)Settings.WorkArea.Height); snappyY = NewDefaultSnappyHelper(false, ResizeMode.TopEdge);
} }
// Edge dragging // Edge dragging
private void NResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e) private void NResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{ {
snappyX = null; snappyX = null;
snappyY = NewDefaultSnappyHelper(false, ResizeMode.BottomEdge, (int)Settings.WorkArea.Height); snappyY = NewDefaultSnappyHelper(false, ResizeMode.BottomEdge);
} }
private void SResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e) private void SResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{ {
snappyX = null; snappyX = null;
snappyY = NewDefaultSnappyHelper(false, ResizeMode.TopEdge, (int)Settings.WorkArea.Height); snappyY = NewDefaultSnappyHelper(false, ResizeMode.TopEdge);
} }
private void WResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e) private void WResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{ {
snappyX = NewDefaultSnappyHelper(true, ResizeMode.BottomEdge, (int)Settings.WorkArea.Width); snappyX = NewDefaultSnappyHelper(true, ResizeMode.BottomEdge);
snappyY = null; snappyY = null;
} }
private void EResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e) private void EResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{ {
snappyX = NewDefaultSnappyHelper(true, ResizeMode.TopEdge, (int)Settings.WorkArea.Width); snappyX = NewDefaultSnappyHelper(true, ResizeMode.TopEdge);
snappyY = null; snappyY = null;
} }
} }

View File

@ -259,6 +259,8 @@ namespace FancyZonesEditor
public static Rect WorkArea { get; private set; } public static Rect WorkArea { get; private set; }
public static List<Rect> UsedWorkAreas { get; private set; }
public static string UniqueKey { get; private set; } public static string UniqueKey { get; private set; }
public static string ActiveZoneSetUUid { get; private set; } public static string ActiveZoneSetUUid { get; private set; }
@ -453,6 +455,7 @@ namespace FancyZonesEditor
private void ParseCommandLineArgs() private void ParseCommandLineArgs()
{ {
WorkArea = SystemParameters.WorkArea; WorkArea = SystemParameters.WorkArea;
UsedWorkAreas = new List<Rect> { WorkArea };
string[] args = Environment.GetCommandLineArgs(); string[] args = Environment.GetCommandLineArgs();
@ -470,7 +473,10 @@ namespace FancyZonesEditor
} }
else if (args.Length == 3) else if (args.Length == 3)
{ {
var parsedLocation = args[(int)CmdArgs.WorkAreaSize].Split('_'); UsedWorkAreas.Clear();
foreach (var singleMonitorString in args[(int)CmdArgs.WorkAreaSize].Split('/'))
{
var parsedLocation = singleMonitorString.Split('_');
if (parsedLocation.Length != 4) if (parsedLocation.Length != 4)
{ {
MessageBox.Show(ErrorInvalidArgs, ErrorMessageBoxTitle); MessageBox.Show(ErrorInvalidArgs, ErrorMessageBoxTitle);
@ -482,7 +488,18 @@ namespace FancyZonesEditor
var width = int.Parse(parsedLocation[(int)WorkAreaCmdArgElements.Width]); var width = int.Parse(parsedLocation[(int)WorkAreaCmdArgElements.Width]);
var height = int.Parse(parsedLocation[(int)WorkAreaCmdArgElements.Height]); var height = int.Parse(parsedLocation[(int)WorkAreaCmdArgElements.Height]);
WorkArea = new Rect(x, y, width, height); Rect thisMonitor = new Rect(x, y, width, height);
if (UsedWorkAreas.Count == 0)
{
WorkArea = thisMonitor;
}
else
{
WorkArea = Rect.Union(WorkArea, thisMonitor);
}
UsedWorkAreas.Add(thisMonitor);
}
int.TryParse(args[(int)CmdArgs.PowerToysPID], out _powerToysPID); int.TryParse(args[(int)CmdArgs.PowerToysPID], out _powerToysPID);
ParseDeviceInfoData(); ParseDeviceInfoData();

View File

@ -76,12 +76,20 @@ public:
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept
{ {
std::unique_lock writeLock(m_lock); std::unique_lock writeLock(m_lock);
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
monitor = NULL;
}
m_windowMoveHandler.MoveSizeStart(window, monitor, ptScreen, m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId)); m_windowMoveHandler.MoveSizeStart(window, monitor, ptScreen, m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId));
} }
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept
{ {
std::unique_lock writeLock(m_lock); std::unique_lock writeLock(m_lock);
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
monitor = NULL;
}
m_windowMoveHandler.MoveSizeUpdate(monitor, ptScreen, m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId)); m_windowMoveHandler.MoveSizeUpdate(monitor, ptScreen, m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId));
} }
@ -623,32 +631,76 @@ void FancyZones::ToggleEditor() noexcept
return; return;
} }
winrt::com_ptr<IZoneWindow> zoneWindow;
std::shared_lock readLock(m_lock); std::shared_lock readLock(m_lock);
auto zoneWindow = m_workAreaHandler.GetWorkArea(m_currentDesktopId, monitor);
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
zoneWindow = m_workAreaHandler.GetWorkArea(m_currentDesktopId, NULL);
}
else
{
zoneWindow = m_workAreaHandler.GetWorkArea(m_currentDesktopId, monitor);
}
if (!zoneWindow) if (!zoneWindow)
{ {
return; return;
} }
std::wstring editorLocation;
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
std::vector<std::pair<HMONITOR, RECT>> allMonitors;
m_dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] {
allMonitors = GetAllMonitorRects<&MONITORINFOEX::rcWork>();
} }).wait();
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; MONITORINFOEX mi;
mi.cbSize = sizeof(mi); mi.cbSize = sizeof(mi);
m_dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] { m_dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] {
GetMonitorInfo(monitor, &mi); GetMonitorInfo(monitor, &mi);
} }) } }).wait();
.wait();
const auto taskbar_x_offset = mi.rcWork.left - mi.rcMonitor.left; const auto x = mi.rcWork.left;
const auto taskbar_y_offset = mi.rcWork.top - mi.rcMonitor.top; const auto y = mi.rcWork.top;
const auto x = mi.rcMonitor.left + taskbar_x_offset;
const auto y = mi.rcMonitor.top + taskbar_y_offset;
const auto width = mi.rcWork.right - mi.rcWork.left; const auto width = mi.rcWork.right - mi.rcWork.left;
const auto height = mi.rcWork.bottom - mi.rcWork.top; const auto height = mi.rcWork.bottom - mi.rcWork.top;
const std::wstring editorLocation = editorLocation =
std::to_wstring(x) + L"_" + std::to_wstring(x) + L"_" +
std::to_wstring(y) + L"_" + std::to_wstring(y) + L"_" +
std::to_wstring(width) + L"_" + std::to_wstring(width) + L"_" +
std::to_wstring(height); std::to_wstring(height);
}
const auto& fancyZonesData = FancyZonesDataInstance(); const auto& fancyZonesData = FancyZonesDataInstance();
@ -696,10 +748,13 @@ void FancyZones::ToggleEditor() noexcept
void FancyZones::SettingsChanged() noexcept void FancyZones::SettingsChanged() noexcept
{ {
std::shared_lock readLock(m_lock);
// Update the hotkey // Update the hotkey
UnregisterHotKey(m_window, 1); UnregisterHotKey(m_window, 1);
RegisterHotKey(m_window, 1, m_settings->GetSettings()->editorHotkey.get_modifiers(), m_settings->GetSettings()->editorHotkey.get_code()); RegisterHotKey(m_window, 1, m_settings->GetSettings()->editorHotkey.get_modifiers(), m_settings->GetSettings()->editorHotkey.get_code());
// Needed if we toggled spanZonesAcrossMonitors
m_workAreaHandler.Clear();
OnDisplayChange(DisplayChangeType::Initialization);
} }
// IZoneWindowHost // IZoneWindowHost
@ -864,7 +919,16 @@ void FancyZones::AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept
wil::unique_cotaskmem_string virtualDesktopId; wil::unique_cotaskmem_string virtualDesktopId;
if (SUCCEEDED(StringFromCLSID(m_currentDesktopId, &virtualDesktopId))) if (SUCCEEDED(StringFromCLSID(m_currentDesktopId, &virtualDesktopId)))
{ {
std::wstring uniqueId = ZoneWindowUtils::GenerateUniqueId(monitor, deviceId, virtualDesktopId.get()); std::wstring uniqueId;
if (monitor)
{
uniqueId = ZoneWindowUtils::GenerateUniqueId(monitor, deviceId, virtualDesktopId.get());
}
else
{
uniqueId = ZoneWindowUtils::GenerateUniqueIdAllMonitorsArea(virtualDesktopId.get());
}
// "Turning FLASHING_ZONE option off" // "Turning FLASHING_ZONE option off"
//const bool flash = m_settings->GetSettings()->zoneSetChange_flashZones; //const bool flash = m_settings->GetSettings()->zoneSetChange_flashZones;
@ -939,8 +1003,15 @@ void FancyZones::UpdateZoneWindows() noexcept
return TRUE; return TRUE;
}; };
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
AddZoneWindow(nullptr, NULL);
}
else
{
EnumDisplayMonitors(nullptr, nullptr, callback, reinterpret_cast<LPARAM>(this)); EnumDisplayMonitors(nullptr, nullptr, callback, reinterpret_cast<LPARAM>(this));
} }
}
void FancyZones::UpdateWindowsPositions() noexcept void FancyZones::UpdateWindowsPositions() noexcept
{ {
@ -995,11 +1066,19 @@ bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept
auto window = GetForegroundWindow(); auto window = GetForegroundWindow();
if (IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray)) if (IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray))
{ {
const HMONITOR current = MonitorFromWindow(window, MONITOR_DEFAULTTONULL); HMONITOR current;
if (current)
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{ {
current = NULL;
}
else
{
current = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
}
std::vector<HMONITOR> monitorInfo = GetMonitorsSorted(); std::vector<HMONITOR> monitorInfo = GetMonitorsSorted();
if (monitorInfo.size() > 1 && m_settings->GetSettings()->moveWindowAcrossMonitors) if (current && monitorInfo.size() > 1 && m_settings->GetSettings()->moveWindowAcrossMonitors)
{ {
// Multi monitor environment. // Multi monitor environment.
auto currMonitorInfo = std::find(std::begin(monitorInfo), std::end(monitorInfo), current); auto currMonitorInfo = std::find(std::begin(monitorInfo), std::end(monitorInfo), current);
@ -1031,7 +1110,7 @@ bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept
} }
else else
{ {
// Single monitor environment. // Single monitor environment, or combined multi-monitor environment.
std::unique_lock writeLock(m_lock); std::unique_lock writeLock(m_lock);
if (m_settings->GetSettings()->restoreSize) if (m_settings->GetSettings()->restoreSize)
{ {
@ -1049,7 +1128,6 @@ bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept
} }
} }
} }
}
return false; return false;
} }
@ -1096,16 +1174,22 @@ bool FancyZones::ShouldProcessSnapHotkey() noexcept
{ {
if (m_settings->GetSettings()->overrideSnapHotkeys) if (m_settings->GetSettings()->overrideSnapHotkeys)
{ {
const HMONITOR monitor = MonitorFromWindow(GetForegroundWindow(), MONITOR_DEFAULTTONULL); HMONITOR monitor;
if (monitor) if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{ {
monitor = NULL;
}
else
{
monitor = MonitorFromWindow(GetForegroundWindow(), MONITOR_DEFAULTTONULL);
}
auto zoneWindow = m_workAreaHandler.GetWorkArea(m_currentDesktopId, monitor); auto zoneWindow = m_workAreaHandler.GetWorkArea(m_currentDesktopId, monitor);
if (zoneWindow->ActiveZoneSet() != nullptr) if (zoneWindow->ActiveZoneSet() != nullptr)
{ {
return true; return true;
} }
} }
}
return false; return false;
} }

View File

@ -19,12 +19,23 @@ winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkArea(const GUID& desk
winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkArea(HWND window) winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkArea(HWND window)
{ {
HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
GUID desktopId{}; GUID desktopId{};
if (monitor && VirtualDesktopUtils::GetWindowDesktopId(window, &desktopId)) if (VirtualDesktopUtils::GetWindowDesktopId(window, &desktopId))
{ {
auto allMonitorsWorkArea = GetWorkArea(desktopId, NULL);
if (allMonitorsWorkArea)
{
// First, check if there's a work area spanning all monitors (signalled by the NULL monitor handle)
return allMonitorsWorkArea;
}
else
{
// Otherwise, look for the work area based on the window's position
HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
return GetWorkArea(desktopId, monitor); return GetWorkArea(desktopId, monitor);
} }
}
return nullptr; return nullptr;
} }

View File

@ -36,7 +36,7 @@ private:
PCWSTR name; PCWSTR name;
bool* value; bool* value;
int resourceId; int resourceId;
} m_configBools[12 /* 13 */] = { // "Turning FLASHING_ZONE option off" } m_configBools[13 /* 14 */] = { // "Turning FLASHING_ZONE option off"
{ L"fancyzones_shiftDrag", &m_settings.shiftDrag, IDS_SETTING_DESCRIPTION_SHIFTDRAG }, { L"fancyzones_shiftDrag", &m_settings.shiftDrag, IDS_SETTING_DESCRIPTION_SHIFTDRAG },
{ L"fancyzones_mouseSwitch", &m_settings.mouseSwitch, IDS_SETTING_DESCRIPTION_MOUSESWITCH }, { L"fancyzones_mouseSwitch", &m_settings.mouseSwitch, IDS_SETTING_DESCRIPTION_MOUSESWITCH },
{ L"fancyzones_overrideSnapHotkeys", &m_settings.overrideSnapHotkeys, IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS }, { L"fancyzones_overrideSnapHotkeys", &m_settings.overrideSnapHotkeys, IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS },
@ -50,6 +50,7 @@ private:
{ L"fancyzones_restoreSize", &m_settings.restoreSize, IDS_SETTING_DESCRIPTION_RESTORESIZE }, { L"fancyzones_restoreSize", &m_settings.restoreSize, IDS_SETTING_DESCRIPTION_RESTORESIZE },
{ L"use_cursorpos_editor_startupscreen", &m_settings.use_cursorpos_editor_startupscreen, IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN }, { L"use_cursorpos_editor_startupscreen", &m_settings.use_cursorpos_editor_startupscreen, IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN },
{ L"fancyzones_show_on_all_monitors", &m_settings.showZonesOnAllMonitors, IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS }, { L"fancyzones_show_on_all_monitors", &m_settings.showZonesOnAllMonitors, IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS },
{ L"fancyzones_span_zones_across_monitors", &m_settings.spanZonesAcrossMonitors, IDS_SETTING_DESCRIPTION_SPAN_ZONES_ACROSS_MONITORS },
{ L"fancyzones_makeDraggedWindowTransparent", &m_settings.makeDraggedWindowTransparent, IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT }, { L"fancyzones_makeDraggedWindowTransparent", &m_settings.makeDraggedWindowTransparent, IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT },
}; };

View File

@ -3,6 +3,7 @@
#define MULTI_ZONE_STAMP L"FancyZones_zones" #define MULTI_ZONE_STAMP L"FancyZones_zones"
#define RESTORE_SIZE_STAMP L"FancyZones_RestoreSize" #define RESTORE_SIZE_STAMP L"FancyZones_RestoreSize"
#define RESTORE_ORIGIN_STAMP L"FancyZones_RestoreOrigin" #define RESTORE_ORIGIN_STAMP L"FancyZones_RestoreOrigin"
#define MULTI_MONITOR_MODE_DEVICE L"FancyZonesMultiMonitorDevice"
#include <common/settings_objects.h> #include <common/settings_objects.h>
struct Settings struct Settings
@ -20,6 +21,7 @@ struct Settings
bool restoreSize = false; bool restoreSize = false;
bool use_cursorpos_editor_startupscreen = true; bool use_cursorpos_editor_startupscreen = true;
bool showZonesOnAllMonitors = false; bool showZonesOnAllMonitors = false;
bool spanZonesAcrossMonitors = false;
bool makeDraggedWindowTransparent = true; bool makeDraggedWindowTransparent = true;
std::wstring zoneColor = L"#F5FCFF"; std::wstring zoneColor = L"#F5FCFF";
std::wstring zoneBorderColor = L"#FFFFFF"; std::wstring zoneBorderColor = L"#FFFFFF";

View File

@ -142,7 +142,7 @@ public:
IFACEMETHODIMP_(void) IFACEMETHODIMP_(void)
MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient) noexcept; MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient) noexcept;
IFACEMETHODIMP_(bool) IFACEMETHODIMP_(bool)
CalculateZones(MONITORINFO monitorInfo, int zoneCount, int spacing) noexcept; CalculateZones(RECT workArea, int zoneCount, int spacing) noexcept;
IFACEMETHODIMP_(bool) IFACEMETHODIMP_(bool)
IsZoneEmpty(int zoneIndex) noexcept; IsZoneEmpty(int zoneIndex) noexcept;
@ -369,9 +369,9 @@ ZoneSet::MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient)
} }
IFACEMETHODIMP_(bool) IFACEMETHODIMP_(bool)
ZoneSet::CalculateZones(MONITORINFO monitorInfo, int zoneCount, int spacing) noexcept ZoneSet::CalculateZones(RECT workAreaRect, int zoneCount, int spacing) noexcept
{ {
Rect const workArea(monitorInfo.rcWork); Rect workArea(workAreaRect);
//invalid work area //invalid work area
if (workArea.width() == 0 || workArea.height() == 0) if (workArea.width() == 0 || workArea.height() == 0)
{ {

View File

@ -89,13 +89,13 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
* Calculate zone coordinates within zone layout based on number of zones and spacing. Used for one of * Calculate zone coordinates within zone layout based on number of zones and spacing. Used for one of
* the predefined layouts (focus, columns, rows, grid, priority grid) or for custom layout. * the predefined layouts (focus, columns, rows, grid, priority grid) or for custom layout.
* *
* @param monitorInfo Information about monitor on which zone layout is applied. * @param workAreaRect The rectangular area on the screen on which the zone layout is applied.
* @param zoneCount Number of zones inside zone layout. * @param zoneCount Number of zones inside zone layout.
* @param spacing Spacing between zones in pixels. * @param spacing Spacing between zones in pixels.
* *
* @returns Boolean indicating if calculation was successful. * @returns Boolean indicating if calculation was successful.
*/ */
IFACEMETHOD_(bool, CalculateZones)(MONITORINFO monitorInfo, int zoneCount, int spacing) = 0; IFACEMETHOD_(bool, CalculateZones)(RECT workAreaRect, int zoneCount, int spacing) = 0;
/** /**
* Check if the zone with the specified index is empty. Returns true if the zone does not exist. * Check if the zone with the specified index is empty. Returns true if the zone does not exist.
* *

View File

@ -7,6 +7,7 @@
#include "ZoneWindow.h" #include "ZoneWindow.h"
#include "trace.h" #include "trace.h"
#include "util.h" #include "util.h"
#include "Settings.h"
#include <ShellScalingApi.h> #include <ShellScalingApi.h>
#include <mutex> #include <mutex>
@ -32,6 +33,22 @@ namespace ZoneWindowUtils
} }
return std::wstring{ uniqueId }; return std::wstring{ uniqueId };
} }
std::wstring GenerateUniqueIdAllMonitorsArea(PCWSTR virtualDesktopId)
{
std::wstring result{ MULTI_MONITOR_MODE_DEVICE };
RECT combinedResolution = GetAllMonitorsCombinedRect<&MONITORINFO::rcMonitor>();
result += L'_';
result += std::to_wstring(combinedResolution.right - combinedResolution.left);
result += L'_';
result += std::to_wstring(combinedResolution.bottom - combinedResolution.top);
result += L'_';
result += virtualDesktopId;
return result;
}
} }
namespace ZoneWindowDrawUtils namespace ZoneWindowDrawUtils
@ -253,16 +270,23 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit
{ {
m_host.copy_from(host); m_host.copy_from(host);
Rect workAreaRect;
m_monitor = monitor;
if (monitor)
{
MONITORINFO mi{}; MONITORINFO mi{};
mi.cbSize = sizeof(mi); mi.cbSize = sizeof(mi);
if (!GetMonitorInfoW(monitor, &mi)) if (!GetMonitorInfoW(monitor, &mi))
{ {
return false; return false;
} }
m_monitor = monitor;
const UINT dpi = GetDpiForMonitor(m_monitor); const UINT dpi = GetDpiForMonitor(m_monitor);
const Rect workAreaRect(mi.rcWork, dpi); workAreaRect = Rect(mi.rcWork, dpi);
}
else
{
workAreaRect = GetAllMonitorsCombinedRect<&MONITORINFO::rcWork>();
}
m_uniqueId = uniqueId; m_uniqueId = uniqueId;
InitializeZoneSets(parentUniqueId); InitializeZoneSets(parentUniqueId);
@ -277,6 +301,9 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit
} }
MakeWindowTransparent(m_window.get()); MakeWindowTransparent(m_window.get());
// Ignore flashZones
/*
if (flashZones) if (flashZones)
{ {
// Don't flash if the foreground window is in full screen mode // Don't flash if the foreground window is in full screen mode
@ -290,6 +317,7 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit
FlashZones(); FlashZones();
} }
} }
*/
return true; return true;
} }
@ -566,18 +594,33 @@ void ZoneWindow::CalculateZoneSet() noexcept
zoneSetId, zoneSetId,
activeZoneSet.type, activeZoneSet.type,
m_monitor)); m_monitor));
RECT workArea;
if (m_monitor)
{
MONITORINFO monitorInfo{}; MONITORINFO monitorInfo{};
monitorInfo.cbSize = sizeof(monitorInfo); monitorInfo.cbSize = sizeof(monitorInfo);
if (GetMonitorInfoW(m_monitor, &monitorInfo)) if (GetMonitorInfoW(m_monitor, &monitorInfo))
{ {
workArea = monitorInfo.rcWork;
}
else
{
return;
}
}
else
{
workArea = GetAllMonitorsCombinedRect<&MONITORINFO::rcWork>();
}
bool showSpacing = deviceInfoData->showSpacing; bool showSpacing = deviceInfoData->showSpacing;
int spacing = showSpacing ? deviceInfoData->spacing : 0; int spacing = showSpacing ? deviceInfoData->spacing : 0;
int zoneCount = deviceInfoData->zoneCount; int zoneCount = deviceInfoData->zoneCount;
zoneSet->CalculateZones(monitorInfo, zoneCount, spacing); zoneSet->CalculateZones(workArea, zoneCount, spacing);
UpdateActiveZoneSet(zoneSet.get()); UpdateActiveZoneSet(zoneSet.get());
} }
} }
}
void ZoneWindow::UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept void ZoneWindow::UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept
{ {

View File

@ -5,6 +5,7 @@
namespace ZoneWindowUtils namespace ZoneWindowUtils
{ {
std::wstring GenerateUniqueId(HMONITOR monitor, PCWSTR deviceId, PCWSTR virtualDesktopId); std::wstring GenerateUniqueId(HMONITOR monitor, PCWSTR deviceId, PCWSTR virtualDesktopId);
std::wstring GenerateUniqueIdAllMonitorsArea(PCWSTR virtualDesktopId);
} }
/** /**

View File

@ -13,6 +13,7 @@ BEGIN
IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS "During zone layout changes, windows assigned to a zone will match new size/positions" IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS "During zone layout changes, windows assigned to a zone will match new size/positions"
IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES "Flash zones when the active FancyZones layout changes" IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES "Flash zones when the active FancyZones layout changes"
IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS "Show zones on all monitors while dragging a window" IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS "Show zones on all monitors while dragging a window"
IDS_SETTING_DESCRIPTION_SPAN_ZONES_ACROSS_MONITORS "Allow zones to span across monitors"
IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT "Make dragged window transparent" IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT "Make dragged window transparent"
IDS_SETTING_DESCRIPTION_ZONECOLOR "Zone inactive color (Default #F5FCFF)" IDS_SETTING_DESCRIPTION_ZONECOLOR "Zone inactive color (Default #F5FCFF)"
IDS_SETTING_DESCRIPTION_ZONE_BORDER_COLOR "Zone border color (Default #FFFFFF)" IDS_SETTING_DESCRIPTION_ZONE_BORDER_COLOR "Zone border color (Default #FFFFFF)"

View File

@ -20,22 +20,23 @@
#define IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS 106 #define IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS 106
#define IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES 107 #define IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES 107
#define IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS 108 #define IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS 108
#define IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT 109 #define IDS_SETTING_DESCRIPTION_SPAN_ZONES_ACROSS_MONITORS 109
#define IDS_SETTING_DESCRIPTION_ZONECOLOR 110 #define IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT 110
#define IDS_SETTING_DESCRIPTION_ZONE_BORDER_COLOR 111 #define IDS_SETTING_DESCRIPTION_ZONECOLOR 111
#define IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR 112 #define IDS_SETTING_DESCRIPTION_ZONE_BORDER_COLOR 112
#define IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS 113 #define IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR 113
#define IDS_SETTING_DESCRIPTION_OPEN_WINDOW_ON_ACTIVE_MONITOR 114 #define IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS 114
#define IDS_SETTING_DESCRIPTION_RESTORESIZE 115 #define IDS_SETTING_DESCRIPTION_OPEN_WINDOW_ON_ACTIVE_MONITOR 115
#define IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN 116 #define IDS_SETTING_DESCRIPTION_RESTORESIZE 116
#define IDS_SETTING_DESCRIPTION 117 #define IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN 117
#define IDS_SETTING_LAUNCH_EDITOR_LABEL 118 #define IDS_SETTING_DESCRIPTION 118
#define IDS_SETTING_LAUNCH_EDITOR_BUTTON 119 #define IDS_SETTING_LAUNCH_EDITOR_LABEL 119
#define IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION 120 #define IDS_SETTING_LAUNCH_EDITOR_BUTTON 120
#define IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL 121 #define IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION 121
#define IDS_SETTING_EXCLUDED_APPS_DESCRIPTION 122 #define IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL 122
#define IDS_SETTINGS_HIGHLIGHT_OPACITY 123 #define IDS_SETTING_EXCLUDED_APPS_DESCRIPTION 123
#define IDS_FANCYZONES 124 #define IDS_SETTINGS_HIGHLIGHT_OPACITY 124
#define IDS_CANT_DRAG_ELEVATED 125 #define IDS_FANCYZONES 125
#define IDS_CANT_DRAG_ELEVATED_LEARN_MORE 126 #define IDS_CANT_DRAG_ELEVATED 126
#define IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN 127 #define IDS_CANT_DRAG_ELEVATED_LEARN_MORE 127
#define IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN 128

View File

@ -189,6 +189,7 @@ void Trace::SettingsChanged(const Settings& settings) noexcept
TraceLoggingBoolean(settings.restoreSize, "RestoreSize"), TraceLoggingBoolean(settings.restoreSize, "RestoreSize"),
TraceLoggingBoolean(settings.use_cursorpos_editor_startupscreen, "UseCursorPosOnEditorStartup"), TraceLoggingBoolean(settings.use_cursorpos_editor_startupscreen, "UseCursorPosOnEditorStartup"),
TraceLoggingBoolean(settings.showZonesOnAllMonitors, "ShowZonesOnAllMonitors"), TraceLoggingBoolean(settings.showZonesOnAllMonitors, "ShowZonesOnAllMonitors"),
TraceLoggingBoolean(settings.spanZonesAcrossMonitors, "SpanZonesAcrossMonitors"),
TraceLoggingBoolean(settings.makeDraggedWindowTransparent, "MakeDraggedWindowTransparent"), TraceLoggingBoolean(settings.makeDraggedWindowTransparent, "MakeDraggedWindowTransparent"),
TraceLoggingWideString(settings.zoneColor.c_str(), "ZoneColor"), TraceLoggingWideString(settings.zoneColor.c_str(), "ZoneColor"),
TraceLoggingWideString(settings.zoneBorderColor.c_str(), "ZoneBorderColor"), TraceLoggingWideString(settings.zoneBorderColor.c_str(), "ZoneBorderColor"),

View File

@ -116,6 +116,55 @@ inline BYTE OpacitySettingToAlpha(int opacity)
return static_cast<BYTE>(opacity * 2.55); return static_cast<BYTE>(opacity * 2.55);
} }
template<RECT MONITORINFO::*member>
std::vector<std::pair<HMONITOR, RECT>> GetAllMonitorRects()
{
using result_t = std::vector<std::pair<HMONITOR, RECT>>;
result_t result;
auto enumMonitors = [](HMONITOR monitor, HDC hdc, LPRECT pRect, LPARAM param) -> BOOL
{
MONITORINFOEX mi;
mi.cbSize = sizeof(mi);
result_t& result = *reinterpret_cast<result_t*>(param);
if (GetMonitorInfo(monitor, &mi))
{
result.push_back({ monitor, mi.*member });
}
return TRUE;
};
EnumDisplayMonitors(NULL, NULL, enumMonitors, reinterpret_cast<LPARAM>(&result));
return result;
}
template<RECT MONITORINFO::*member>
RECT GetAllMonitorsCombinedRect()
{
auto allMonitors = GetAllMonitorRects<member>();
bool empty = true;
RECT result{ 0, 0, 0, 0 };
for (auto& [monitor, rect] : allMonitors)
{
if (empty)
{
empty = false;
result = rect;
}
else
{
result.left = min(result.left, rect.left);
result.top = min(result.top, rect.top);
result.right = max(result.right, rect.right);
result.bottom = max(result.bottom, rect.bottom);
}
}
return result;
}
UINT GetDpiForMonitor(HMONITOR monitor) noexcept; UINT GetDpiForMonitor(HMONITOR monitor) noexcept;
void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo); void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo);
void SizeWindowToRect(HWND window, RECT rect) noexcept; void SizeWindowToRect(HWND window, RECT rect) noexcept;

View File

@ -77,6 +77,7 @@ namespace FancyZonesUnitTests
ptSettings.add_bool_toggle(L"fancyzones_restoreSize", IDS_SETTING_DESCRIPTION_RESTORESIZE, settings.restoreSize); ptSettings.add_bool_toggle(L"fancyzones_restoreSize", IDS_SETTING_DESCRIPTION_RESTORESIZE, settings.restoreSize);
ptSettings.add_bool_toggle(L"use_cursorpos_editor_startupscreen", IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN, settings.use_cursorpos_editor_startupscreen); ptSettings.add_bool_toggle(L"use_cursorpos_editor_startupscreen", IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN, settings.use_cursorpos_editor_startupscreen);
ptSettings.add_bool_toggle(L"fancyzones_show_on_all_monitors", IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS, settings.showZonesOnAllMonitors); ptSettings.add_bool_toggle(L"fancyzones_show_on_all_monitors", IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS, settings.showZonesOnAllMonitors);
ptSettings.add_bool_toggle(L"fancyzones_multi_monitor_mode", IDS_SETTING_DESCRIPTION_SPAN_ZONES_ACROSS_MONITORS, settings.spanZonesAcrossMonitors);
ptSettings.add_bool_toggle(L"fancyzones_makeDraggedWindowTransparent", IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT, settings.makeDraggedWindowTransparent); ptSettings.add_bool_toggle(L"fancyzones_makeDraggedWindowTransparent", IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT, settings.makeDraggedWindowTransparent);
ptSettings.add_int_spinner(L"fancyzones_highlight_opacity", IDS_SETTINGS_HIGHLIGHT_OPACITY, settings.zoneHighlightOpacity, 0, 100, 1); ptSettings.add_int_spinner(L"fancyzones_highlight_opacity", IDS_SETTINGS_HIGHLIGHT_OPACITY, settings.zoneHighlightOpacity, 0, 100, 1);
ptSettings.add_color_picker(L"fancyzones_zoneColor", IDS_SETTING_DESCRIPTION_ZONECOLOR, settings.zoneColor); ptSettings.add_color_picker(L"fancyzones_zoneColor", IDS_SETTING_DESCRIPTION_ZONECOLOR, settings.zoneColor);
@ -122,6 +123,7 @@ namespace FancyZonesUnitTests
.appLastZone_moveWindows = true, .appLastZone_moveWindows = true,
.restoreSize = false, .restoreSize = false,
.use_cursorpos_editor_startupscreen = true, .use_cursorpos_editor_startupscreen = true,
.spanZonesAcrossMonitors = false,
.zoneColor = L"#abafee", .zoneColor = L"#abafee",
.zoneBorderColor = L"FAFAFA", .zoneBorderColor = L"FAFAFA",
.zoneHighlightColor = L"#FAFAFA", .zoneHighlightColor = L"#FAFAFA",
@ -152,6 +154,7 @@ namespace FancyZonesUnitTests
.appLastZone_moveWindows = true, .appLastZone_moveWindows = true,
.restoreSize = false, .restoreSize = false,
.use_cursorpos_editor_startupscreen = true, .use_cursorpos_editor_startupscreen = true,
.spanZonesAcrossMonitors = false,
.zoneColor = L"#FAFAFA", .zoneColor = L"#FAFAFA",
.zoneBorderColor = L"#abafee", .zoneBorderColor = L"#abafee",
.zoneHighlightColor = L"#FAFAFA", .zoneHighlightColor = L"#FAFAFA",
@ -183,6 +186,7 @@ namespace FancyZonesUnitTests
.restoreSize = false, .restoreSize = false,
.use_cursorpos_editor_startupscreen = true, .use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false, .showZonesOnAllMonitors = false,
.spanZonesAcrossMonitors = false,
.makeDraggedWindowTransparent = true, .makeDraggedWindowTransparent = true,
.zoneColor = L"#FAFAFA", .zoneColor = L"#FAFAFA",
.zoneBorderColor = L"FAFAFA", .zoneBorderColor = L"FAFAFA",
@ -215,6 +219,7 @@ namespace FancyZonesUnitTests
.restoreSize = false, .restoreSize = false,
.use_cursorpos_editor_startupscreen = true, .use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false, .showZonesOnAllMonitors = false,
.spanZonesAcrossMonitors = false,
.makeDraggedWindowTransparent = true, .makeDraggedWindowTransparent = true,
.zoneColor = L"#FAFAFA", .zoneColor = L"#FAFAFA",
.zoneBorderColor = L"FAFAFA", .zoneBorderColor = L"FAFAFA",
@ -247,6 +252,7 @@ namespace FancyZonesUnitTests
.restoreSize = false, .restoreSize = false,
.use_cursorpos_editor_startupscreen = true, .use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false, .showZonesOnAllMonitors = false,
.spanZonesAcrossMonitors = false,
.makeDraggedWindowTransparent = true, .makeDraggedWindowTransparent = true,
.zoneColor = L"#FAFAFA", .zoneColor = L"#FAFAFA",
.zoneBorderColor = L"FAFAFA", .zoneBorderColor = L"FAFAFA",
@ -289,6 +295,7 @@ namespace FancyZonesUnitTests
ptSettings.add_bool_toggle(L"fancyzones_restoreSize", IDS_SETTING_DESCRIPTION_RESTORESIZE, settings.restoreSize); ptSettings.add_bool_toggle(L"fancyzones_restoreSize", IDS_SETTING_DESCRIPTION_RESTORESIZE, settings.restoreSize);
ptSettings.add_bool_toggle(L"use_cursorpos_editor_startupscreen", IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN, settings.use_cursorpos_editor_startupscreen); ptSettings.add_bool_toggle(L"use_cursorpos_editor_startupscreen", IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN, settings.use_cursorpos_editor_startupscreen);
ptSettings.add_bool_toggle(L"fancyzones_show_on_all_monitors", IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS, settings.showZonesOnAllMonitors); ptSettings.add_bool_toggle(L"fancyzones_show_on_all_monitors", IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS, settings.showZonesOnAllMonitors);
ptSettings.add_bool_toggle(L"fancyzones_multi_monitor_mode", IDS_SETTING_DESCRIPTION_SPAN_ZONES_ACROSS_MONITORS, settings.spanZonesAcrossMonitors);
ptSettings.add_bool_toggle(L"fancyzones_makeDraggedWindowTransparent", IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT, settings.makeDraggedWindowTransparent); ptSettings.add_bool_toggle(L"fancyzones_makeDraggedWindowTransparent", IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT, settings.makeDraggedWindowTransparent);
ptSettings.add_int_spinner(L"fancyzones_highlight_opacity", IDS_SETTINGS_HIGHLIGHT_OPACITY, settings.zoneHighlightOpacity, 0, 100, 1); ptSettings.add_int_spinner(L"fancyzones_highlight_opacity", IDS_SETTINGS_HIGHLIGHT_OPACITY, settings.zoneHighlightOpacity, 0, 100, 1);
ptSettings.add_color_picker(L"fancyzones_zoneColor", IDS_SETTING_DESCRIPTION_ZONECOLOR, settings.zoneColor); ptSettings.add_color_picker(L"fancyzones_zoneColor", IDS_SETTING_DESCRIPTION_ZONECOLOR, settings.zoneColor);

View File

@ -38,6 +38,7 @@ namespace FancyZonesUnitTests
Assert::AreEqual(expected.restoreSize, actual.restoreSize); Assert::AreEqual(expected.restoreSize, actual.restoreSize);
Assert::AreEqual(expected.use_cursorpos_editor_startupscreen, actual.use_cursorpos_editor_startupscreen); Assert::AreEqual(expected.use_cursorpos_editor_startupscreen, actual.use_cursorpos_editor_startupscreen);
Assert::AreEqual(expected.showZonesOnAllMonitors, actual.showZonesOnAllMonitors); Assert::AreEqual(expected.showZonesOnAllMonitors, actual.showZonesOnAllMonitors);
Assert::AreEqual(expected.spanZonesAcrossMonitors, actual.spanZonesAcrossMonitors);
Assert::AreEqual(expected.makeDraggedWindowTransparent, actual.makeDraggedWindowTransparent); Assert::AreEqual(expected.makeDraggedWindowTransparent, actual.makeDraggedWindowTransparent);
Assert::AreEqual(expected.zoneColor.c_str(), actual.zoneColor.c_str()); Assert::AreEqual(expected.zoneColor.c_str(), actual.zoneColor.c_str());
Assert::AreEqual(expected.zoneBorderColor.c_str(), actual.zoneBorderColor.c_str()); Assert::AreEqual(expected.zoneBorderColor.c_str(), actual.zoneBorderColor.c_str());
@ -117,6 +118,7 @@ namespace FancyZonesUnitTests
values.add_property(L"fancyzones_restoreSize", expected.restoreSize); values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen); values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors); values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent); values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
values.add_property(L"fancyzones_zoneColor", expected.zoneColor); values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor); values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
@ -155,6 +157,7 @@ namespace FancyZonesUnitTests
values.add_property(L"fancyzones_restoreSize", expected.restoreSize); values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen); values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors); values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent); values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
values.add_property(L"fancyzones_zoneColor", expected.zoneColor); values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor); values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
@ -187,6 +190,7 @@ namespace FancyZonesUnitTests
.restoreSize = m_defaultSettings.restoreSize, .restoreSize = m_defaultSettings.restoreSize,
.use_cursorpos_editor_startupscreen = m_defaultSettings.use_cursorpos_editor_startupscreen, .use_cursorpos_editor_startupscreen = m_defaultSettings.use_cursorpos_editor_startupscreen,
.showZonesOnAllMonitors = m_defaultSettings.showZonesOnAllMonitors, .showZonesOnAllMonitors = m_defaultSettings.showZonesOnAllMonitors,
.spanZonesAcrossMonitors = m_defaultSettings.spanZonesAcrossMonitors,
.makeDraggedWindowTransparent = m_defaultSettings.makeDraggedWindowTransparent, .makeDraggedWindowTransparent = m_defaultSettings.makeDraggedWindowTransparent,
.zoneColor = L"FAFAFA", .zoneColor = L"FAFAFA",
.zoneBorderColor = L"CCDDEE", .zoneBorderColor = L"CCDDEE",
@ -232,6 +236,7 @@ namespace FancyZonesUnitTests
values.add_property(L"fancyzones_restoreSize", expected.restoreSize); values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen); values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors); values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent); values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
values.add_property(L"fancyzones_highlight_opacity", expected.zoneHighlightOpacity); values.add_property(L"fancyzones_highlight_opacity", expected.zoneHighlightOpacity);
values.add_property(L"fancyzones_editor_hotkey", expected.editorHotkey.get_json()); values.add_property(L"fancyzones_editor_hotkey", expected.editorHotkey.get_json());
@ -264,6 +269,7 @@ namespace FancyZonesUnitTests
values.add_property(L"fancyzones_restoreSize", expected.restoreSize); values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen); values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors); values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent); values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
values.add_property(L"fancyzones_zoneColor", expected.zoneColor); values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
values.add_property(L"fancyzones_zoneHighlightColor", expected.zoneHighlightColor); values.add_property(L"fancyzones_zoneHighlightColor", expected.zoneHighlightColor);
@ -297,6 +303,7 @@ namespace FancyZonesUnitTests
values.add_property(L"fancyzones_restoreSize", expected.restoreSize); values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen); values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors); values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent); values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
values.add_property(L"fancyzones_zoneColor", expected.zoneColor); values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor); values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
@ -331,6 +338,7 @@ namespace FancyZonesUnitTests
values.add_property(L"fancyzones_restoreSize", expected.restoreSize); values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen); values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors); values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent); values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
values.add_property(L"fancyzones_zoneColor", expected.zoneColor); values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor); values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
@ -446,6 +454,7 @@ namespace FancyZonesUnitTests
.restoreSize = false, .restoreSize = false,
.use_cursorpos_editor_startupscreen = true, .use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false, .showZonesOnAllMonitors = false,
.spanZonesAcrossMonitors = false,
.makeDraggedWindowTransparent = true, .makeDraggedWindowTransparent = true,
.zoneColor = L"FAFAFA", .zoneColor = L"FAFAFA",
.zoneBorderColor = L"CCDDEE", .zoneBorderColor = L"CCDDEE",
@ -469,6 +478,7 @@ namespace FancyZonesUnitTests
values.add_property(L"fancyzones_restoreSize", expected.restoreSize); values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen); values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors); values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent); values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
values.add_property(L"fancyzones_zoneColor", expected.zoneColor); values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor); values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
@ -587,6 +597,7 @@ namespace FancyZonesUnitTests
ptSettings.add_bool_toggle(L"fancyzones_restoreSize", IDS_SETTING_DESCRIPTION_RESTORESIZE, settings.restoreSize); ptSettings.add_bool_toggle(L"fancyzones_restoreSize", IDS_SETTING_DESCRIPTION_RESTORESIZE, settings.restoreSize);
ptSettings.add_bool_toggle(L"use_cursorpos_editor_startupscreen", IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN, settings.use_cursorpos_editor_startupscreen); ptSettings.add_bool_toggle(L"use_cursorpos_editor_startupscreen", IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN, settings.use_cursorpos_editor_startupscreen);
ptSettings.add_bool_toggle(L"fancyzones_show_on_all_monitors", IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS, settings.showZonesOnAllMonitors); ptSettings.add_bool_toggle(L"fancyzones_show_on_all_monitors", IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS, settings.showZonesOnAllMonitors);
ptSettings.add_bool_toggle(L"fancyzones_multi_monitor_mode", IDS_SETTING_DESCRIPTION_SPAN_ZONES_ACROSS_MONITORS, settings.spanZonesAcrossMonitors);
ptSettings.add_bool_toggle(L"fancyzones_makeDraggedWindowTransparent", IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT, settings.makeDraggedWindowTransparent); ptSettings.add_bool_toggle(L"fancyzones_makeDraggedWindowTransparent", IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT, settings.makeDraggedWindowTransparent);
ptSettings.add_int_spinner(L"fancyzones_highlight_opacity", IDS_SETTINGS_HIGHLIGHT_OPACITY, settings.zoneHighlightOpacity, 0, 100, 1); ptSettings.add_int_spinner(L"fancyzones_highlight_opacity", IDS_SETTINGS_HIGHLIGHT_OPACITY, settings.zoneHighlightOpacity, 0, 100, 1);
ptSettings.add_color_picker(L"fancyzones_zoneColor", IDS_SETTING_DESCRIPTION_ZONECOLOR, settings.zoneColor); ptSettings.add_color_picker(L"fancyzones_zoneColor", IDS_SETTING_DESCRIPTION_ZONECOLOR, settings.zoneColor);
@ -617,6 +628,7 @@ namespace FancyZonesUnitTests
values.add_property(L"fancyzones_restoreSize", expected.restoreSize); values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen); values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors); values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
values.add_property(L"fancyzones_zoneHighlightColor", expected.zoneHighlightColor); values.add_property(L"fancyzones_zoneHighlightColor", expected.zoneHighlightColor);
values.add_property(L"fancyzones_zoneColor", expected.zoneColor); values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor); values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
@ -654,6 +666,7 @@ namespace FancyZonesUnitTests
m_ptSettings->add_bool_toggle(L"fancyzones_restoreSize", IDS_SETTING_DESCRIPTION_RESTORESIZE, expected.restoreSize); m_ptSettings->add_bool_toggle(L"fancyzones_restoreSize", IDS_SETTING_DESCRIPTION_RESTORESIZE, expected.restoreSize);
m_ptSettings->add_bool_toggle(L"use_cursorpos_editor_startupscreen", IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN, expected.use_cursorpos_editor_startupscreen); m_ptSettings->add_bool_toggle(L"use_cursorpos_editor_startupscreen", IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN, expected.use_cursorpos_editor_startupscreen);
m_ptSettings->add_bool_toggle(L"fancyzones_show_on_all_monitors", IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS, expected.showZonesOnAllMonitors); m_ptSettings->add_bool_toggle(L"fancyzones_show_on_all_monitors", IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS, expected.showZonesOnAllMonitors);
m_ptSettings->add_bool_toggle(L"fancyzones_multi_monitor_mode", IDS_SETTING_DESCRIPTION_SPAN_ZONES_ACROSS_MONITORS, expected.spanZonesAcrossMonitors);
m_ptSettings->add_bool_toggle(L"fancyzones_makeDraggedWindowTransparent", IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT, expected.makeDraggedWindowTransparent); m_ptSettings->add_bool_toggle(L"fancyzones_makeDraggedWindowTransparent", IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT, expected.makeDraggedWindowTransparent);
m_ptSettings->add_color_picker(L"fancyzones_zoneHighlightColor", IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR, expected.zoneHighlightColor); m_ptSettings->add_color_picker(L"fancyzones_zoneHighlightColor", IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR, expected.zoneHighlightColor);
m_ptSettings->add_color_picker(L"fancyzones_zoneColor", IDS_SETTING_DESCRIPTION_ZONECOLOR, expected.zoneColor); m_ptSettings->add_color_picker(L"fancyzones_zoneColor", IDS_SETTING_DESCRIPTION_ZONECOLOR, expected.zoneColor);
@ -724,6 +737,7 @@ namespace FancyZonesUnitTests
.restoreSize = false, .restoreSize = false,
.use_cursorpos_editor_startupscreen = true, .use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false, .showZonesOnAllMonitors = false,
.spanZonesAcrossMonitors = false,
.makeDraggedWindowTransparent = true, .makeDraggedWindowTransparent = true,
.zoneColor = L"#FAFAFA", .zoneColor = L"#FAFAFA",
.zoneBorderColor = L"CCDDEE", .zoneBorderColor = L"CCDDEE",

View File

@ -791,7 +791,7 @@ namespace FancyZonesUnitTests
for (const auto& monitorInfo : m_popularMonitors) for (const auto& monitorInfo : m_popularMonitors)
{ {
auto set = MakeZoneSet(m_config); auto set = MakeZoneSet(m_config);
auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing);
Assert::IsTrue(result); Assert::IsTrue(result);
checkZones(set, zoneCount, monitorInfo); checkZones(set, zoneCount, monitorInfo);
} }
@ -808,7 +808,7 @@ namespace FancyZonesUnitTests
auto set = MakeZoneSet(m_config); auto set = MakeZoneSet(m_config);
MONITORINFO info{}; MONITORINFO info{};
auto result = set->CalculateZones(info, zoneCount, spacing); auto result = set->CalculateZones(info.rcWork, zoneCount, spacing);
Assert::IsFalse(result); Assert::IsFalse(result);
} }
} }
@ -825,7 +825,7 @@ namespace FancyZonesUnitTests
for (const auto& monitorInfo : m_popularMonitors) for (const auto& monitorInfo : m_popularMonitors)
{ {
auto set = MakeZoneSet(m_config); auto set = MakeZoneSet(m_config);
auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing);
Assert::IsTrue(result); Assert::IsTrue(result);
checkZones(set, zoneCount, monitorInfo); checkZones(set, zoneCount, monitorInfo);
} }
@ -844,7 +844,7 @@ namespace FancyZonesUnitTests
for (const auto& monitorInfo : m_popularMonitors) for (const auto& monitorInfo : m_popularMonitors)
{ {
auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing);
if (type == static_cast<int>(ZoneSetLayoutType::Focus)) if (type == static_cast<int>(ZoneSetLayoutType::Focus))
{ {
//Focus doesn't depends on spacing //Focus doesn't depends on spacing
@ -870,7 +870,7 @@ namespace FancyZonesUnitTests
for (const auto& monitorInfo : m_popularMonitors) for (const auto& monitorInfo : m_popularMonitors)
{ {
const int spacing = monitorInfo.rcWork.right; const int spacing = monitorInfo.rcWork.right;
auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing);
if (type == static_cast<int>(ZoneSetLayoutType::Focus)) if (type == static_cast<int>(ZoneSetLayoutType::Focus))
{ {
//Focus doesn't depends on spacing //Focus doesn't depends on spacing
@ -896,7 +896,7 @@ namespace FancyZonesUnitTests
for (const auto& monitorInfo : m_popularMonitors) for (const auto& monitorInfo : m_popularMonitors)
{ {
const int spacing = monitorInfo.rcWork.bottom; const int spacing = monitorInfo.rcWork.bottom;
auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing);
if (type == static_cast<int>(ZoneSetLayoutType::Focus)) if (type == static_cast<int>(ZoneSetLayoutType::Focus))
{ {
//Focus doesn't depends on spacing //Focus doesn't depends on spacing
@ -922,7 +922,7 @@ namespace FancyZonesUnitTests
for (const auto& monitorInfo : m_popularMonitors) for (const auto& monitorInfo : m_popularMonitors)
{ {
auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing);
Assert::IsFalse(result); Assert::IsFalse(result);
} }
} }
@ -942,7 +942,7 @@ namespace FancyZonesUnitTests
for (const auto& monitorInfo : m_popularMonitors) for (const auto& monitorInfo : m_popularMonitors)
{ {
auto set = MakeZoneSet(m_config); auto set = MakeZoneSet(m_config);
auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing);
Assert::IsTrue(result); Assert::IsTrue(result);
checkZones(set, zoneCount, monitorInfo); checkZones(set, zoneCount, monitorInfo);
} }
@ -965,7 +965,7 @@ namespace FancyZonesUnitTests
for (const auto& monitorInfo : m_popularMonitors) for (const auto& monitorInfo : m_popularMonitors)
{ {
auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing);
Assert::IsFalse(result); Assert::IsFalse(result);
} }
} }
@ -983,7 +983,7 @@ namespace FancyZonesUnitTests
for (const auto& monitorInfo : m_popularMonitors) for (const auto& monitorInfo : m_popularMonitors)
{ {
auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing);
Assert::IsFalse(result); Assert::IsFalse(result);
} }
} }
@ -1004,7 +1004,7 @@ namespace FancyZonesUnitTests
for (const auto& monitorInfo : m_popularMonitors) for (const auto& monitorInfo : m_popularMonitors)
{ {
auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing);
Assert::IsFalse(result); Assert::IsFalse(result);
} }
} }
@ -1030,7 +1030,7 @@ namespace FancyZonesUnitTests
for (const auto& monitorInfo : m_popularMonitors) for (const auto& monitorInfo : m_popularMonitors)
{ {
auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing);
Assert::IsFalse(result); Assert::IsFalse(result);
} }
} }
@ -1064,7 +1064,7 @@ namespace FancyZonesUnitTests
for (const auto& monitorInfo : m_popularMonitors) for (const auto& monitorInfo : m_popularMonitors)
{ {
auto set = MakeZoneSet(m_config); auto set = MakeZoneSet(m_config);
auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing);
Assert::IsTrue(result); Assert::IsTrue(result);
checkZones(set, zoneCount, monitorInfo); checkZones(set, zoneCount, monitorInfo);
} }
@ -1105,7 +1105,7 @@ namespace FancyZonesUnitTests
for (const auto& monitorInfo : m_popularMonitors) for (const auto& monitorInfo : m_popularMonitors)
{ {
auto set = MakeZoneSet(m_config); auto set = MakeZoneSet(m_config);
auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing);
Assert::IsTrue(result); Assert::IsTrue(result);
checkZones(set, zoneCount, monitorInfo); checkZones(set, zoneCount, monitorInfo);
} }
@ -1129,7 +1129,7 @@ namespace FancyZonesUnitTests
for (const auto& monitorInfo : m_popularMonitors) for (const auto& monitorInfo : m_popularMonitors)
{ {
auto result = set->CalculateZones(monitorInfo, zoneCount, spacing); auto result = set->CalculateZones(monitorInfo.rcWork, zoneCount, spacing);
Assert::IsFalse(result); Assert::IsFalse(result);
} }
} }

View File

@ -313,7 +313,8 @@ namespace PowerToysTests
Assert.AreNotEqual(toggleValues[7], GetPropertyValue<bool>(savedProps, "fancyzones_restoreSize")); Assert.AreNotEqual(toggleValues[7], GetPropertyValue<bool>(savedProps, "fancyzones_restoreSize"));
Assert.AreNotEqual(toggleValues[8], GetPropertyValue<bool>(savedProps, "use_cursorpos_editor_startupscreen")); Assert.AreNotEqual(toggleValues[8], GetPropertyValue<bool>(savedProps, "use_cursorpos_editor_startupscreen"));
Assert.AreNotEqual(toggleValues[9], GetPropertyValue<bool>(savedProps, "fancyzones_show_on_all_monitors")); Assert.AreNotEqual(toggleValues[9], GetPropertyValue<bool>(savedProps, "fancyzones_show_on_all_monitors"));
Assert.AreNotEqual(toggleValues[10], GetPropertyValue<bool>(savedProps, "fancyzones_makeDraggedWindowTransparent")); Assert.AreNotEqual(toggleValues[10], GetPropertyValue<bool>(savedProps, "fancyzones_multi_monitor_mode"));
Assert.AreNotEqual(toggleValues[11], GetPropertyValue<bool>(savedProps, "fancyzones_makeDraggedWindowTransparent"));
} }
/* /*
@ -353,7 +354,8 @@ namespace PowerToysTests
Assert.AreEqual(toggleValues[7], GetPropertyValue<bool>(savedProps, "fancyzones_restoreSize")); Assert.AreEqual(toggleValues[7], GetPropertyValue<bool>(savedProps, "fancyzones_restoreSize"));
Assert.AreEqual(toggleValues[8], GetPropertyValue<bool>(savedProps, "use_cursorpos_editor_startupscreen")); Assert.AreEqual(toggleValues[8], GetPropertyValue<bool>(savedProps, "use_cursorpos_editor_startupscreen"));
Assert.AreEqual(toggleValues[9], GetPropertyValue<bool>(savedProps, "fancyzones_show_on_all_monitors")); Assert.AreEqual(toggleValues[9], GetPropertyValue<bool>(savedProps, "fancyzones_show_on_all_monitors"));
Assert.AreEqual(toggleValues[10], GetPropertyValue<bool>(savedProps, "fancyzones_makeDraggedWindowTransparent")); Assert.AreEqual(toggleValues[10], GetPropertyValue<bool>(savedProps, "fancyzones_span_zones_across_monitors"));
Assert.AreEqual(toggleValues[11], GetPropertyValue<bool>(savedProps, "fancyzones_makeDraggedWindowTransparent"));
} }
[TestMethod] [TestMethod]