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

View File

@ -417,7 +417,7 @@
<data name="FileExplorerPreview_ToggleSwitch_Preview_SVG.Header" xml:space="preserve">
<value>Enable SVG (.svg) preview</value>
</data>
<data name="FileExplorerPreview_ToggleSwitch_SVG_Thumbnail.Header" xml:space="preserve">
<data name="FileExplorerPreview_ToggleSwitch_SVG_Thumbnail.Header" xml:space="preserve">
<value>Enable SVG (.svg) thumbnails</value>
</data>
<data name="FileExplorerPreview_Description.Text" xml:space="preserve">
@ -642,4 +642,7 @@
<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>
</data>
<data name="FancyZones_SpanZonesAcrossMonitorsCheckBoxControl.Content" xml:space="preserve">
<value>Allow zones to span across monitors</value>
</data>
</root>

View File

@ -45,11 +45,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
_restoreSize = Settings.Properties.FancyzonesRestoreSize.Value;
_useCursorPosEditorStartupScreen = Settings.Properties.UseCursorposEditorStartupscreen.Value;
_showOnAllMonitors = Settings.Properties.FancyzonesShowOnAllMonitors.Value;
_spanZonesAcrossMonitors = Settings.Properties.FancyzonesSpanZonesAcrossMonitors.Value;
_makeDraggedWindowTransparent = Settings.Properties.FancyzonesMakeDraggedWindowTransparent.Value;
_highlightOpacity = Settings.Properties.FancyzonesHighlightOpacity.Value;
_excludedApps = Settings.Properties.FancyzonesExcludedApps.Value;
EditorHotkey = Settings.Properties.FancyzonesEditorHotkey.Value;
string inactiveColor = Settings.Properties.FancyzonesInActiveColor.Value;
_zoneInActiveColor = inactiveColor != string.Empty ? inactiveColor.ToColor() : "#F5FCFF".ToColor();
@ -82,6 +82,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private bool _zoneSetChangeMoveWindows;
private bool _appLastZoneMoveWindows;
private bool _openWindowOnActiveMonitor;
private bool _spanZonesAcrossMonitors;
private bool _restoreSize;
private bool _useCursorPosEditorStartupScreen;
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
{
get

View File

@ -150,6 +150,11 @@
Margin="{StaticResource SmallTopMargin}"
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"
IsChecked="{x:Bind Mode=TwoWay, Path=ViewModel.MakeDraggedWindowsTransparent}"
Margin="{StaticResource SmallTopMargin}"

View File

@ -266,6 +266,24 @@ namespace ViewModelTests
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]
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="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="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>
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 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
keyPositions.Sort();
Snaps = new List<int>();
@ -143,8 +157,8 @@ namespace FancyZonesEditor
get => (int)(0.08 * ScreenW);
}
public SnappyHelperMagnetic(IList<Int32Rect> zones, int zoneIndex, bool isX, ResizeMode mode, int screenAxisSize)
: base(zones, zoneIndex, isX, mode, screenAxisSize)
public SnappyHelperMagnetic(IList<Int32Rect> zones, int zoneIndex, bool isX, ResizeMode mode, int screenAxisOrigin, int screenAxisSize)
: base(zones, zoneIndex, isX, mode, screenAxisOrigin, screenAxisSize)
{
freePosition = Position;
magnetZoneSizes = new List<int>();
@ -197,9 +211,11 @@ namespace FancyZonesEditor
private SnappyHelperBase snappyX;
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()
@ -287,8 +303,8 @@ namespace FancyZonesEditor
// Corner dragging
private void Caption_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{
snappyX = NewDefaultSnappyHelper(true, ResizeMode.BothEdges, (int)Settings.WorkArea.Width);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.BothEdges, (int)Settings.WorkArea.Height);
snappyX = NewDefaultSnappyHelper(true, ResizeMode.BothEdges);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.BothEdges);
}
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)
{
snappyX = NewDefaultSnappyHelper(true, ResizeMode.BottomEdge, (int)Settings.WorkArea.Width);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.BottomEdge, (int)Settings.WorkArea.Height);
snappyX = NewDefaultSnappyHelper(true, ResizeMode.BottomEdge);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.BottomEdge);
}
private void NEResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{
snappyX = NewDefaultSnappyHelper(true, ResizeMode.TopEdge, (int)Settings.WorkArea.Width);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.BottomEdge, (int)Settings.WorkArea.Height);
snappyX = NewDefaultSnappyHelper(true, ResizeMode.TopEdge);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.BottomEdge);
}
private void SWResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{
snappyX = NewDefaultSnappyHelper(true, ResizeMode.BottomEdge, (int)Settings.WorkArea.Width);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.TopEdge, (int)Settings.WorkArea.Height);
snappyX = NewDefaultSnappyHelper(true, ResizeMode.BottomEdge);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.TopEdge);
}
private void SEResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{
snappyX = NewDefaultSnappyHelper(true, ResizeMode.TopEdge, (int)Settings.WorkArea.Width);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.TopEdge, (int)Settings.WorkArea.Height);
snappyX = NewDefaultSnappyHelper(true, ResizeMode.TopEdge);
snappyY = NewDefaultSnappyHelper(false, ResizeMode.TopEdge);
}
// Edge dragging
private void NResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{
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)
{
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)
{
snappyX = NewDefaultSnappyHelper(true, ResizeMode.BottomEdge, (int)Settings.WorkArea.Width);
snappyX = NewDefaultSnappyHelper(true, ResizeMode.BottomEdge);
snappyY = null;
}
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;
}
}

