From e562b29ecd9bbca5521b392cf82e9d6b1fe7d411 Mon Sep 17 00:00:00 2001 From: Bret Anderson Date: Sun, 8 Sep 2019 01:47:12 -0700 Subject: [PATCH 1/7] Editor should come up on the monitor with the foreground window. Defaults to primary monitor if there is no foreground window. --- src/modules/fancyzones/dll/dllmain.cpp | 36 ++- .../editor/FancyZonesEditor/App.xaml.cs | 4 +- .../FancyZonesEditor/CanvasZone.xaml.cs | 27 +- .../FancyZonesEditor/EditorOverlay.xaml.cs | 266 +++++++++--------- .../FancyZonesEditor/Models/LayoutModel.cs | 17 +- .../FancyZonesEditor/Models/Settings.cs | 26 +- src/modules/fancyzones/lib/FancyZones.cpp | 15 +- 7 files changed, 206 insertions(+), 185 deletions(-) diff --git a/src/modules/fancyzones/dll/dllmain.cpp b/src/modules/fancyzones/dll/dllmain.cpp index 41c3e62677..a5d1a63158 100644 --- a/src/modules/fancyzones/dll/dllmain.cpp +++ b/src/modules/fancyzones/dll/dllmain.cpp @@ -32,22 +32,32 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReser // This function is exported and called from FancyZonesEditor.exe to save a layout from the editor. STDAPI PersistZoneSet( PCWSTR activeKey, // Registry key holding ActiveZoneSet - PCWSTR resolutionKey, // Registry key for screen resolution + HMONITOR monitor, WORD layoutId, // LayoutModel Id int zoneCount, // Number of zones in zones int zones[]) // Array of zones serialized in left/top/right/bottom chunks { // See if we have already persisted this layout we can update. - UUID id{GUID_NULL}; - if (wil::unique_hkey key{ RegistryHelpers::OpenKey(resolutionKey) }) - { - ZoneSetPersistedData data{}; - DWORD dataSize = sizeof(data); - wchar_t value[256]{}; - DWORD valueLength = ARRAYSIZE(value); - DWORD i = 0; - while (RegEnumValueW(key.get(), i++, value, &valueLength, nullptr, nullptr, reinterpret_cast(&data), &dataSize) == ERROR_SUCCESS) - { + std::wstringstream stream; + MONITORINFOEX mi; + mi.cbSize = sizeof(mi); + if (GetMonitorInfo(monitor, &mi)) + { + stream << (mi.rcMonitor.right - mi.rcMonitor.left) << "_"; + stream << (mi.rcMonitor.bottom - mi.rcMonitor.top); + } + + std::wstring resolutionKey(stream.str()); + UUID id{GUID_NULL}; + if (wil::unique_hkey key{ RegistryHelpers::OpenKey(resolutionKey.c_str()) }) + { + ZoneSetPersistedData data{}; + DWORD dataSize = sizeof(data); + wchar_t value[256]{}; + DWORD valueLength = ARRAYSIZE(value); + DWORD i = 0; + while (RegEnumValueW(key.get(), i++, value, &valueLength, nullptr, nullptr, reinterpret_cast(&data), &dataSize) == ERROR_SUCCESS) + { if (data.LayoutId == layoutId) { if (data.ZoneCount == zoneCount) @@ -73,8 +83,8 @@ STDAPI PersistZoneSet( ZoneSetConfig( id, layoutId, - MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), - resolutionKey, + reinterpret_cast(monitor), + resolutionKey.c_str(), ZoneSetLayout::Custom, 0, 0, 0)); diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/App.xaml.cs b/src/modules/fancyzones/editor/FancyZonesEditor/App.xaml.cs index 6115581a74..9d2b719cad 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/App.xaml.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/App.xaml.cs @@ -20,7 +20,6 @@ namespace FancyZonesEditor private ushort _idInitial = 0; public App() { - //init settings _settings = new Settings(); } @@ -64,8 +63,7 @@ namespace FancyZonesEditor } foundModel.IsSelected = true; - // TODO: multimon - // Pass in the correct args to show on the desired monitor + EditorOverlay overlay = new EditorOverlay(); overlay.Show(); overlay.DataContext = foundModel; diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/CanvasZone.xaml.cs b/src/modules/fancyzones/editor/FancyZonesEditor/CanvasZone.xaml.cs index ba3b26b82d..c0e74cdfde 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/CanvasZone.xaml.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/CanvasZone.xaml.cs @@ -41,7 +41,7 @@ namespace FancyZonesEditor } else if (xDelta > 0) { - xDelta = Math.Min(xDelta, c_workArea.Width - rect.Width - rect.X); + xDelta = Math.Min(xDelta, _settings.WorkArea.Width - rect.Width - rect.X); } if (yDelta < 0) @@ -50,7 +50,7 @@ namespace FancyZonesEditor } else if (yDelta > 0) { - yDelta = Math.Min(yDelta, c_workArea.Height - rect.Height - rect.Y); + yDelta = Math.Min(yDelta, _settings.WorkArea.Height - rect.Height - rect.Y); } rect.X += (int) xDelta; @@ -69,13 +69,13 @@ namespace FancyZonesEditor { int newWidth = rect.Width + (int) xDelta; - if (newWidth < 48) + if (newWidth < c_minZoneSize) { - newWidth = 48; + newWidth = c_minZoneSize; } - else if (newWidth > (c_workArea.Width - rect.X)) + else if (newWidth > (_settings.WorkArea.Width - rect.X)) { - newWidth = (int) c_workArea.Width - rect.X; + newWidth = (int) _settings.WorkArea.Width - rect.X; } MinWidth = rect.Width = newWidth; } @@ -84,13 +84,13 @@ namespace FancyZonesEditor { int newHeight = rect.Height + (int)yDelta; - if (newHeight < 48) + if (newHeight < c_minZoneSize) { - newHeight = 48; + newHeight = c_minZoneSize; } - else if (newHeight > (c_workArea.Height - rect.Y)) + else if (newHeight > (_settings.WorkArea.Height - rect.Y)) { - newHeight = (int)c_workArea.Height - rect.Y; + newHeight = (int)_settings.WorkArea.Height - rect.Y; } MinHeight = rect.Height = newHeight; } @@ -98,10 +98,7 @@ namespace FancyZonesEditor } private static int c_zIndex = 0; - - // TODO: multimon - // This needs to be the work area of the monitor we get launched on - private static Rect c_workArea = System.Windows.SystemParameters.WorkArea; + private static int c_minZoneSize = 48; protected override void OnPreviewMouseDown(MouseButtonEventArgs e) { @@ -163,5 +160,7 @@ namespace FancyZonesEditor ((Panel)Parent).Children.Remove(this); Model.RemoveZoneAt(ZoneIndex); } + + private Settings _settings = ((App)Application.Current).ZoneSettings; } } diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/EditorOverlay.xaml.cs b/src/modules/fancyzones/editor/FancyZonesEditor/EditorOverlay.xaml.cs index e537e9b523..9a83516ae1 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/EditorOverlay.xaml.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/EditorOverlay.xaml.cs @@ -1,138 +1,134 @@ -using FancyZonesEditor.Models; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.NetworkInformation; -using System.Security.RightsManagement; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Shapes; - -namespace FancyZonesEditor -{ - /// - /// Interaction logic for Window1.xaml - /// - public partial class EditorOverlay : Window - { - public Int32Rect[] GetZoneRects() - { - // TODO: the ideal here is that the ArrangeRects logic is entirely inside the model, so we don't have to walk the UIElement children to get the rect info - Panel previewPanel = null; - - if (_editor != null) - { - GridEditor gridEditor = _editor as GridEditor; - if (gridEditor != null) - { - previewPanel = gridEditor.PreviewPanel; - } - else - { - //CanvasEditor - previewPanel = ((CanvasEditor)_editor).Preview; - } - } - else - { - previewPanel = _layoutPreview.PreviewPanel; - } - - var count = previewPanel.Children.Count; - Int32Rect[] zones = new Int32Rect[count]; - - int i = 0; - foreach (FrameworkElement child in previewPanel.Children) - { - Point topLeft = child.TransformToAncestor(previewPanel).Transform(new Point()); - - var right = topLeft.X + child.ActualWidth; - var bottom = topLeft.Y + child.ActualHeight; - zones[i].X = (int)topLeft.X; - zones[i].Y = (int)topLeft.Y; - zones[i].Width = (int)child.ActualWidth; - zones[i].Height = (int)child.ActualHeight; - i++; - } - - return zones; - } - - public static EditorOverlay Current; - public EditorOverlay() - { - InitializeComponent(); - Current = this; +using FancyZonesEditor.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.NetworkInformation; +using System.Security.RightsManagement; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; - // TODO: multimon - // Need to set Left and Top to the correct monitor based on the - // foreground window passed in the command line arguments - Rect workArea = System.Windows.SystemParameters.WorkArea; - Left = workArea.Left; - Top = workArea.Top; - Width = workArea.Width; - Height = workArea.Height; +namespace FancyZonesEditor +{ + /// + /// Interaction logic for Window1.xaml + /// + public partial class EditorOverlay : Window + { + public Int32Rect[] GetZoneRects() + { + // TODO: the ideal here is that the ArrangeRects logic is entirely inside the model, so we don't have to walk the UIElement children to get the rect info + Panel previewPanel = null; + + if (_editor != null) + { + GridEditor gridEditor = _editor as GridEditor; + if (gridEditor != null) + { + previewPanel = gridEditor.PreviewPanel; + } + else + { + //CanvasEditor + previewPanel = ((CanvasEditor)_editor).Preview; + } + } + else + { + previewPanel = _layoutPreview.PreviewPanel; + } + + var count = previewPanel.Children.Count; + Int32Rect[] zones = new Int32Rect[count]; + + int i = 0; + foreach (FrameworkElement child in previewPanel.Children) + { + Point topLeft = child.TransformToAncestor(previewPanel).Transform(new Point()); + + var right = topLeft.X + child.ActualWidth; + var bottom = topLeft.Y + child.ActualHeight; + zones[i].X = (int)topLeft.X; + zones[i].Y = (int)topLeft.Y; + zones[i].Width = (int)child.ActualWidth; + zones[i].Height = (int)child.ActualHeight; + i++; + } + + return zones; } - void onLoad(object sender, RoutedEventArgs e) - { - ShowLayoutPicker(); - } - - public void ShowLayoutPicker() - { - DataContext = null; - - _editor = null; - _layoutPreview = new LayoutPreview(); - _layoutPreview.IsActualSize = true; - _layoutPreview.Opacity = 0.5; - Content = _layoutPreview; - - MainWindow window = new MainWindow(); - window.Owner = this; - window.Show(); - } - - // These event handlers are used to track the current state of the Shift and Ctrl keys on the keyboard - // They reflect that current state into properties on the Settings object, which the Zone view will listen to in editing mode - protected override void OnPreviewKeyDown(KeyEventArgs e) - { - _settings.IsShiftKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Shift); - _settings.IsCtrlKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Control); - base.OnPreviewKeyDown(e); - } - - protected override void OnPreviewKeyUp(KeyEventArgs e) - { - _settings.IsShiftKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Shift); - _settings.IsCtrlKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Control); - base.OnPreviewKeyUp(e); - } - - public void Edit() - { - _layoutPreview = null; - if (DataContext is GridLayoutModel) - { - _editor = new GridEditor(); - } - else if (DataContext is CanvasLayoutModel) - { - _editor = new CanvasEditor(); - } - Content = _editor; - } - - private Settings _settings = ((App)Application.Current).ZoneSettings; - private LayoutPreview _layoutPreview; - private UserControl _editor; - } -} + public static EditorOverlay Current; + public EditorOverlay() + { + InitializeComponent(); + Current = this; + + Left = _settings.WorkArea.Left; + Top = _settings.WorkArea.Top; + Width = _settings.WorkArea.Width; + Height = _settings.WorkArea.Height; + } + + void onLoad(object sender, RoutedEventArgs e) + { + ShowLayoutPicker(); + } + + public void ShowLayoutPicker() + { + DataContext = null; + + _editor = null; + _layoutPreview = new LayoutPreview(); + _layoutPreview.IsActualSize = true; + _layoutPreview.Opacity = 0.5; + Content = _layoutPreview; + + MainWindow window = new MainWindow(); + window.Owner = this; + window.Show(); + } + + // These event handlers are used to track the current state of the Shift and Ctrl keys on the keyboard + // They reflect that current state into properties on the Settings object, which the Zone view will listen to in editing mode + protected override void OnPreviewKeyDown(KeyEventArgs e) + { + _settings.IsShiftKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Shift); + _settings.IsCtrlKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Control); + base.OnPreviewKeyDown(e); + } + + protected override void OnPreviewKeyUp(KeyEventArgs e) + { + _settings.IsShiftKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Shift); + _settings.IsCtrlKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Control); + base.OnPreviewKeyUp(e); + } + + public void Edit() + { + _layoutPreview = null; + if (DataContext is GridLayoutModel) + { + _editor = new GridEditor(); + } + else if (DataContext is CanvasLayoutModel) + { + _editor = new CanvasEditor(); + } + Content = _editor; + } + + private Settings _settings = ((App)Application.Current).ZoneSettings; + private LayoutPreview _layoutPreview; + private UserControl _editor; + } +} diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs b/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs index 6a612d958b..8448677b84 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs @@ -155,7 +155,7 @@ namespace FancyZonesEditor.Models internal delegate int PersistZoneSet( [MarshalAs(UnmanagedType.LPWStr)] string activeKey, - [MarshalAs(UnmanagedType.LPWStr)] string key, + uint monitor, ushort layoutId, int zoneCount, [MarshalAs(UnmanagedType.LPArray)] int[] zoneArray); @@ -205,18 +205,15 @@ namespace FancyZonesEditor.Models string[] args = Environment.GetCommandLineArgs(); if (args.Length > 1) { - // args[1] = registry key value of currently active ZoneSet - // args[2] = id of layout to load at startup - string uniqueId = args[1]; - - // TODO: multimon - double height = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height; - double width = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width; - var key = width.ToString() + "_" + height.ToString(); + uint monitor = 0; + if (args.Length > 3) + { + monitor = uint.Parse(args[4]); + } var persistZoneSet = Marshal.GetDelegateForFunctionPointer(pfn); - persistZoneSet(uniqueId, key, _id, zoneCount, zoneArray); + persistZoneSet(uniqueId, monitor, _id, zoneCount, zoneArray); } } diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs b/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs index 0f10102924..6445554e66 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs @@ -23,11 +23,25 @@ namespace FancyZonesEditor { public Settings() { - Rect workArea = System.Windows.SystemParameters.WorkArea; + _workArea = System.Windows.SystemParameters.WorkArea; + string[] args = Environment.GetCommandLineArgs(); + if (args.Length > 2) + { + var foregroundWindow = uint.Parse(args[3]); + var screen = System.Windows.Forms.Screen.FromHandle(new IntPtr(foregroundWindow)); + + var graphics = System.Drawing.Graphics.FromHwnd(IntPtr.Zero); + float dpi = graphics.DpiX / 96; + _workArea = new Rect( + screen.WorkingArea.X / dpi, + screen.WorkingArea.Y / dpi, + screen.WorkingArea.Width / dpi, + screen.WorkingArea.Height / dpi); + } // Initialize the five default layout models: Focus, Columns, Rows, Grid, and PriorityGrid _defaultModels = new List(5); - _focusModel = new CanvasLayoutModel("Focus", c_focusModelId, (int)workArea.Width, (int)workArea.Height); + _focusModel = new CanvasLayoutModel("Focus", c_focusModelId, (int)_workArea.Width, (int)_workArea.Height); _defaultModels.Add(_focusModel); _columnsModel = new GridLayoutModel("Columns", c_columnsModelId); @@ -46,7 +60,7 @@ namespace FancyZonesEditor _priorityGridModel = new GridLayoutModel("Priority Grid", c_priorityGridModelId); _defaultModels.Add(_priorityGridModel); - _blankCustomModel = new CanvasLayoutModel("Create new custom", c_blankCustomModelId, (int)workArea.Width, (int)workArea.Height); + _blankCustomModel = new CanvasLayoutModel("Create new custom", c_blankCustomModelId, (int)_workArea.Width, (int)_workArea.Height); _zoneCount = (int)Registry.GetValue(FullRegistryPath, "ZoneCount", 3); _spacing = (int)Registry.GetValue(FullRegistryPath, "Spacing", 16); @@ -134,6 +148,12 @@ namespace FancyZonesEditor } private bool _isCtrlKeyPressed; + public Rect WorkArea + { + get { return _workArea; } + } + private Rect _workArea; + // UpdateLayoutModels // Update the five default layouts based on the new ZoneCount private void UpdateLayoutModels() diff --git a/src/modules/fancyzones/lib/FancyZones.cpp b/src/modules/fancyzones/lib/FancyZones.cpp index cd1266bc2b..372eeb5718 100644 --- a/src/modules/fancyzones/lib/FancyZones.cpp +++ b/src/modules/fancyzones/lib/FancyZones.cpp @@ -237,18 +237,19 @@ void FancyZones::ToggleEditor() noexcept m_terminateEditorEvent.reset(CreateEvent(nullptr, true, false, nullptr)); } - // TODO: multimon support - // Pass in args so that the editor shows up on the correct monitor - // This can be an HWND, HMONITOR, or the X/Y/Width/Height of the monitor's work area, (whichever works best). - if (const HMONITOR monitor = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY)) + const HWND foregroundWindow = GetForegroundWindow(); + if (const HMONITOR monitor = MonitorFromWindow(foregroundWindow, MONITOR_DEFAULTTOPRIMARY)) { std::shared_lock readLock(m_lock); auto iter = m_zoneWindowMap.find(monitor); if (iter != m_zoneWindowMap.end()) { - // Pass command line args to the editor to tell it which layout it should pick by default - auto activeZoneSet = iter->second->ActiveZoneSet(); - std::wstring params = iter->second->UniqueId() + L" " + std::to_wstring(activeZoneSet->LayoutId()); + const std::wstring params = + iter->second->UniqueId() + L" " + + std::to_wstring(iter->second->ActiveZoneSet()->LayoutId()) + L" " + + std::to_wstring(reinterpret_cast(foregroundWindow)) + L" " + + std::to_wstring(reinterpret_cast(monitor)); + SHELLEXECUTEINFO sei{ sizeof(sei) }; sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI }; sei.lpFile = L"modules\\FancyZonesEditor.exe"; From 3836aaa9d10774a7663f4daedd2475c292610e61 Mon Sep 17 00:00:00 2001 From: Bret Anderson Date: Sun, 8 Sep 2019 14:54:44 -0700 Subject: [PATCH 2/7] Almost working. Doesn't apply on my small monitor running at 150% scaling. --- .../FancyZonesEditor/Models/LayoutModel.cs | 25 ++---- .../FancyZonesEditor/Models/Settings.cs | 87 ++++++++++++++----- src/modules/fancyzones/lib/FancyZones.cpp | 10 +-- 3 files changed, 76 insertions(+), 46 deletions(-) diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs b/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs index 8448677b84..ddc1f94bef 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs @@ -186,14 +186,12 @@ namespace FancyZonesEditor.Models // Scale all the zones to the DPI and then pack them up to be marshalled. int zoneCount = zones.Length; var zoneArray = new int[zoneCount * 4]; - var graphics = System.Drawing.Graphics.FromHwnd(IntPtr.Zero); - float dpi = graphics.DpiX / 96; for (int i = 0; i < zones.Length; i++) { - var left = (int)(zones[i].X * dpi); - var top = (int)(zones[i].Y * dpi); - var right = left + (int)(zones[i].Width * dpi); - var bottom = top + (int)(zones[i].Height * dpi); + var left = (int)(zones[i].X * Settings.Dpi); + var top = (int)(zones[i].Y * Settings.Dpi); + var right = left + (int)(zones[i].Width * Settings.Dpi); + var bottom = top + (int)(zones[i].Height * Settings.Dpi); var index = i * 4; zoneArray[index] = left; @@ -202,19 +200,8 @@ namespace FancyZonesEditor.Models zoneArray[index+3] = bottom; } - string[] args = Environment.GetCommandLineArgs(); - if (args.Length > 1) - { - string uniqueId = args[1]; - uint monitor = 0; - if (args.Length > 3) - { - monitor = uint.Parse(args[4]); - } - - var persistZoneSet = Marshal.GetDelegateForFunctionPointer(pfn); - persistZoneSet(uniqueId, monitor, _id, zoneCount, zoneArray); - } + var persistZoneSet = Marshal.GetDelegateForFunctionPointer(pfn); + persistZoneSet(Settings.UniqueKey, Settings.Monitor, _id, zoneCount, zoneArray); } private static readonly string c_registryPath = Settings.RegistryPath + "\\Layouts"; diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs b/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs index 6445554e66..6449772831 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs @@ -23,21 +23,7 @@ namespace FancyZonesEditor { public Settings() { - _workArea = System.Windows.SystemParameters.WorkArea; - string[] args = Environment.GetCommandLineArgs(); - if (args.Length > 2) - { - var foregroundWindow = uint.Parse(args[3]); - var screen = System.Windows.Forms.Screen.FromHandle(new IntPtr(foregroundWindow)); - - var graphics = System.Drawing.Graphics.FromHwnd(IntPtr.Zero); - float dpi = graphics.DpiX / 96; - _workArea = new Rect( - screen.WorkingArea.X / dpi, - screen.WorkingArea.Y / dpi, - screen.WorkingArea.Width / dpi, - screen.WorkingArea.Height / dpi); - } + ParseCommandLineArgs(); // Initialize the five default layout models: Focus, Columns, Rows, Grid, and PriorityGrid _defaultModels = new List(5); @@ -62,9 +48,9 @@ namespace FancyZonesEditor _blankCustomModel = new CanvasLayoutModel("Create new custom", c_blankCustomModelId, (int)_workArea.Width, (int)_workArea.Height); - _zoneCount = (int)Registry.GetValue(FullRegistryPath, "ZoneCount", 3); - _spacing = (int)Registry.GetValue(FullRegistryPath, "Spacing", 16); - _showSpacing = (int)Registry.GetValue(FullRegistryPath, "ShowSpacing", 1) == 1; + _zoneCount = (int)Registry.GetValue(_uniqueRegistryPath, "ZoneCount", 3); + _spacing = (int)Registry.GetValue(_uniqueRegistryPath, "Spacing", 16); + _showSpacing = (int)Registry.GetValue(_uniqueRegistryPath, "ShowSpacing", 1) == 1; UpdateLayoutModels(); } @@ -78,7 +64,7 @@ namespace FancyZonesEditor if (_zoneCount != value) { _zoneCount = value; - Registry.SetValue(FullRegistryPath, "ZoneCount", _zoneCount, RegistryValueKind.DWord); + Registry.SetValue(_uniqueRegistryPath, "ZoneCount", _zoneCount, RegistryValueKind.DWord); UpdateLayoutModels(); FirePropertyChanged("ZoneCount"); } @@ -95,7 +81,7 @@ namespace FancyZonesEditor if (_spacing != value) { _spacing = value; - Registry.SetValue(FullRegistryPath, "Spacing", _spacing, RegistryValueKind.DWord); + Registry.SetValue(_uniqueRegistryPath, "Spacing", _spacing, RegistryValueKind.DWord); FirePropertyChanged("Spacing"); } } @@ -111,7 +97,7 @@ namespace FancyZonesEditor if (_showSpacing != value) { _showSpacing = value; - Registry.SetValue(FullRegistryPath, "ShowSpacing", _showSpacing, RegistryValueKind.DWord); + Registry.SetValue(_uniqueRegistryPath, "ShowSpacing", _showSpacing, RegistryValueKind.DWord); FirePropertyChanged("ShowSpacing"); } } @@ -154,6 +140,25 @@ namespace FancyZonesEditor } private Rect _workArea; + public static uint Monitor + { + get { return _monitor; } + } + private static uint _monitor; + + public static String UniqueKey + { + get { return _uniqueKey; } + } + private static String _uniqueKey; + private String _uniqueRegistryPath; + + public static float Dpi + { + get { return _dpi; } + } + private static float _dpi; + // UpdateLayoutModels // Update the five default layouts based on the new ZoneCount private void UpdateLayoutModels() @@ -251,7 +256,45 @@ namespace FancyZonesEditor _priorityGridModel.ColumnPercents = _gridModel.ColumnPercents; _priorityGridModel.CellChildMap = _gridModel.CellChildMap; } - } + } + + private void ParseCommandLineArgs() + { + _workArea = System.Windows.SystemParameters.WorkArea; + _monitor = 0; + _uniqueKey = ""; + _dpi = 1; + + string[] args = Environment.GetCommandLineArgs(); + if (args.Length == 5) + { + // 1 = unique key for per-monitor settings + // 2 = layoutid used to generate current layout + // 3 = handle to foreground window (used to figure out which monitor to show on) + // 4 = handle to monitor (passed back to engine to persist data) + + _uniqueKey = args[1]; + _uniqueRegistryPath = FullRegistryPath + "\\" + _uniqueKey; + + var foregroundWindow = new IntPtr(uint.Parse(args[3])); + var screen = System.Windows.Forms.Screen.FromHandle(foregroundWindow); + + var graphics = System.Drawing.Graphics.FromHwnd(foregroundWindow); + _dpi = graphics.DpiX / 96; + _workArea = new Rect( + screen.WorkingArea.X / _dpi, + screen.WorkingArea.Y / _dpi, + screen.WorkingArea.Width / _dpi, + screen.WorkingArea.Height / _dpi); + + uint monitor = 0; + if (uint.TryParse(args[4], out monitor)) + { + _monitor = monitor; + } + } + } + public IList DefaultModels { get { return _defaultModels; } } public ObservableCollection CustomModels diff --git a/src/modules/fancyzones/lib/FancyZones.cpp b/src/modules/fancyzones/lib/FancyZones.cpp index 372eeb5718..6587694cdc 100644 --- a/src/modules/fancyzones/lib/FancyZones.cpp +++ b/src/modules/fancyzones/lib/FancyZones.cpp @@ -237,7 +237,7 @@ void FancyZones::ToggleEditor() noexcept m_terminateEditorEvent.reset(CreateEvent(nullptr, true, false, nullptr)); } - const HWND foregroundWindow = GetForegroundWindow(); + const HWND foregroundWindow = GetForegroundWindow(); if (const HMONITOR monitor = MonitorFromWindow(foregroundWindow, MONITOR_DEFAULTTOPRIMARY)) { std::shared_lock readLock(m_lock); @@ -245,10 +245,10 @@ void FancyZones::ToggleEditor() noexcept if (iter != m_zoneWindowMap.end()) { const std::wstring params = - iter->second->UniqueId() + L" " + - std::to_wstring(iter->second->ActiveZoneSet()->LayoutId()) + L" " + - std::to_wstring(reinterpret_cast(foregroundWindow)) + L" " + - std::to_wstring(reinterpret_cast(monitor)); + iter->second->UniqueId() + L" " + + std::to_wstring(iter->second->ActiveZoneSet()->LayoutId()) + L" " + + std::to_wstring(reinterpret_cast(foregroundWindow)) + L" " + + std::to_wstring(reinterpret_cast(monitor)); SHELLEXECUTEINFO sei{ sizeof(sei) }; sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI }; From d4c8c8444582ba3921cd050d765768df074cc314 Mon Sep 17 00:00:00 2001 From: Bret Anderson Date: Sun, 8 Sep 2019 23:53:30 -0700 Subject: [PATCH 3/7] Pass DPI through to editor. It is more reliable. --- .../FancyZonesEditor/Models/Settings.cs | 663 +++++++++--------- src/modules/fancyzones/lib/FancyZones.cpp | 8 +- 2 files changed, 339 insertions(+), 332 deletions(-) diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs b/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs index 6449772831..f5098f04ed 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs @@ -1,290 +1,291 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.ComponentModel; -using System.Collections; -using System.Collections.ObjectModel; -using FancyZonesEditor.Models; -using System.Windows.Documents; -using System.Windows; -using System.Windows.Controls; -using Microsoft.Win32; - -namespace FancyZonesEditor -{ - // - // Settings - // These are the configuration settings used by the rest of the editor - // Other UIs in the editor will subscribe to change events on the properties to stay up to date as these properties change - // - public class Settings : INotifyPropertyChanged - { - public Settings() - { - ParseCommandLineArgs(); - - // Initialize the five default layout models: Focus, Columns, Rows, Grid, and PriorityGrid - _defaultModels = new List(5); - _focusModel = new CanvasLayoutModel("Focus", c_focusModelId, (int)_workArea.Width, (int)_workArea.Height); - _defaultModels.Add(_focusModel); - - _columnsModel = new GridLayoutModel("Columns", c_columnsModelId); - _columnsModel.Rows = 1; - _columnsModel.RowPercents = new int[1] { c_multiplier }; - _defaultModels.Add(_columnsModel); - - _rowsModel = new GridLayoutModel("Rows", c_rowsModelId); - _rowsModel.Columns = 1; - _rowsModel.ColumnPercents = new int[1] { c_multiplier }; - _defaultModels.Add(_rowsModel); - - _gridModel = new GridLayoutModel("Grid", c_gridModelId); - _defaultModels.Add(_gridModel); - - _priorityGridModel = new GridLayoutModel("Priority Grid", c_priorityGridModelId); - _defaultModels.Add(_priorityGridModel); - - _blankCustomModel = new CanvasLayoutModel("Create new custom", c_blankCustomModelId, (int)_workArea.Width, (int)_workArea.Height); - - _zoneCount = (int)Registry.GetValue(_uniqueRegistryPath, "ZoneCount", 3); - _spacing = (int)Registry.GetValue(_uniqueRegistryPath, "Spacing", 16); - _showSpacing = (int)Registry.GetValue(_uniqueRegistryPath, "ShowSpacing", 1) == 1; - - UpdateLayoutModels(); - } - - // ZoneCount - number of zones selected in the picker window - public int ZoneCount - { - get { return _zoneCount; } - set - { - if (_zoneCount != value) - { - _zoneCount = value; - Registry.SetValue(_uniqueRegistryPath, "ZoneCount", _zoneCount, RegistryValueKind.DWord); - UpdateLayoutModels(); - FirePropertyChanged("ZoneCount"); - } - } - } - private int _zoneCount; - - // Spacing - how much space in between zones of the grid do you want - public int Spacing - { - get { return _spacing; } - set - { - if (_spacing != value) - { - _spacing = value; - Registry.SetValue(_uniqueRegistryPath, "Spacing", _spacing, RegistryValueKind.DWord); - FirePropertyChanged("Spacing"); - } - } - } - private int _spacing; - - // ShowSpacing - is the Spacing value used or ignored? - public bool ShowSpacing - { - get { return _showSpacing; } - set - { - if (_showSpacing != value) - { - _showSpacing = value; - Registry.SetValue(_uniqueRegistryPath, "ShowSpacing", _showSpacing, RegistryValueKind.DWord); - FirePropertyChanged("ShowSpacing"); - } - } - } - private bool _showSpacing; - - // IsShiftKeyPressed - is the shift key currently being held down - public bool IsShiftKeyPressed - { - get { return _isShiftKeyPressed; } - set - { - if (_isShiftKeyPressed != value) - { - _isShiftKeyPressed = value; - FirePropertyChanged("IsShiftKeyPressed"); - } - } - } - private bool _isShiftKeyPressed; - - // IsCtrlKeyPressed - is the ctrl key currently being held down - public bool IsCtrlKeyPressed - { - get { return _isCtrlKeyPressed; } - set - { - if (_isCtrlKeyPressed != value) - { - _isCtrlKeyPressed = value; - FirePropertyChanged("IsCtrlKeyPressed"); - } - } - } - private bool _isCtrlKeyPressed; - - public Rect WorkArea - { - get { return _workArea; } - } - private Rect _workArea; - +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.ComponentModel; +using System.Collections; +using System.Collections.ObjectModel; +using FancyZonesEditor.Models; +using System.Windows.Documents; +using System.Windows; +using System.Windows.Controls; +using Microsoft.Win32; + +namespace FancyZonesEditor +{ + // + // Settings + // These are the configuration settings used by the rest of the editor + // Other UIs in the editor will subscribe to change events on the properties to stay up to date as these properties change + // + public class Settings : INotifyPropertyChanged + { + public Settings() + { + ParseCommandLineArgs(); + + // Initialize the five default layout models: Focus, Columns, Rows, Grid, and PriorityGrid + _defaultModels = new List(5); + _focusModel = new CanvasLayoutModel("Focus", c_focusModelId, (int)_workArea.Width, (int)_workArea.Height); + _defaultModels.Add(_focusModel); + + _columnsModel = new GridLayoutModel("Columns", c_columnsModelId); + _columnsModel.Rows = 1; + _columnsModel.RowPercents = new int[1] { c_multiplier }; + _defaultModels.Add(_columnsModel); + + _rowsModel = new GridLayoutModel("Rows", c_rowsModelId); + _rowsModel.Columns = 1; + _rowsModel.ColumnPercents = new int[1] { c_multiplier }; + _defaultModels.Add(_rowsModel); + + _gridModel = new GridLayoutModel("Grid", c_gridModelId); + _defaultModels.Add(_gridModel); + + _priorityGridModel = new GridLayoutModel("Priority Grid", c_priorityGridModelId); + _defaultModels.Add(_priorityGridModel); + + _blankCustomModel = new CanvasLayoutModel("Create new custom", c_blankCustomModelId, (int)_workArea.Width, (int)_workArea.Height); + + _zoneCount = (int)Registry.GetValue(_uniqueRegistryPath, "ZoneCount", 3); + _spacing = (int)Registry.GetValue(_uniqueRegistryPath, "Spacing", 16); + _showSpacing = (int)Registry.GetValue(_uniqueRegistryPath, "ShowSpacing", 1) == 1; + + UpdateLayoutModels(); + } + + // ZoneCount - number of zones selected in the picker window + public int ZoneCount + { + get { return _zoneCount; } + set + { + if (_zoneCount != value) + { + _zoneCount = value; + Registry.SetValue(_uniqueRegistryPath, "ZoneCount", _zoneCount, RegistryValueKind.DWord); + UpdateLayoutModels(); + FirePropertyChanged("ZoneCount"); + } + } + } + private int _zoneCount; + + // Spacing - how much space in between zones of the grid do you want + public int Spacing + { + get { return _spacing; } + set + { + if (_spacing != value) + { + _spacing = value; + Registry.SetValue(_uniqueRegistryPath, "Spacing", _spacing, RegistryValueKind.DWord); + FirePropertyChanged("Spacing"); + } + } + } + private int _spacing; + + // ShowSpacing - is the Spacing value used or ignored? + public bool ShowSpacing + { + get { return _showSpacing; } + set + { + if (_showSpacing != value) + { + _showSpacing = value; + Registry.SetValue(_uniqueRegistryPath, "ShowSpacing", _showSpacing, RegistryValueKind.DWord); + FirePropertyChanged("ShowSpacing"); + } + } + } + private bool _showSpacing; + + // IsShiftKeyPressed - is the shift key currently being held down + public bool IsShiftKeyPressed + { + get { return _isShiftKeyPressed; } + set + { + if (_isShiftKeyPressed != value) + { + _isShiftKeyPressed = value; + FirePropertyChanged("IsShiftKeyPressed"); + } + } + } + private bool _isShiftKeyPressed; + + // IsCtrlKeyPressed - is the ctrl key currently being held down + public bool IsCtrlKeyPressed + { + get { return _isCtrlKeyPressed; } + set + { + if (_isCtrlKeyPressed != value) + { + _isCtrlKeyPressed = value; + FirePropertyChanged("IsCtrlKeyPressed"); + } + } + } + private bool _isCtrlKeyPressed; + + public Rect WorkArea + { + get { return _workArea; } + } + private Rect _workArea; + public static uint Monitor { get { return _monitor; } - } - private static uint _monitor; - + } + private static uint _monitor; + public static String UniqueKey { get { return _uniqueKey; } - } - private static String _uniqueKey; - private String _uniqueRegistryPath; - + } + private static String _uniqueKey; + private String _uniqueRegistryPath; + public static float Dpi { get { return _dpi; } - } - private static float _dpi; - - // UpdateLayoutModels - // Update the five default layouts based on the new ZoneCount - private void UpdateLayoutModels() - { - int previousZoneCount = _focusModel.Zones.Count; - - // Update the "Focus" Default Layout - _focusModel.Zones.Clear(); - - Int32Rect focusZoneRect = new Int32Rect((int)(_focusModel.ReferenceWidth * 0.1), (int)(_focusModel.ReferenceHeight * 0.1), (int)(_focusModel.ReferenceWidth * 0.6), (int)(_focusModel.ReferenceHeight * 0.6)); - int focusRectXIncrement = (ZoneCount <= 1) ? 0 : (int)(_focusModel.ReferenceWidth * 0.2) / (ZoneCount - 1); - int focusRectYIncrement = (ZoneCount <= 1) ? 0 : (int)(_focusModel.ReferenceHeight * 0.2) / (ZoneCount - 1); - - for (int i = 0; i < ZoneCount; i++) - { - _focusModel.Zones.Add(focusZoneRect); - focusZoneRect.X += focusRectXIncrement; - focusZoneRect.Y += focusRectYIncrement; - } - - // Update the "Rows" and "Columns" Default Layouts - // They can share their model, just transposed - _rowsModel.CellChildMap = new int[ZoneCount, 1]; - _columnsModel.CellChildMap = new int[1, ZoneCount]; - _rowsModel.Rows = _columnsModel.Columns = ZoneCount; - _rowsModel.RowPercents = _columnsModel.ColumnPercents = new int[ZoneCount]; - - for (int i = 0; i < ZoneCount; i++) - { - _rowsModel.CellChildMap[i, 0] = i; - _columnsModel.CellChildMap[0, i] = i; - _rowsModel.RowPercents[i] = c_multiplier / ZoneCount; // _columnsModel is sharing the same array - } - - // Update the "Grid" Default Layout - int rows = 1; - int cols = 1; - int mergeCount = 0; - while (ZoneCount / rows >= rows) - { - rows++; - } - rows--; - cols = ZoneCount / rows; - if (ZoneCount % rows == 0) - { - // even grid - } - else - { - cols++; - mergeCount = rows - (ZoneCount % rows); - } - _gridModel.Rows = rows; - _gridModel.Columns = cols; - _gridModel.RowPercents = new int[rows]; - _gridModel.ColumnPercents = new int[cols]; - _gridModel.CellChildMap = new int[rows, cols]; - - for (int row = 0; row < rows; row++) - { - _gridModel.RowPercents[row] = c_multiplier / rows; - } - - for (int col = 0; col < cols; col++) - { - _gridModel.ColumnPercents[col] = c_multiplier / cols; - } - - int index = 0; - for (int col = cols - 1; col >= 0; col--) - { - for (int row = rows - 1; row >= 0; row--) - { - _gridModel.CellChildMap[row, col] = index++; - if (index == ZoneCount) - { - index--; - } - - } - } - - // Update the "Priority Grid" Default Layout - if (ZoneCount <= s_priorityData.Length) - { - _priorityGridModel.Reload(s_priorityData[ZoneCount - 1]); - } - else - { - // same as grid; - _priorityGridModel.Rows = _gridModel.Rows; - _priorityGridModel.Columns = _gridModel.Columns; - _priorityGridModel.RowPercents = _gridModel.RowPercents; - _priorityGridModel.ColumnPercents = _gridModel.ColumnPercents; - _priorityGridModel.CellChildMap = _gridModel.CellChildMap; - } + } + private static float _dpi; + + // UpdateLayoutModels + // Update the five default layouts based on the new ZoneCount + private void UpdateLayoutModels() + { + int previousZoneCount = _focusModel.Zones.Count; + + // Update the "Focus" Default Layout + _focusModel.Zones.Clear(); + + Int32Rect focusZoneRect = new Int32Rect((int)(_focusModel.ReferenceWidth * 0.1), (int)(_focusModel.ReferenceHeight * 0.1), (int)(_focusModel.ReferenceWidth * 0.6), (int)(_focusModel.ReferenceHeight * 0.6)); + int focusRectXIncrement = (ZoneCount <= 1) ? 0 : (int)(_focusModel.ReferenceWidth * 0.2) / (ZoneCount - 1); + int focusRectYIncrement = (ZoneCount <= 1) ? 0 : (int)(_focusModel.ReferenceHeight * 0.2) / (ZoneCount - 1); + + for (int i = 0; i < ZoneCount; i++) + { + _focusModel.Zones.Add(focusZoneRect); + focusZoneRect.X += focusRectXIncrement; + focusZoneRect.Y += focusRectYIncrement; + } + + // Update the "Rows" and "Columns" Default Layouts + // They can share their model, just transposed + _rowsModel.CellChildMap = new int[ZoneCount, 1]; + _columnsModel.CellChildMap = new int[1, ZoneCount]; + _rowsModel.Rows = _columnsModel.Columns = ZoneCount; + _rowsModel.RowPercents = _columnsModel.ColumnPercents = new int[ZoneCount]; + + for (int i = 0; i < ZoneCount; i++) + { + _rowsModel.CellChildMap[i, 0] = i; + _columnsModel.CellChildMap[0, i] = i; + _rowsModel.RowPercents[i] = c_multiplier / ZoneCount; // _columnsModel is sharing the same array + } + + // Update the "Grid" Default Layout + int rows = 1; + int cols = 1; + int mergeCount = 0; + while (ZoneCount / rows >= rows) + { + rows++; + } + rows--; + cols = ZoneCount / rows; + if (ZoneCount % rows == 0) + { + // even grid + } + else + { + cols++; + mergeCount = rows - (ZoneCount % rows); + } + _gridModel.Rows = rows; + _gridModel.Columns = cols; + _gridModel.RowPercents = new int[rows]; + _gridModel.ColumnPercents = new int[cols]; + _gridModel.CellChildMap = new int[rows, cols]; + + for (int row = 0; row < rows; row++) + { + _gridModel.RowPercents[row] = c_multiplier / rows; + } + + for (int col = 0; col < cols; col++) + { + _gridModel.ColumnPercents[col] = c_multiplier / cols; + } + + int index = 0; + for (int col = cols - 1; col >= 0; col--) + { + for (int row = rows - 1; row >= 0; row--) + { + _gridModel.CellChildMap[row, col] = index++; + if (index == ZoneCount) + { + index--; + } + + } + } + + // Update the "Priority Grid" Default Layout + if (ZoneCount <= s_priorityData.Length) + { + _priorityGridModel.Reload(s_priorityData[ZoneCount - 1]); + } + else + { + // same as grid; + _priorityGridModel.Rows = _gridModel.Rows; + _priorityGridModel.Columns = _gridModel.Columns; + _priorityGridModel.RowPercents = _gridModel.RowPercents; + _priorityGridModel.ColumnPercents = _gridModel.ColumnPercents; + _priorityGridModel.CellChildMap = _gridModel.CellChildMap; + } } private void ParseCommandLineArgs() { _workArea = System.Windows.SystemParameters.WorkArea; _monitor = 0; + _uniqueRegistryPath = FullRegistryPath; _uniqueKey = ""; _dpi = 1; string[] args = Environment.GetCommandLineArgs(); - if (args.Length == 5) + if (args.Length == 6) { // 1 = unique key for per-monitor settings // 2 = layoutid used to generate current layout // 3 = handle to foreground window (used to figure out which monitor to show on) // 4 = handle to monitor (passed back to engine to persist data) + // 5 = monitor DPI (float) _uniqueKey = args[1]; - _uniqueRegistryPath = FullRegistryPath + "\\" + _uniqueKey; + _uniqueRegistryPath += "\\" + _uniqueKey; - var foregroundWindow = new IntPtr(uint.Parse(args[3])); - var screen = System.Windows.Forms.Screen.FromHandle(foregroundWindow); - - var graphics = System.Drawing.Graphics.FromHwnd(foregroundWindow); - _dpi = graphics.DpiX / 96; - _workArea = new Rect( - screen.WorkingArea.X / _dpi, - screen.WorkingArea.Y / _dpi, - screen.WorkingArea.Width / _dpi, + var foregroundWindow = new IntPtr(uint.Parse(args[3])); + var screen = System.Windows.Forms.Screen.FromHandle(foregroundWindow); + + _dpi = float.Parse(args[5]); + _workArea = new Rect( + screen.WorkingArea.X / _dpi, + screen.WorkingArea.Y / _dpi, + screen.WorkingArea.Width / _dpi, screen.WorkingArea.Height / _dpi); uint monitor = 0; @@ -294,74 +295,74 @@ namespace FancyZonesEditor } } } - - - public IList DefaultModels { get { return _defaultModels; } } - public ObservableCollection CustomModels - { - get - { - if (_customModels == null) - { - _customModels = LayoutModel.LoadCustomModels(); - _customModels.Insert(0, _blankCustomModel); - } - return _customModels; - } - } - private ObservableCollection _customModels; - - public static readonly string RegistryPath = "SOFTWARE\\SuperFancyZones"; - public static readonly string FullRegistryPath = "HKEY_CURRENT_USER\\" + RegistryPath; - - public static bool IsPredefinedLayout(LayoutModel model) - { - return (model.Id >= c_lastPrefinedId); - } - - // implementation of INotifyProeprtyChanged - public event PropertyChangedEventHandler PropertyChanged; - - // FirePropertyChanged -- wrapper that calls INPC.PropertyChanged - protected virtual void FirePropertyChanged(string propertyName) - { - PropertyChangedEventHandler handler = PropertyChanged; - if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); - } - - // storage for Default Layout Models - private IList _defaultModels; - private CanvasLayoutModel _focusModel; - private GridLayoutModel _rowsModel; - private GridLayoutModel _columnsModel; - private GridLayoutModel _gridModel; - private GridLayoutModel _priorityGridModel; - private CanvasLayoutModel _blankCustomModel; - - private static readonly ushort c_focusModelId = 0xFFFF; - private static readonly ushort c_rowsModelId = 0xFFFE; - private static readonly ushort c_columnsModelId = 0xFFFD; - private static readonly ushort c_gridModelId = 0xFFFC; - private static readonly ushort c_priorityGridModelId = 0xFFFB; - private static readonly ushort c_blankCustomModelId = 0xFFFA; - private static readonly ushort c_lastPrefinedId = c_blankCustomModelId; - - // hard coded data for all the "Priority Grid" configurations that are unique to "Grid" - private static byte[][] s_priorityData = new byte[][] - { - new byte[] { 0, 0, 0, 0, 0, 1, 1, 39, 16, 39, 16, 0 }, - new byte[] { 0, 0, 0, 0, 0, 1, 2, 39, 16, 26, 11, 13, 5, 0, 1 }, - new byte[] { 0, 0, 0, 0, 0, 1, 3, 39, 16, 9, 196, 19, 136, 9, 196, 0, 1, 2 }, - new byte[] { 0, 0, 0, 0, 0, 2, 3, 19, 136, 19, 136, 9, 196, 19, 136, 9, 196, 0, 1, 2, 0, 1, 3 }, - new byte[] { 0, 0, 0, 0, 0, 2, 3, 19, 136, 19, 136, 9, 196, 19, 136, 9, 196, 0, 1, 2, 3, 1, 4 }, - new byte[] { 0, 0, 0, 0, 0, 3, 3, 13, 5, 13, 6, 13, 5, 9, 196, 19, 136, 9, 196, 0, 1, 2, 0, 1, 3, 4, 1, 5 }, - new byte[] { 0, 0, 0, 0, 0, 3, 3, 13, 5, 13, 6, 13, 5, 9, 196, 19, 136, 9, 196, 0, 1, 2, 3, 1, 4, 5, 1, 6 }, - new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 2, 7 }, - new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 7, 8 }, - new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 5, 6, 7, 1, 8, 9 }, - new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 5, 6, 7, 8, 9, 10 } - }; - - private const int c_multiplier = 10000; - } -} + + + public IList DefaultModels { get { return _defaultModels; } } + public ObservableCollection CustomModels + { + get + { + if (_customModels == null) + { + _customModels = LayoutModel.LoadCustomModels(); + _customModels.Insert(0, _blankCustomModel); + } + return _customModels; + } + } + private ObservableCollection _customModels; + + public static readonly string RegistryPath = "SOFTWARE\\SuperFancyZones"; + public static readonly string FullRegistryPath = "HKEY_CURRENT_USER\\" + RegistryPath; + + public static bool IsPredefinedLayout(LayoutModel model) + { + return (model.Id >= c_lastPrefinedId); + } + + // implementation of INotifyProeprtyChanged + public event PropertyChangedEventHandler PropertyChanged; + + // FirePropertyChanged -- wrapper that calls INPC.PropertyChanged + protected virtual void FirePropertyChanged(string propertyName) + { + PropertyChangedEventHandler handler = PropertyChanged; + if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); + } + + // storage for Default Layout Models + private IList _defaultModels; + private CanvasLayoutModel _focusModel; + private GridLayoutModel _rowsModel; + private GridLayoutModel _columnsModel; + private GridLayoutModel _gridModel; + private GridLayoutModel _priorityGridModel; + private CanvasLayoutModel _blankCustomModel; + + private static readonly ushort c_focusModelId = 0xFFFF; + private static readonly ushort c_rowsModelId = 0xFFFE; + private static readonly ushort c_columnsModelId = 0xFFFD; + private static readonly ushort c_gridModelId = 0xFFFC; + private static readonly ushort c_priorityGridModelId = 0xFFFB; + private static readonly ushort c_blankCustomModelId = 0xFFFA; + private static readonly ushort c_lastPrefinedId = c_blankCustomModelId; + + // hard coded data for all the "Priority Grid" configurations that are unique to "Grid" + private static byte[][] s_priorityData = new byte[][] + { + new byte[] { 0, 0, 0, 0, 0, 1, 1, 39, 16, 39, 16, 0 }, + new byte[] { 0, 0, 0, 0, 0, 1, 2, 39, 16, 26, 11, 13, 5, 0, 1 }, + new byte[] { 0, 0, 0, 0, 0, 1, 3, 39, 16, 9, 196, 19, 136, 9, 196, 0, 1, 2 }, + new byte[] { 0, 0, 0, 0, 0, 2, 3, 19, 136, 19, 136, 9, 196, 19, 136, 9, 196, 0, 1, 2, 0, 1, 3 }, + new byte[] { 0, 0, 0, 0, 0, 2, 3, 19, 136, 19, 136, 9, 196, 19, 136, 9, 196, 0, 1, 2, 3, 1, 4 }, + new byte[] { 0, 0, 0, 0, 0, 3, 3, 13, 5, 13, 6, 13, 5, 9, 196, 19, 136, 9, 196, 0, 1, 2, 0, 1, 3, 4, 1, 5 }, + new byte[] { 0, 0, 0, 0, 0, 3, 3, 13, 5, 13, 6, 13, 5, 9, 196, 19, 136, 9, 196, 0, 1, 2, 3, 1, 4, 5, 1, 6 }, + new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 2, 7 }, + new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 7, 8 }, + new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 5, 6, 7, 1, 8, 9 }, + new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 5, 6, 7, 8, 9, 10 } + }; + + private const int c_multiplier = 10000; + } +} diff --git a/src/modules/fancyzones/lib/FancyZones.cpp b/src/modules/fancyzones/lib/FancyZones.cpp index 6587694cdc..00f0a8449b 100644 --- a/src/modules/fancyzones/lib/FancyZones.cpp +++ b/src/modules/fancyzones/lib/FancyZones.cpp @@ -1,4 +1,5 @@ #include "pch.h" +#include "common/dpi_aware.h" struct FancyZones : public winrt::implements { @@ -244,11 +245,16 @@ void FancyZones::ToggleEditor() noexcept auto iter = m_zoneWindowMap.find(monitor); if (iter != m_zoneWindowMap.end()) { + UINT dpi_x = 96; + UINT dpi_y = 96; + DPIAware::GetScreenDPIForWindow(foregroundWindow, dpi_x, dpi_y); + const std::wstring params = iter->second->UniqueId() + L" " + std::to_wstring(iter->second->ActiveZoneSet()->LayoutId()) + L" " + std::to_wstring(reinterpret_cast(foregroundWindow)) + L" " + - std::to_wstring(reinterpret_cast(monitor)); + std::to_wstring(reinterpret_cast(monitor)) + L" " + + std::to_wstring(static_cast(dpi_x) / 96.0f); SHELLEXECUTEINFO sei{ sizeof(sei) }; sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI }; From c0cdf7aaa68545b32569b900e8f93d8bc1681464 Mon Sep 17 00:00:00 2001 From: Bret Anderson Date: Sun, 15 Sep 2019 13:34:00 -0700 Subject: [PATCH 4/7] Everything is working. --- src/modules/fancyzones/dll/dllmain.cpp | 18 +++------- .../FancyZonesEditor/Models/LayoutModel.cs | 3 +- .../FancyZonesEditor/Models/Settings.cs | 33 +++++++++++-------- src/modules/fancyzones/lib/FancyZones.cpp | 14 +++++++- src/modules/fancyzones/lib/ZoneWindow.cpp | 1 + src/modules/fancyzones/lib/ZoneWindow.h | 1 + 6 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/modules/fancyzones/dll/dllmain.cpp b/src/modules/fancyzones/dll/dllmain.cpp index a5d1a63158..19dd123748 100644 --- a/src/modules/fancyzones/dll/dllmain.cpp +++ b/src/modules/fancyzones/dll/dllmain.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include +#include #include #include #include @@ -27,29 +28,18 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReser return TRUE; } -// TODO: multimon support, need to pass the HMONITOR from the editor to here instead -// of using MonitorFromPoint // This function is exported and called from FancyZonesEditor.exe to save a layout from the editor. STDAPI PersistZoneSet( PCWSTR activeKey, // Registry key holding ActiveZoneSet + PCWSTR resolutionKey, // Registry key to persist ZoneSet to HMONITOR monitor, WORD layoutId, // LayoutModel Id int zoneCount, // Number of zones in zones int zones[]) // Array of zones serialized in left/top/right/bottom chunks { // See if we have already persisted this layout we can update. - std::wstringstream stream; - MONITORINFOEX mi; - mi.cbSize = sizeof(mi); - if (GetMonitorInfo(monitor, &mi)) - { - stream << (mi.rcMonitor.right - mi.rcMonitor.left) << "_"; - stream << (mi.rcMonitor.bottom - mi.rcMonitor.top); - } - - std::wstring resolutionKey(stream.str()); UUID id{GUID_NULL}; - if (wil::unique_hkey key{ RegistryHelpers::OpenKey(resolutionKey.c_str()) }) + if (wil::unique_hkey key{ RegistryHelpers::OpenKey(resolutionKey) }) { ZoneSetPersistedData data{}; DWORD dataSize = sizeof(data); @@ -84,7 +74,7 @@ STDAPI PersistZoneSet( id, layoutId, reinterpret_cast(monitor), - resolutionKey.c_str(), + resolutionKey, ZoneSetLayout::Custom, 0, 0, 0)); diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs b/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs index ddc1f94bef..f86f47439d 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/Models/LayoutModel.cs @@ -155,6 +155,7 @@ namespace FancyZonesEditor.Models internal delegate int PersistZoneSet( [MarshalAs(UnmanagedType.LPWStr)] string activeKey, + [MarshalAs(UnmanagedType.LPWStr)] string resolutionKey, uint monitor, ushort layoutId, int zoneCount, @@ -201,7 +202,7 @@ namespace FancyZonesEditor.Models } var persistZoneSet = Marshal.GetDelegateForFunctionPointer(pfn); - persistZoneSet(Settings.UniqueKey, Settings.Monitor, _id, zoneCount, zoneArray); + persistZoneSet(Settings.UniqueKey, Settings.WorkAreaKey, Settings.Monitor, _id, zoneCount, zoneArray); } private static readonly string c_registryPath = Settings.RegistryPath + "\\Layouts"; diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs b/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs index f5098f04ed..0f19c51703 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/Models/Settings.cs @@ -153,6 +153,12 @@ namespace FancyZonesEditor private static String _uniqueKey; private String _uniqueRegistryPath; + public static String WorkAreaKey + { + get { return _workAreaKey; } + } + private static String _workAreaKey; + public static float Dpi { get { return _dpi; } @@ -267,26 +273,27 @@ namespace FancyZonesEditor _dpi = 1; string[] args = Environment.GetCommandLineArgs(); - if (args.Length == 6) + if (args.Length == 7) { // 1 = unique key for per-monitor settings - // 2 = layoutid used to generate current layout - // 3 = handle to foreground window (used to figure out which monitor to show on) - // 4 = handle to monitor (passed back to engine to persist data) - // 5 = monitor DPI (float) + // 2 = layoutid used to generate current layout (used to pick the default layout to show) + // 3 = handle to monitor (passed back to engine to persist data) + // 4 = X_Y_Width_Height (where EditorOverlay shows up) + // 5 = resolution key (passed back to engine to persist data) + // 6 = monitor DPI (float) _uniqueKey = args[1]; _uniqueRegistryPath += "\\" + _uniqueKey; - var foregroundWindow = new IntPtr(uint.Parse(args[3])); - var screen = System.Windows.Forms.Screen.FromHandle(foregroundWindow); + var parsedLocation = args[4].Split('_'); + var x = int.Parse(parsedLocation[0]); + var y = int.Parse(parsedLocation[1]); + var width = int.Parse(parsedLocation[2]); + var height = int.Parse(parsedLocation[3]); - _dpi = float.Parse(args[5]); - _workArea = new Rect( - screen.WorkingArea.X / _dpi, - screen.WorkingArea.Y / _dpi, - screen.WorkingArea.Width / _dpi, - screen.WorkingArea.Height / _dpi); + _workAreaKey = args[5]; + _dpi = float.Parse(args[6]); + _workArea = new Rect(x, y, width, height); uint monitor = 0; if (uint.TryParse(args[4], out monitor)) diff --git a/src/modules/fancyzones/lib/FancyZones.cpp b/src/modules/fancyzones/lib/FancyZones.cpp index 00f0a8449b..0b578add72 100644 --- a/src/modules/fancyzones/lib/FancyZones.cpp +++ b/src/modules/fancyzones/lib/FancyZones.cpp @@ -249,11 +249,23 @@ void FancyZones::ToggleEditor() noexcept UINT dpi_y = 96; DPIAware::GetScreenDPIForWindow(foregroundWindow, dpi_x, dpi_y); + MONITORINFOEX mi; + mi.cbSize = sizeof(mi); + GetMonitorInfo(monitor, &mi); + + // Location that the editor should occupy, scaled by DPI + std::wstring editorLocation = + std::to_wstring(MulDiv(mi.rcWork.left, 96, dpi_x)) + L"_" + + std::to_wstring(MulDiv(mi.rcWork.top, 96, dpi_y)) + L"_" + + std::to_wstring(MulDiv(mi.rcWork.right - mi.rcWork.left, 96, dpi_x)) + L"_" + + std::to_wstring(MulDiv(mi.rcWork.bottom - mi.rcWork.top, 96, dpi_y)); + const std::wstring params = iter->second->UniqueId() + L" " + std::to_wstring(iter->second->ActiveZoneSet()->LayoutId()) + L" " + - std::to_wstring(reinterpret_cast(foregroundWindow)) + L" " + std::to_wstring(reinterpret_cast(monitor)) + L" " + + editorLocation + L" " + + iter->second->WorkAreaKey() + L" " + std::to_wstring(static_cast(dpi_x) / 96.0f); SHELLEXECUTEINFO sei{ sizeof(sei) }; diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index 8b2aaf76b6..d7b1666c7e 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -18,6 +18,7 @@ public: IFACEMETHODIMP_(void) CycleActiveZoneSet(DWORD vkCode) noexcept; IFACEMETHODIMP_(std::wstring) DeviceId() noexcept { return { m_deviceId.get() }; } IFACEMETHODIMP_(std::wstring) UniqueId() noexcept { return { m_uniqueId }; } + IFACEMETHODIMP_(std::wstring) WorkAreaKey() noexcept { return { m_workArea }; } IFACEMETHODIMP_(void) SaveWindowProcessToZoneIndex(HWND window) noexcept; IFACEMETHODIMP_(IZoneSet*) ActiveZoneSet() noexcept { return m_activeZoneSet.get(); } diff --git a/src/modules/fancyzones/lib/ZoneWindow.h b/src/modules/fancyzones/lib/ZoneWindow.h index 7979ee9216..566a520ee5 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.h +++ b/src/modules/fancyzones/lib/ZoneWindow.h @@ -16,6 +16,7 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow IFACEMETHOD_(void, SaveWindowProcessToZoneIndex)(HWND window) = 0; IFACEMETHOD_(std::wstring, DeviceId)() = 0; IFACEMETHOD_(std::wstring, UniqueId)() = 0; + IFACEMETHOD_(std::wstring, WorkAreaKey)() = 0; IFACEMETHOD_(IZoneSet*, ActiveZoneSet)() = 0; }; From 1078101631742a3f0ab82b22188d91113f9e4cc9 Mon Sep 17 00:00:00 2001 From: Bret Anderson Date: Sun, 15 Sep 2019 13:48:56 -0700 Subject: [PATCH 5/7] Fix for #292 (Zone Editor opens behind PowerToys Window) --- .../fancyzones/editor/FancyZonesEditor/EditorOverlay.xaml.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/EditorOverlay.xaml.cs b/src/modules/fancyzones/editor/FancyZonesEditor/EditorOverlay.xaml.cs index 9a83516ae1..31d6690cf8 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/EditorOverlay.xaml.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/EditorOverlay.xaml.cs @@ -94,6 +94,7 @@ namespace FancyZonesEditor MainWindow window = new MainWindow(); window.Owner = this; + window.ShowActivated = true; window.Show(); } From 2c3c4e7519ec270deb7a4c1f3d274c43a6cb1194 Mon Sep 17 00:00:00 2001 From: Bret Anderson Date: Mon, 16 Sep 2019 12:48:55 -0700 Subject: [PATCH 6/7] Need to adjust x/y by scaled diff between monitor and work area rect --- src/modules/fancyzones/lib/FancyZones.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/modules/fancyzones/lib/FancyZones.cpp b/src/modules/fancyzones/lib/FancyZones.cpp index 0b578add72..2e3d143556 100644 --- a/src/modules/fancyzones/lib/FancyZones.cpp +++ b/src/modules/fancyzones/lib/FancyZones.cpp @@ -253,10 +253,17 @@ void FancyZones::ToggleEditor() noexcept mi.cbSize = sizeof(mi); GetMonitorInfo(monitor, &mi); + // X/Y need to start in unscaled screen coordinates to get to the proper top/left of the monitor + // From there, we need to scale the difference between the monitor and workarea rects to get the + // appropriate offset where the overlay should appear. + // This covers the cases where the taskbar is not at the bottom of the screen. + const auto x = mi.rcMonitor.left + MulDiv(mi.rcWork.left - mi.rcMonitor.left, 96, dpi_x); + const auto y = mi.rcMonitor.top + MulDiv(mi.rcWork.top - mi.rcMonitor.top, 96, dpi_y); + // Location that the editor should occupy, scaled by DPI std::wstring editorLocation = - std::to_wstring(MulDiv(mi.rcWork.left, 96, dpi_x)) + L"_" + - std::to_wstring(MulDiv(mi.rcWork.top, 96, dpi_y)) + L"_" + + std::to_wstring(x) + L"_" + + std::to_wstring(y) + L"_" + std::to_wstring(MulDiv(mi.rcWork.right - mi.rcWork.left, 96, dpi_x)) + L"_" + std::to_wstring(MulDiv(mi.rcWork.bottom - mi.rcWork.top, 96, dpi_y)); From 209ec559127a3ca04409d4ac3ea5366b66276ef6 Mon Sep 17 00:00:00 2001 From: Bret Anderson Date: Tue, 17 Sep 2019 17:53:43 -0700 Subject: [PATCH 7/7] PR feedback --- src/modules/fancyzones/dll/dllmain.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/fancyzones/dll/dllmain.cpp b/src/modules/fancyzones/dll/dllmain.cpp index 19dd123748..6114b9a76f 100644 --- a/src/modules/fancyzones/dll/dllmain.cpp +++ b/src/modules/fancyzones/dll/dllmain.cpp @@ -1,6 +1,5 @@ #include "pch.h" #include -#include #include #include #include