mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-12-05 04:39:08 +08:00
Editor should come up on the monitor with the foreground window. Defaults to primary monitor if there is no foreground window.
This commit is contained in:
parent
5f5402aa0a
commit
e562b29ecd
@ -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<BYTE*>(&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<BYTE*>(&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<HMONITOR>(monitor),
|
||||
resolutionKey.c_str(),
|
||||
ZoneSetLayout::Custom,
|
||||
0, 0, 0));
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for Window1.xaml
|
||||
/// </summary>
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for Window1.xaml
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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<Native.PersistZoneSet>(pfn);
|
||||
persistZoneSet(uniqueId, key, _id, zoneCount, zoneArray);
|
||||
persistZoneSet(uniqueId, monitor, _id, zoneCount, zoneArray);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<LayoutModel>(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()
|
||||
|
@ -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<UINT_PTR>(foregroundWindow)) + L" " +
|
||||
std::to_wstring(reinterpret_cast<UINT_PTR>(monitor));
|
||||
|
||||
SHELLEXECUTEINFO sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
||||
sei.lpFile = L"modules\\FancyZonesEditor.exe";
|
||||
|
Loading…
Reference in New Issue
Block a user