View File

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

View File

@ -76,12 +76,20 @@ public:
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept
{
std::unique_lock writeLock(m_lock);
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
monitor = NULL;
}
m_windowMoveHandler.MoveSizeStart(window, monitor, ptScreen, m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId));
}
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept
{
std::unique_lock writeLock(m_lock);
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
monitor = NULL;
}
m_windowMoveHandler.MoveSizeUpdate(monitor, ptScreen, m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId));
}
@ -623,32 +631,76 @@ void FancyZones::ToggleEditor() noexcept
return;
}
winrt::com_ptr<IZoneWindow> zoneWindow;
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)
{
return;
}
MONITORINFOEX mi;
mi.cbSize = sizeof(mi);
std::wstring editorLocation;
m_dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] {
GetMonitorInfo(monitor, &mi);
} })
.wait();
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
std::vector<std::pair<HMONITOR, RECT>> allMonitors;
const auto taskbar_x_offset = mi.rcWork.left - mi.rcMonitor.left;
const auto taskbar_y_offset = mi.rcWork.top - mi.rcMonitor.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 height = mi.rcWork.bottom - mi.rcWork.top;
const std::wstring editorLocation =
std::to_wstring(x) + L"_" +
std::to_wstring(y) + L"_" +
std::to_wstring(width) + L"_" +
std::to_wstring(height);
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;
mi.cbSize = sizeof(mi);
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);
}
const auto& fancyZonesData = FancyZonesDataInstance();
@ -696,10 +748,13 @@ void FancyZones::ToggleEditor() noexcept
void FancyZones::SettingsChanged() noexcept
{
std::shared_lock readLock(m_lock);
// Update the hotkey
UnregisterHotKey(m_window, 1);
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
@ -864,7 +919,16 @@ void FancyZones::AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept
wil::unique_cotaskmem_string 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"
//const bool flash = m_settings->GetSettings()->zoneSetChange_flashZones;
@ -939,7 +1003,14 @@ void FancyZones::UpdateZoneWindows() noexcept
return TRUE;
};
EnumDisplayMonitors(nullptr, nullptr, callback, reinterpret_cast<LPARAM>(this));
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
AddZoneWindow(nullptr, NULL);
}
else
{
EnumDisplayMonitors(nullptr, nullptr, callback, reinterpret_cast<LPARAM>(this));
}
}
void FancyZones::UpdateWindowsPositions() noexcept
@ -995,58 +1066,65 @@ bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept
auto window = GetForegroundWindow();
if (IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray))
{
const HMONITOR current = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (current)
HMONITOR current;
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
std::vector<HMONITOR> monitorInfo = GetMonitorsSorted();
if (monitorInfo.size() > 1 && m_settings->GetSettings()->moveWindowAcrossMonitors)
current = NULL;
}
else
{
current = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
}
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
{
// Multi monitor environment.
auto currMonitorInfo = std::find(std::begin(monitorInfo), std::end(monitorInfo), current);
do
std::unique_lock writeLock(m_lock);
if (m_windowMoveHandler.MoveWindowIntoZoneByDirection(window, vkCode, false /* cycle through zones */, m_workAreaHandler.GetWorkArea(m_currentDesktopId, *currMonitorInfo)))
{
std::unique_lock writeLock(m_lock);
if (m_windowMoveHandler.MoveWindowIntoZoneByDirection(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))
{
return true;
currMonitorInfo = std::begin(monitorInfo);
}
// We iterated through all zones in current monitor zone layout, move on to next one (or previous depending on direction).
if (vkCode == VK_RIGHT)
}
else if (vkCode == VK_LEFT)
{
if (currMonitorInfo == std::begin(monitorInfo))
{
currMonitorInfo = std::next(currMonitorInfo);
if (currMonitorInfo == std::end(monitorInfo))
{
currMonitorInfo = std::begin(monitorInfo);
}
currMonitorInfo = std::end(monitorInfo);
}
else if (vkCode == VK_LEFT)
{
if (currMonitorInfo == std::begin(monitorInfo))
{
currMonitorInfo = std::end(monitorInfo);
}
currMonitorInfo = std::prev(currMonitorInfo);
}
} while (*currMonitorInfo != current);
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.MoveWindowIntoZoneByDirection(window, vkCode, false /* cycle through zones */, m_workAreaHandler.GetWorkArea(m_currentDesktopId, current));
if (!moved)
{
RestoreWindowOrigin(window);
RestoreWindowSize(window);
}
return true;
}
else
{
// Single monitor environment.
std::unique_lock writeLock(m_lock);
if (m_settings->GetSettings()->restoreSize)
{
bool moved = m_windowMoveHandler.MoveWindowIntoZoneByDirection(window, vkCode, false /* cycle through zones */, m_workAreaHandler.GetWorkArea(m_currentDesktopId, current));
if (!moved)
{
RestoreWindowOrigin(window);
RestoreWindowSize(window);
}
return true;
}
else
{
return m_windowMoveHandler.MoveWindowIntoZoneByDirection(window, vkCode, true /* cycle through zones */, m_workAreaHandler.GetWorkArea(m_currentDesktopId, current));
}
return m_windowMoveHandler.MoveWindowIntoZoneByDirection(window, vkCode, true /* cycle through zones */, m_workAreaHandler.GetWorkArea(m_currentDesktopId, current));
}
}
}
@ -1096,14 +1174,20 @@ bool FancyZones::ShouldProcessSnapHotkey() noexcept
{
if (m_settings->GetSettings()->overrideSnapHotkeys)
{
const HMONITOR monitor = MonitorFromWindow(GetForegroundWindow(), MONITOR_DEFAULTTONULL);
if (monitor)
HMONITOR monitor;
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
{
auto zoneWindow = m_workAreaHandler.GetWorkArea(m_currentDesktopId, monitor);
if (zoneWindow->ActiveZoneSet() != nullptr)
{
return true;
}
monitor = NULL;
}
else
{
monitor = MonitorFromWindow(GetForegroundWindow(), MONITOR_DEFAULTTONULL);
}
auto zoneWindow = m_workAreaHandler.GetWorkArea(m_currentDesktopId, monitor);
if (zoneWindow->ActiveZoneSet() != nullptr)
{
return true;
}
}
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)
{
HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
GUID desktopId{};
if (monitor && VirtualDesktopUtils::GetWindowDesktopId(window, &desktopId))
if (VirtualDesktopUtils::GetWindowDesktopId(window, &desktopId))
{
return GetWorkArea(desktopId, monitor);
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 nullptr;
}

View File

@ -36,7 +36,7 @@ private:
PCWSTR name;
bool* value;
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_mouseSwitch", &m_settings.mouseSwitch, IDS_SETTING_DESCRIPTION_MOUSESWITCH },
{ L"fancyzones_overrideSnapHotkeys", &m_settings.overrideSnapHotkeys, IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS },
@ -49,8 +49,9 @@ private:
{ L"fancyzones_openWindowOnActiveMonitor", &m_settings.openWindowOnActiveMonitor, IDS_SETTING_DESCRIPTION_OPEN_WINDOW_ON_ACTIVE_MONITOR },
{ 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"fancyzones_show_on_all_monitors", &m_settings.showZonesOnAllMonitors, IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS},
{ L"fancyzones_makeDraggedWindowTransparent", &m_settings.makeDraggedWindowTransparent, IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT},
{ 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 },
};
const std::wstring m_zoneColorName = L"fancyzones_zoneColor";

