From faf1fae8731648e01b1147ad97a4f71d1ab134c9 Mon Sep 17 00:00:00 2001 From: cedi Date: Sat, 28 Sep 2019 15:29:29 +0100 Subject: [PATCH] Modifying the startup behaviour of the FancyZones Layout Editor Add setting to allow to choose if the FZ editor opens in the screen where mouse cursor is or where the active windows is. --- src/common/dpi_aware.cpp | 12 ++ src/common/dpi_aware.h | 1 + src/modules/fancyzones/lib/FancyZones.cpp | 154 ++++++++++++---------- src/modules/fancyzones/lib/Settings.cpp | 3 +- src/modules/fancyzones/lib/Settings.h | 1 + src/modules/fancyzones/lib/fancyzones.rc | 1 + src/modules/fancyzones/lib/resource.h | 9 +- 7 files changed, 109 insertions(+), 72 deletions(-) diff --git a/src/common/dpi_aware.cpp b/src/common/dpi_aware.cpp index 55e8f4c9bb..25292d0772 100644 --- a/src/common/dpi_aware.cpp +++ b/src/common/dpi_aware.cpp @@ -14,6 +14,18 @@ HRESULT DPIAware::GetScreenDPIForWindow(HWND hwnd, UINT &dpi_x, UINT &dpi_y) { } } +HRESULT DPIAware::GetScreenDPIForPoint(POINT p, UINT& dpi_x, UINT& dpi_y) { + auto monitor_handle = MonitorFromPoint(p, MONITOR_DEFAULTTONEAREST); + dpi_x = 0; + dpi_y = 0; + if (monitor_handle != nullptr) { + return GetDpiForMonitor(monitor_handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y); + } + else { + return E_FAIL; + } +} + void DPIAware::Convert(HMONITOR monitor_handle, int &width, int &height) { if (monitor_handle == NULL) { const POINT ptZero = { 0, 0 }; diff --git a/src/common/dpi_aware.h b/src/common/dpi_aware.h index e4f5eeb3fb..47ba2e6644 100644 --- a/src/common/dpi_aware.h +++ b/src/common/dpi_aware.h @@ -7,5 +7,6 @@ private: public: static HRESULT GetScreenDPIForWindow(HWND hwnd, UINT & dpi_x, UINT & dpi_y); + static HRESULT GetScreenDPIForPoint(POINT p, UINT& dpi_x, UINT& dpi_y); static void Convert(HMONITOR monitor_handle, int &width, int &height); }; diff --git a/src/modules/fancyzones/lib/FancyZones.cpp b/src/modules/fancyzones/lib/FancyZones.cpp index efeb224528..1dc7d1a2fc 100644 --- a/src/modules/fancyzones/lib/FancyZones.cpp +++ b/src/modules/fancyzones/lib/FancyZones.cpp @@ -237,75 +237,95 @@ void FancyZones::ToggleEditor() noexcept m_terminateEditorEvent.reset(CreateEvent(nullptr, true, false, nullptr)); } - const HWND foregroundWindow = GetForegroundWindow(); - if (const HMONITOR monitor = MonitorFromWindow(foregroundWindow, MONITOR_DEFAULTTOPRIMARY)) + HMONITOR monitor{}; + UINT dpi_x = 96; + UINT dpi_y = 96; + + if (m_settings->GetSettings().use_cursorpos_editor_startupscreen) { - std::shared_lock readLock(m_lock); - 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); + POINT currentCursorPos{}; + GetCursorPos(¤tCursorPos); - MONITORINFOEX mi; - 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(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)); - - const std::wstring params = - iter->second->UniqueId() + L" " + - std::to_wstring(iter->second->ActiveZoneSet()->LayoutId()) + 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) }; - sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI }; - sei.lpFile = L"modules\\FancyZonesEditor.exe"; - sei.lpParameters = params.c_str(); - sei.nShow = SW_SHOWNORMAL; - ShellExecuteEx(&sei); - - // Launch the editor on a background thread - // Wait for the editor's process to exit - // Post back to the main thread to update - std::thread waitForEditorThread([window = m_window, processHandle = sei.hProcess, terminateEditorEvent = m_terminateEditorEvent.get()]() - { - HANDLE waitEvents[2] = { processHandle, terminateEditorEvent }; - auto result = WaitForMultipleObjects(2, waitEvents, false, INFINITE); - if (result == WAIT_OBJECT_0 + 0) - { - // Editor exited - // Update any changes it may have made - PostMessage(window, WM_PRIV_EDITOR, 0, static_cast(EditorExitKind::Exit)); - } - else if (result == WAIT_OBJECT_0 + 1) - { - // User hit Win+~ while editor is already running - // Shut it down - TerminateProcess(processHandle, 2); - PostMessage(window, WM_PRIV_EDITOR, 0, static_cast(EditorExitKind::Terminate)); - } - CloseHandle(processHandle); - }); - waitForEditorThread.detach(); - } + monitor = MonitorFromPoint(currentCursorPos, MONITOR_DEFAULTTOPRIMARY); + DPIAware::GetScreenDPIForPoint(currentCursorPos, dpi_x, dpi_y); } + else + { + const HWND foregroundWindow = GetForegroundWindow(); + monitor = MonitorFromWindow(foregroundWindow, MONITOR_DEFAULTTOPRIMARY); + DPIAware::GetScreenDPIForWindow(foregroundWindow, dpi_x, dpi_y); + } + + + if (!monitor) + { + return; + } + + std::shared_lock readLock(m_lock); + auto iter = m_zoneWindowMap.find(monitor); + if (iter == m_zoneWindowMap.end()) + { + return; + } + + MONITORINFOEX mi; + 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(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)); + + const std::wstring params = + iter->second->UniqueId() + L" " + + std::to_wstring(iter->second->ActiveZoneSet()->LayoutId()) + 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) }; + sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI }; + sei.lpFile = L"modules\\FancyZonesEditor.exe"; + sei.lpParameters = params.c_str(); + sei.nShow = SW_SHOWNORMAL; + ShellExecuteEx(&sei); + + // Launch the editor on a background thread + // Wait for the editor's process to exit + // Post back to the main thread to update + std::thread waitForEditorThread([window = m_window, processHandle = sei.hProcess, terminateEditorEvent = m_terminateEditorEvent.get()]() + { + HANDLE waitEvents[2] = { processHandle, terminateEditorEvent }; + auto result = WaitForMultipleObjects(2, waitEvents, false, INFINITE); + if (result == WAIT_OBJECT_0 + 0) + { + // Editor exited + // Update any changes it may have made + PostMessage(window, WM_PRIV_EDITOR, 0, static_cast(EditorExitKind::Exit)); + } + else if (result == WAIT_OBJECT_0 + 1) + { + // User hit Win+~ while editor is already running + // Shut it down + TerminateProcess(processHandle, 2); + PostMessage(window, WM_PRIV_EDITOR, 0, static_cast(EditorExitKind::Terminate)); + } + CloseHandle(processHandle); + }); + + waitForEditorThread.detach(); } // IZoneWindowHost @@ -723,4 +743,4 @@ void FancyZones::MoveSizeUpdateInternal(HMONITOR monitor, POINT const& ptScreen, winrt::com_ptr MakeFancyZones(HINSTANCE hinstance, IFancyZonesSettings* settings) noexcept { return winrt::make_self(hinstance, settings); -} +} \ No newline at end of file diff --git a/src/modules/fancyzones/lib/Settings.cpp b/src/modules/fancyzones/lib/Settings.cpp index ab35897508..6143324a04 100644 --- a/src/modules/fancyzones/lib/Settings.cpp +++ b/src/modules/fancyzones/lib/Settings.cpp @@ -32,7 +32,7 @@ private: PCWSTR name; bool* value; int resourceId; - } m_configBools[8] = { + } m_configBools[9] = { { L"fancyzones_shiftDrag", &m_settings.shiftDrag, IDS_SETTING_DESCRIPTION_SHIFTDRAG }, { L"fancyzones_overrideSnapHotkeys", &m_settings.overrideSnapHotkeys, IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS }, { L"fancyzones_zoneSetChange_flashZones", &m_settings.zoneSetChange_flashZones, IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES }, @@ -41,6 +41,7 @@ private: { L"fancyzones_virtualDesktopChange_moveWindows", &m_settings.virtualDesktopChange_moveWindows, IDS_SETTING_DESCRIPTION_VIRTUALDESKTOPCHANGE_MOVEWINDOWS }, { L"fancyzones_appLastZone_moveWindows", &m_settings.appLastZone_moveWindows, IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS }, { L"fancyzones_use_standalone_editor", &m_settings.use_standalone_editor, IDS_SETTING_DESCRIPTION_USE_STANDALONE_EDITOR }, + { L"use_cursorpos_editor_startupscreen", &m_settings.use_cursorpos_editor_startupscreen, IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN }, }; struct diff --git a/src/modules/fancyzones/lib/Settings.h b/src/modules/fancyzones/lib/Settings.h index 3483db0706..471bcc1988 100644 --- a/src/modules/fancyzones/lib/Settings.h +++ b/src/modules/fancyzones/lib/Settings.h @@ -13,6 +13,7 @@ struct Settings bool overrideSnapHotkeys = false; bool appLastZone_moveWindows = false; bool use_standalone_editor = true; + bool use_cursorpos_editor_startupscreen = true; std::wstring zoneHightlightColor = L"#0078D7"; }; diff --git a/src/modules/fancyzones/lib/fancyzones.rc b/src/modules/fancyzones/lib/fancyzones.rc index f92804df32..b2c2c6bad9 100644 --- a/src/modules/fancyzones/lib/fancyzones.rc +++ b/src/modules/fancyzones/lib/fancyzones.rc @@ -13,6 +13,7 @@ IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES "Flash zones when the active FancyZones layout changes" IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR "Zone Highlight Color (Default #0078D7)" IDS_SETTING_DESCRIPTION_USE_STANDALONE_EDITOR "Use new zone editing experience (Preview)" + IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN "Follow mouse cursor instead of focus when launching editor in a multi screen environment" IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS "Move newly created windows to their last known zone" IDS_SETTING_LAUNCH_EDITOR_LABEL "Zone configuration" IDS_SETTING_LAUNCH_EDITOR_BUTTON "Edit zones" diff --git a/src/modules/fancyzones/lib/resource.h b/src/modules/fancyzones/lib/resource.h index 6b68ee12fe..1b6fa1e798 100644 --- a/src/modules/fancyzones/lib/resource.h +++ b/src/modules/fancyzones/lib/resource.h @@ -7,7 +7,8 @@ #define IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR 107 #define IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS 108 #define IDS_SETTING_DESCRIPTION_USE_STANDALONE_EDITOR 109 -#define IDS_SETTING_DESCRIPTION 110 -#define IDS_SETTING_LAUNCH_EDITOR_LABEL 111 -#define IDS_SETTING_LAUNCH_EDITOR_BUTTON 112 -#define IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION 113 +#define IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN 110 +#define IDS_SETTING_DESCRIPTION 111 +#define IDS_SETTING_LAUNCH_EDITOR_LABEL 112 +#define IDS_SETTING_LAUNCH_EDITOR_BUTTON 113 +#define IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION 114