View File

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

View File

@ -142,7 +142,7 @@ public:
IFACEMETHODIMP_(void)
MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient) noexcept;
IFACEMETHODIMP_(bool)
CalculateZones(MONITORINFO monitorInfo, int zoneCount, int spacing) noexcept;
CalculateZones(RECT workArea, int zoneCount, int spacing) noexcept;
IFACEMETHODIMP_(bool)
IsZoneEmpty(int zoneIndex) noexcept;
@ -369,9 +369,9 @@ ZoneSet::MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient)
}
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
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
* 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 zoneCount Number of zones inside zone layout.
* @param spacing Spacing between zones in pixels.
* @param workAreaRect The rectangular area on the screen on which the zone layout is applied.
* @param zoneCount Number of zones inside zone layout.
* @param spacing Spacing between zones in pixels.
*
* @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.
*

View File

@ -7,6 +7,7 @@
#include "ZoneWindow.h"
#include "trace.h"
#include "util.h"
#include "Settings.h"
#include <ShellScalingApi.h>
#include <mutex>
@ -32,6 +33,22 @@ namespace ZoneWindowUtils
}
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
@ -253,16 +270,23 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit
{
m_host.copy_from(host);
MONITORINFO mi{};
mi.cbSize = sizeof(mi);
if (!GetMonitorInfoW(monitor, &mi))
{
return false;
}
Rect workAreaRect;
m_monitor = monitor;
const UINT dpi = GetDpiForMonitor(m_monitor);
const Rect workAreaRect(mi.rcWork, dpi);
if (monitor)
{
MONITORINFO mi{};
mi.cbSize = sizeof(mi);
if (!GetMonitorInfoW(monitor, &mi))
{
return false;
}
const UINT dpi = GetDpiForMonitor(m_monitor);
workAreaRect = Rect(mi.rcWork, dpi);
}
else
{
workAreaRect = GetAllMonitorsCombinedRect<&MONITORINFO::rcWork>();
}
m_uniqueId = uniqueId;
InitializeZoneSets(parentUniqueId);
@ -277,6 +301,9 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit
}
MakeWindowTransparent(m_window.get());
// Ignore flashZones
/*
if (flashZones)
{
// 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();
}
}
*/
return true;
}
@ -566,16 +594,31 @@ void ZoneWindow::CalculateZoneSet() noexcept
zoneSetId,
activeZoneSet.type,
m_monitor));
MONITORINFO monitorInfo{};
monitorInfo.cbSize = sizeof(monitorInfo);
if (GetMonitorInfoW(m_monitor, &monitorInfo))
RECT workArea;
if (m_monitor)
{
bool showSpacing = deviceInfoData->showSpacing;
int spacing = showSpacing ? deviceInfoData->spacing : 0;
int zoneCount = deviceInfoData->zoneCount;
zoneSet->CalculateZones(monitorInfo, zoneCount, spacing);
UpdateActiveZoneSet(zoneSet.get());
MONITORINFO monitorInfo{};
monitorInfo.cbSize = sizeof(monitorInfo);
if (GetMonitorInfoW(m_monitor, &monitorInfo))
{
workArea = monitorInfo.rcWork;
}
else
{
return;
}
}
else
{
workArea = GetAllMonitorsCombinedRect<&MONITORINFO::rcWork>();
}
bool showSpacing = deviceInfoData->showSpacing;
int spacing = showSpacing ? deviceInfoData->spacing : 0;
int zoneCount = deviceInfoData->zoneCount;
zoneSet->CalculateZones(workArea, zoneCount, spacing);
UpdateActiveZoneSet(zoneSet.get());
}
}

View File

@ -5,6 +5,7 @@
namespace ZoneWindowUtils
{
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_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_SPAN_ZONES_ACROSS_MONITORS "Allow zones to span across monitors"
IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT "Make dragged window transparent"
IDS_SETTING_DESCRIPTION_ZONECOLOR "Zone inactive color (Default #F5FCFF)"
IDS_SETTING_DESCRIPTION_ZONE_BORDER_COLOR "Zone border color (Default #FFFFFF)"
@ -26,8 +27,8 @@ BEGIN
IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION "To launch the zone editor, select the Edit zones button below or press the zone editor hotkey anytime"
IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL "Configure the zone editor hotkey"
IDS_SETTING_EXCLUDED_APPS_DESCRIPTION "To exclude an application from snapping to zones add its name here (one per line). Excluded apps will react to the Windows Snap regardless of all other settings."
IDS_SETTINGS_HIGHLIGHT_OPACITY "Zone opacity (%)"
IDS_FANCYZONES L"FancyZones"
IDS_SETTINGS_HIGHLIGHT_OPACITY "Zone opacity (%)"
IDS_FANCYZONES L"FancyZones"
IDS_CANT_DRAG_ELEVATED L"We've detected an application running with administrator privileges. This blocks some functionality in PowerToys. Visit our wiki page to learn more."
IDS_CANT_DRAG_ELEVATED_LEARN_MORE L"Learn more"
IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN L"Don't show again"

View File

@ -20,22 +20,23 @@
#define IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS 106
#define IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES 107
#define IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS 108
#define IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT 109
#define IDS_SETTING_DESCRIPTION_ZONECOLOR 110
#define IDS_SETTING_DESCRIPTION_ZONE_BORDER_COLOR 111
#define IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR 112
#define IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS 113
#define IDS_SETTING_DESCRIPTION_OPEN_WINDOW_ON_ACTIVE_MONITOR 114
#define IDS_SETTING_DESCRIPTION_RESTORESIZE 115
#define IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN 116
#define IDS_SETTING_DESCRIPTION 117
#define IDS_SETTING_LAUNCH_EDITOR_LABEL 118
#define IDS_SETTING_LAUNCH_EDITOR_BUTTON 119
#define IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION 120
#define IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL 121
#define IDS_SETTING_EXCLUDED_APPS_DESCRIPTION 122
#define IDS_SETTINGS_HIGHLIGHT_OPACITY 123
#define IDS_FANCYZONES 124
#define IDS_CANT_DRAG_ELEVATED 125
#define IDS_CANT_DRAG_ELEVATED_LEARN_MORE 126
#define IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN 127
#define IDS_SETTING_DESCRIPTION_SPAN_ZONES_ACROSS_MONITORS 109
#define IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT 110
#define IDS_SETTING_DESCRIPTION_ZONECOLOR 111
#define IDS_SETTING_DESCRIPTION_ZONE_BORDER_COLOR 112
#define IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR 113
#define IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS 114
#define IDS_SETTING_DESCRIPTION_OPEN_WINDOW_ON_ACTIVE_MONITOR 115
#define IDS_SETTING_DESCRIPTION_RESTORESIZE 116
#define IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN 117
#define IDS_SETTING_DESCRIPTION 118
#define IDS_SETTING_LAUNCH_EDITOR_LABEL 119
#define IDS_SETTING_LAUNCH_EDITOR_BUTTON 120
#define IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION 121
#define IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL 122
#define IDS_SETTING_EXCLUDED_APPS_DESCRIPTION 123
#define IDS_SETTINGS_HIGHLIGHT_OPACITY 124
#define IDS_FANCYZONES 125
#define IDS_CANT_DRAG_ELEVATED 126
#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.use_cursorpos_editor_startupscreen, "UseCursorPosOnEditorStartup"),
TraceLoggingBoolean(settings.showZonesOnAllMonitors, "ShowZonesOnAllMonitors"),
TraceLoggingBoolean(settings.spanZonesAcrossMonitors, "SpanZonesAcrossMonitors"),
TraceLoggingBoolean(settings.makeDraggedWindowTransparent, "MakeDraggedWindowTransparent"),
TraceLoggingWideString(settings.zoneColor.c_str(), "ZoneColor"),
TraceLoggingWideString(settings.zoneBorderColor.c_str(), "ZoneBorderColor"),

View File

@ -116,6 +116,55 @@ inline BYTE OpacitySettingToAlpha(int opacity)
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;
void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo);
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"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_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_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);
@ -122,6 +123,7 @@ namespace FancyZonesUnitTests
.appLastZone_moveWindows = true,
.restoreSize = false,
.use_cursorpos_editor_startupscreen = true,
.spanZonesAcrossMonitors = false,
.zoneColor = L"#abafee",
.zoneBorderColor = L"FAFAFA",
.zoneHighlightColor = L"#FAFAFA",
@ -152,6 +154,7 @@ namespace FancyZonesUnitTests
.appLastZone_moveWindows = true,
.restoreSize = false,
.use_cursorpos_editor_startupscreen = true,
.spanZonesAcrossMonitors = false,
.zoneColor = L"#FAFAFA",
.zoneBorderColor = L"#abafee",
.zoneHighlightColor = L"#FAFAFA",
@ -183,6 +186,7 @@ namespace FancyZonesUnitTests
.restoreSize = false,
.use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false,
.spanZonesAcrossMonitors = false,
.makeDraggedWindowTransparent = true,
.zoneColor = L"#FAFAFA",
.zoneBorderColor = L"FAFAFA",
@ -215,6 +219,7 @@ namespace FancyZonesUnitTests
.restoreSize = false,
.use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false,
.spanZonesAcrossMonitors = false,
.makeDraggedWindowTransparent = true,
.zoneColor = L"#FAFAFA",
.zoneBorderColor = L"FAFAFA",
@ -247,6 +252,7 @@ namespace FancyZonesUnitTests
.restoreSize = false,
.use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false,
.spanZonesAcrossMonitors = false,
.makeDraggedWindowTransparent = true,
.zoneColor = 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"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_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_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);

View File

@ -38,6 +38,7 @@ namespace FancyZonesUnitTests
Assert::AreEqual(expected.restoreSize, actual.restoreSize);
Assert::AreEqual(expected.use_cursorpos_editor_startupscreen, actual.use_cursorpos_editor_startupscreen);
Assert::AreEqual(expected.showZonesOnAllMonitors, actual.showZonesOnAllMonitors);
Assert::AreEqual(expected.spanZonesAcrossMonitors, actual.spanZonesAcrossMonitors);
Assert::AreEqual(expected.makeDraggedWindowTransparent, actual.makeDraggedWindowTransparent);
Assert::AreEqual(expected.zoneColor.c_str(), actual.zoneColor.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"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_multi_monitor_mode", expected.spanZonesAcrossMonitors);
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
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"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_multi_monitor_mode", expected.spanZonesAcrossMonitors);
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
@ -187,6 +190,7 @@ namespace FancyZonesUnitTests
.restoreSize = m_defaultSettings.restoreSize,
.use_cursorpos_editor_startupscreen = m_defaultSettings.use_cursorpos_editor_startupscreen,
.showZonesOnAllMonitors = m_defaultSettings.showZonesOnAllMonitors,
.spanZonesAcrossMonitors = m_defaultSettings.spanZonesAcrossMonitors,
.makeDraggedWindowTransparent = m_defaultSettings.makeDraggedWindowTransparent,
.zoneColor = L"FAFAFA",
.zoneBorderColor = L"CCDDEE",
@ -232,6 +236,7 @@ namespace FancyZonesUnitTests
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"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_highlight_opacity", expected.zoneHighlightOpacity);
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"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_multi_monitor_mode", expected.spanZonesAcrossMonitors);
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
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"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_multi_monitor_mode", expected.spanZonesAcrossMonitors);
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
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"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_multi_monitor_mode", expected.spanZonesAcrossMonitors);
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
@ -446,6 +454,7 @@ namespace FancyZonesUnitTests
.restoreSize = false,
.use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false,
.spanZonesAcrossMonitors = false,
.makeDraggedWindowTransparent = true,
.zoneColor = L"FAFAFA",
.zoneBorderColor = L"CCDDEE",
@ -469,6 +478,7 @@ namespace FancyZonesUnitTests
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"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_zoneColor", expected.zoneColor);
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"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_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_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);
@ -617,6 +628,7 @@ namespace FancyZonesUnitTests
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"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_zoneColor", expected.zoneColor);
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"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_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_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);
@ -724,6 +737,7 @@ namespace FancyZonesUnitTests
.restoreSize = false,
.use_cursorpos_editor_startupscreen = true,
.showZonesOnAllMonitors = false,
.spanZonesAcrossMonitors = false,
.makeDraggedWindowTransparent = true,
.zoneColor = L"#FAFAFA",
.zoneBorderColor = L"CCDDEE",

View File

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

View File

@ -313,7 +313,8 @@ namespace PowerToysTests
Assert.AreNotEqual(toggleValues[7], GetPropertyValue<bool>(savedProps, "fancyzones_restoreSize"));
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[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[8], GetPropertyValue<bool>(savedProps, "use_cursorpos_editor_startupscreen"));
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]