mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-12-12 02:09:24 +08:00
commit
b9b60a1346
10
.github/pull_request_template.md
vendored
10
.github/pull_request_template.md
vendored
@ -6,11 +6,11 @@
|
||||
|
||||
<!-- Please review the items on the PR checklist before submitting-->
|
||||
## PR Checklist
|
||||
* [ ] Closes #xxx
|
||||
* [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/PowerToys) and sign the CLA
|
||||
* [ ] Tests added/passed
|
||||
* [ ] Requires documentation to be updated
|
||||
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
|
||||
* [] Applies to #xxx
|
||||
* [] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/PowerToys) and sign the CLA
|
||||
* [] Tests added/passed
|
||||
* [] Requires documentation to be updated
|
||||
* [] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
|
||||
|
||||
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
|
||||
## Detailed Description of the Pull Request / Additional comments
|
||||
|
@ -6,7 +6,6 @@ The list below is the set of utilities we're considering and the rough priority
|
||||
|
||||
* Maximize to new desktop widget - The MTND widget shows a pop-up button when a user hovers over the maximize / restore button on any window. Clicking it creates a new desktop, sends the app to that desktop and maximizes the app on the new desktop.
|
||||
* [Process terminate tool](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/Terminate%20Spec.md)
|
||||
* [Batch file renamer](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/File%20Classification%20Spec.md)
|
||||
* [Animated gif screen recorder](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/GIF%20Maker%20Spec.md)
|
||||
|
||||
## Backlog
|
||||
|
@ -98,6 +98,7 @@
|
||||
<ClInclude Include="d2d_window.h" />
|
||||
<ClInclude Include="dpi_aware.h" />
|
||||
<ClInclude Include="monitors.h" />
|
||||
<ClInclude Include="on_thread_executor.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="settings_helpers.h" />
|
||||
<ClInclude Include="settings_objects.h" />
|
||||
@ -117,6 +118,7 @@
|
||||
<ClCompile Include="d2d_window.cpp" />
|
||||
<ClCompile Include="dpi_aware.cpp" />
|
||||
<ClCompile Include="monitors.cpp" />
|
||||
<ClCompile Include="on_thread_executor.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
|
@ -69,6 +69,9 @@
|
||||
<ClInclude Include="version.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="on_thread_executor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="d2d_svg.cpp">
|
||||
@ -108,5 +111,8 @@
|
||||
<ClCompile Include="dpi_aware.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="on_thread_executor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -37,4 +37,8 @@ void DPIAware::Convert(HMONITOR monitor_handle, int &width, int &height) {
|
||||
width = width * dpi_x / DEFAULT_DPI;
|
||||
height = height * dpi_y / DEFAULT_DPI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DPIAware::EnableDPIAwarenessForThisProcess() {
|
||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
#pragma once
|
||||
#include "windef.h"
|
||||
|
||||
class DPIAware {
|
||||
private:
|
||||
static const int DEFAULT_DPI = 96;
|
||||
struct DPIAware {
|
||||
static constexpr int DEFAULT_DPI = 96;
|
||||
|
||||
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);
|
||||
static void EnableDPIAwarenessForThisProcess();
|
||||
};
|
||||
|
38
src/common/on_thread_executor.cpp
Normal file
38
src/common/on_thread_executor.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "on_thread_executor.h"
|
||||
|
||||
OnThreadExecutor::OnThreadExecutor()
|
||||
:_worker_thread{[this]() { worker_thread(); }}
|
||||
{}
|
||||
|
||||
std::future<void> OnThreadExecutor::submit(task_t task) {
|
||||
auto future = task.get_future();
|
||||
std::lock_guard lock{_task_mutex};
|
||||
_task_queue.emplace(std::move(task));
|
||||
_task_cv.notify_one();
|
||||
return future;
|
||||
}
|
||||
|
||||
void OnThreadExecutor::worker_thread() {
|
||||
while(_active) {
|
||||
task_t task;
|
||||
{
|
||||
std::unique_lock task_lock{_task_mutex};
|
||||
_task_cv.wait(task_lock, [this] { return !_task_queue.empty() || !_active; });
|
||||
if(!_active) {
|
||||
break;
|
||||
}
|
||||
task = std::move(_task_queue.front());
|
||||
_task_queue.pop();
|
||||
}
|
||||
task();
|
||||
}
|
||||
}
|
||||
|
||||
OnThreadExecutor::~OnThreadExecutor() {
|
||||
_active = false;
|
||||
_task_cv.notify_one();
|
||||
_worker_thread.join();
|
||||
}
|
||||
|
30
src/common/on_thread_executor.h
Normal file
30
src/common/on_thread_executor.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <future>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <atomic>
|
||||
|
||||
// OnThreadExecutor allows its caller to off-load some work to a persistently running background thread.
|
||||
// This might come in handy if you use the API which sets thread-wide global state and the state needs
|
||||
// to be isolated.
|
||||
|
||||
class OnThreadExecutor final {
|
||||
public:
|
||||
using task_t = std::packaged_task<void()>;
|
||||
|
||||
OnThreadExecutor();
|
||||
~OnThreadExecutor();
|
||||
std::future<void> submit(task_t task);
|
||||
|
||||
private:
|
||||
void worker_thread();
|
||||
|
||||
std::thread _worker_thread;
|
||||
|
||||
std::mutex _task_mutex;
|
||||
std::condition_variable _task_cv;
|
||||
std::atomic_bool _active;
|
||||
std::queue<std::packaged_task<void()>> _task_queue;
|
||||
};
|
@ -220,6 +220,7 @@ private:
|
||||
void MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept;
|
||||
void MoveSizeUpdate(POINT const& ptScreen) noexcept;
|
||||
|
||||
HANDLE m_movedWindow = nullptr;
|
||||
winrt::com_ptr<IFancyZones> m_app;
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings;
|
||||
};
|
||||
@ -298,6 +299,7 @@ void FancyZonesModule::MoveSizeStart(HWND window, POINT const& ptScreen) noexcep
|
||||
{
|
||||
if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL))
|
||||
{
|
||||
m_movedWindow = window;
|
||||
m_app.as<IFancyZonesCallback>()->MoveSizeStart(window, monitor, ptScreen);
|
||||
}
|
||||
}
|
||||
@ -305,8 +307,9 @@ void FancyZonesModule::MoveSizeStart(HWND window, POINT const& ptScreen) noexcep
|
||||
|
||||
void FancyZonesModule::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept
|
||||
{
|
||||
if (IsInterestingWindow(window))
|
||||
if (IsInterestingWindow(window) || (window != nullptr && window == m_movedWindow))
|
||||
{
|
||||
m_movedWindow = nullptr;
|
||||
m_app.as<IFancyZonesCallback>()->MoveSizeEnd(window, ptScreen);
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,9 @@ namespace FancyZonesEditor
|
||||
/// </summary>
|
||||
public partial class MainWindow : MetroWindow
|
||||
{
|
||||
// TODO: share the constants b/w C# Editor and FancyZoneLib
|
||||
public static int MAX_ZONES = 40;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
@ -57,7 +60,7 @@ namespace FancyZonesEditor
|
||||
|
||||
private void IncrementZones_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_settings.ZoneCount < 40)
|
||||
if (_settings.ZoneCount < MAX_ZONES)
|
||||
{
|
||||
_settings.ZoneCount++;
|
||||
}
|
||||
|
@ -279,7 +279,7 @@ namespace FancyZonesEditor
|
||||
// 1 = unique key for per-monitor settings
|
||||
// 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)
|
||||
// 4 = X_Y_Width_Height in a dpi-scaled-but-unaware coords (where EditorOverlay shows up)
|
||||
// 5 = resolution key (passed back to engine to persist data)
|
||||
// 6 = monitor DPI (float)
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
#include "pch.h"
|
||||
#include "common/dpi_aware.h"
|
||||
#include "common/on_thread_executor.h"
|
||||
|
||||
struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZonesCallback, IZoneWindowHost>
|
||||
{
|
||||
public:
|
||||
FancyZones(HINSTANCE hinstance, IFancyZonesSettings* settings) noexcept
|
||||
: m_hinstance(hinstance)
|
||||
, m_settings(settings)
|
||||
{
|
||||
m_settings.attach(settings);
|
||||
m_settings->SetCallback(this);
|
||||
}
|
||||
|
||||
@ -84,10 +85,12 @@ private:
|
||||
bool m_dragEnabled{}; // True if we should be showing zone hints while dragging
|
||||
std::map<HMONITOR, winrt::com_ptr<IZoneWindow>> m_zoneWindowMap; // Map of monitor to ZoneWindow (one per monitor)
|
||||
winrt::com_ptr<IZoneWindow> m_zoneWindowMoveSize; // "Active" ZoneWindow, where the move/size is happening. Will update as drag moves between monitors.
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings;
|
||||
IFancyZonesSettings* m_settings{};
|
||||
GUID m_currentVirtualDesktopId{};
|
||||
wil::unique_handle m_terminateEditorEvent;
|
||||
|
||||
OnThreadExecutor m_dpiUnawareThread;
|
||||
|
||||
static UINT WM_PRIV_VDCHANGED;
|
||||
static UINT WM_PRIV_EDITOR;
|
||||
|
||||
@ -120,13 +123,18 @@ IFACEMETHODIMP_(void) FancyZones::Run() noexcept
|
||||
|
||||
RegisterHotKey(m_window, 1, m_settings->GetSettings().editorHotkey.get_modifiers(), m_settings->GetSettings().editorHotkey.get_code());
|
||||
VirtualDesktopChanged();
|
||||
|
||||
m_dpiUnawareThread.submit(OnThreadExecutor::task_t{[]{
|
||||
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
|
||||
SetThreadDpiHostingBehavior(DPI_HOSTING_BEHAVIOR_MIXED);
|
||||
}}).wait();
|
||||
}
|
||||
|
||||
// IFancyZones
|
||||
IFACEMETHODIMP_(void) FancyZones::Destroy() noexcept
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
|
||||
m_zoneWindowMap.clear();
|
||||
BufferedPaintUnInit();
|
||||
if (m_window)
|
||||
{
|
||||
@ -239,22 +247,22 @@ void FancyZones::ToggleEditor() noexcept
|
||||
}
|
||||
|
||||
HMONITOR monitor{};
|
||||
UINT dpi_x = 96;
|
||||
UINT dpi_y = 96;
|
||||
HWND foregroundWindow{};
|
||||
|
||||
if (m_settings->GetSettings().use_cursorpos_editor_startupscreen)
|
||||
UINT dpi_x = DPIAware::DEFAULT_DPI;
|
||||
UINT dpi_y = DPIAware::DEFAULT_DPI;
|
||||
|
||||
const bool use_cursorpos_editor_startupscreen = m_settings->GetSettings().use_cursorpos_editor_startupscreen;
|
||||
POINT currentCursorPos{};
|
||||
if (use_cursorpos_editor_startupscreen)
|
||||
{
|
||||
POINT currentCursorPos{};
|
||||
GetCursorPos(¤tCursorPos);
|
||||
|
||||
monitor = MonitorFromPoint(currentCursorPos, MONITOR_DEFAULTTOPRIMARY);
|
||||
DPIAware::GetScreenDPIForPoint(currentCursorPos, dpi_x, dpi_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
const HWND foregroundWindow = GetForegroundWindow();
|
||||
foregroundWindow = GetForegroundWindow();
|
||||
monitor = MonitorFromWindow(foregroundWindow, MONITOR_DEFAULTTOPRIMARY);
|
||||
DPIAware::GetScreenDPIForWindow(foregroundWindow, dpi_x, dpi_y);
|
||||
}
|
||||
|
||||
|
||||
@ -272,21 +280,33 @@ void FancyZones::ToggleEditor() noexcept
|
||||
|
||||
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);
|
||||
m_dpiUnawareThread.submit(OnThreadExecutor::task_t{[&]{
|
||||
GetMonitorInfo(monitor, &mi);
|
||||
}}).wait();
|
||||
|
||||
// Location that the editor should occupy, scaled by DPI
|
||||
std::wstring editorLocation =
|
||||
if(use_cursorpos_editor_startupscreen)
|
||||
{
|
||||
DPIAware::GetScreenDPIForPoint(currentCursorPos, dpi_x, dpi_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPIAware::GetScreenDPIForWindow(foregroundWindow, dpi_x, dpi_y);
|
||||
}
|
||||
|
||||
const auto taskbar_x_offset = MulDiv(mi.rcWork.left - mi.rcMonitor.left, DPIAware::DEFAULT_DPI, dpi_x);
|
||||
const auto taskbar_y_offset = MulDiv(mi.rcWork.top - mi.rcMonitor.top, DPIAware::DEFAULT_DPI, dpi_y);
|
||||
|
||||
// Do not scale window params by the dpi, that will be done in the editor - see LayoutModel.Apply
|
||||
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(MulDiv(mi.rcWork.right - mi.rcWork.left, 96, dpi_x)) + L"_" +
|
||||
std::to_wstring(MulDiv(mi.rcWork.bottom - mi.rcWork.top, 96, dpi_y));
|
||||
std::to_wstring(width) + L"_" +
|
||||
std::to_wstring(height);
|
||||
|
||||
const std::wstring params =
|
||||
iter->second->UniqueId() + L" " +
|
||||
@ -294,7 +314,7 @@ void FancyZones::ToggleEditor() noexcept
|
||||
std::to_wstring(reinterpret_cast<UINT_PTR>(monitor)) + L" " +
|
||||
editorLocation + L" " +
|
||||
iter->second->WorkAreaKey() + L" " +
|
||||
std::to_wstring(static_cast<float>(dpi_x) / 96.0f);
|
||||
std::to_wstring(static_cast<float>(dpi_x) / DPIAware::DEFAULT_DPI);
|
||||
|
||||
SHELLEXECUTEINFO sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
||||
@ -652,34 +672,40 @@ void FancyZones::MoveSizeStartInternal(HWND window, HMONITOR monitor, POINT cons
|
||||
RECT windowRect{};
|
||||
::GetWindowRect(window, &windowRect);
|
||||
|
||||
windowRect.top += 6;
|
||||
windowRect.left += 8;
|
||||
windowRect.right -= 8;
|
||||
windowRect.bottom -= 6;
|
||||
const auto padding_x = 8;
|
||||
const auto padding_y = 6;
|
||||
windowRect.top += padding_y;
|
||||
windowRect.left += padding_x;
|
||||
windowRect.right -= padding_x;
|
||||
windowRect.bottom -= padding_y;
|
||||
|
||||
if (PtInRect(&windowRect, ptScreen))
|
||||
if (PtInRect(&windowRect, ptScreen) == FALSE)
|
||||
{
|
||||
m_inMoveSize = true;
|
||||
return;
|
||||
}
|
||||
|
||||
auto iter = m_zoneWindowMap.find(monitor);
|
||||
if (iter != m_zoneWindowMap.end())
|
||||
{
|
||||
m_windowMoveSize = window;
|
||||
m_inMoveSize = true;
|
||||
|
||||
// This updates m_dragEnabled depending on if the shift key is being held down.
|
||||
UpdateDragState(writeLock);
|
||||
auto iter = m_zoneWindowMap.find(monitor);
|
||||
if (iter == end(m_zoneWindowMap))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_dragEnabled)
|
||||
{
|
||||
m_zoneWindowMoveSize = iter->second;
|
||||
m_zoneWindowMoveSize->MoveSizeEnter(window, m_dragEnabled);
|
||||
}
|
||||
else if (m_zoneWindowMoveSize)
|
||||
{
|
||||
m_zoneWindowMoveSize->MoveSizeCancel();
|
||||
m_zoneWindowMoveSize = nullptr;
|
||||
}
|
||||
}
|
||||
m_windowMoveSize = window;
|
||||
|
||||
// This updates m_dragEnabled depending on if the shift key is being held down.
|
||||
UpdateDragState(writeLock);
|
||||
|
||||
if (m_dragEnabled)
|
||||
{
|
||||
m_zoneWindowMoveSize = iter->second;
|
||||
m_zoneWindowMoveSize->MoveSizeEnter(window, m_dragEnabled);
|
||||
}
|
||||
else if (m_zoneWindowMoveSize)
|
||||
{
|
||||
m_zoneWindowMoveSize->MoveSizeCancel();
|
||||
m_zoneWindowMoveSize = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ public:
|
||||
LoadSettings(name, true /*fromFile*/);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void) SetCallback(IFancyZonesCallback* callback) { m_callback.attach(callback); }
|
||||
IFACEMETHODIMP_(void) SetCallback(IFancyZonesCallback* callback) { m_callback = callback; }
|
||||
IFACEMETHODIMP_(bool) GetConfig(_Out_ PWSTR buffer, _Out_ int *buffer_sizeg) noexcept;
|
||||
IFACEMETHODIMP_(void) SetConfig(PCWSTR config) noexcept;
|
||||
IFACEMETHODIMP_(void) CallCustomAction(PCWSTR action) noexcept;
|
||||
@ -21,7 +21,7 @@ private:
|
||||
void LoadSettings(PCWSTR config, bool fromFile) noexcept;
|
||||
void SaveSettings() noexcept;
|
||||
|
||||
winrt::com_ptr<IFancyZonesCallback> m_callback;
|
||||
IFancyZonesCallback* m_callback{};
|
||||
const HINSTANCE m_hinstance;
|
||||
PCWSTR m_name{};
|
||||
|
||||
|
@ -34,13 +34,15 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
|
||||
#define VERSION_PERSISTEDDATA 0x0000F00D
|
||||
struct ZoneSetPersistedData
|
||||
{
|
||||
static constexpr inline size_t MAX_ZONES = 40;
|
||||
|
||||
DWORD Version{VERSION_PERSISTEDDATA};
|
||||
WORD LayoutId{};
|
||||
DWORD ZoneCount{};
|
||||
ZoneSetLayout Layout{};
|
||||
DWORD PaddingInner{};
|
||||
DWORD PaddingOuter{};
|
||||
RECT Zones[40]{};
|
||||
RECT Zones[MAX_ZONES]{};
|
||||
};
|
||||
|
||||
struct ZoneSetConfig
|
||||
|
@ -1,4 +1,6 @@
|
||||
#include "pch.h"
|
||||
#include <common/dpi_aware.h>
|
||||
|
||||
#include <ShellScalingApi.h>
|
||||
|
||||
struct ZoneWindow : public winrt::implements<ZoneWindow, IZoneWindow>
|
||||
@ -116,78 +118,79 @@ ZoneWindow::ZoneWindow(
|
||||
|
||||
MONITORINFO mi{};
|
||||
mi.cbSize = sizeof(mi);
|
||||
if (GetMonitorInfoW(m_monitor, &mi))
|
||||
if (!GetMonitorInfoW(m_monitor, &mi))
|
||||
{
|
||||
const UINT dpi = GetDpiForMonitor();
|
||||
const Rect monitorRect(mi.rcMonitor);
|
||||
const Rect workAreaRect(mi.rcWork, dpi);
|
||||
return;
|
||||
}
|
||||
const UINT dpi = GetDpiForMonitor();
|
||||
const Rect monitorRect(mi.rcMonitor);
|
||||
const Rect workAreaRect(mi.rcWork, dpi);
|
||||
|
||||
StringCchPrintf(m_workArea, ARRAYSIZE(m_workArea), L"%d_%d", monitorRect.width(), monitorRect.height());
|
||||
StringCchPrintf(m_workArea, ARRAYSIZE(m_workArea), L"%d_%d", monitorRect.width(), monitorRect.height());
|
||||
|
||||
InitializeId(deviceId, virtualDesktopId);
|
||||
LoadSettings();
|
||||
InitializeZoneSets();
|
||||
InitializeId(deviceId, virtualDesktopId);
|
||||
LoadSettings();
|
||||
InitializeZoneSets();
|
||||
|
||||
WNDCLASSEXW wcex{};
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
wcex.lpfnWndProc = s_WndProc;
|
||||
wcex.hInstance = hinstance;
|
||||
wcex.lpszClassName = L"SuperFancyZones_ZoneWindow";
|
||||
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
|
||||
RegisterClassExW(&wcex);
|
||||
WNDCLASSEXW wcex{};
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
wcex.lpfnWndProc = s_WndProc;
|
||||
wcex.hInstance = hinstance;
|
||||
wcex.lpszClassName = L"SuperFancyZones_ZoneWindow";
|
||||
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
|
||||
RegisterClassExW(&wcex);
|
||||
|
||||
m_window = wil::unique_hwnd {
|
||||
CreateWindowExW(WS_EX_TOOLWINDOW, L"SuperFancyZones_ZoneWindow", L"", WS_POPUP,
|
||||
m_window = wil::unique_hwnd {
|
||||
CreateWindowExW(WS_EX_TOOLWINDOW, L"SuperFancyZones_ZoneWindow", L"", WS_POPUP,
|
||||
workAreaRect.left(), workAreaRect.top(), workAreaRect.width(), workAreaRect.height(),
|
||||
nullptr, nullptr, hinstance, this)
|
||||
};
|
||||
};
|
||||
|
||||
if (m_window)
|
||||
if (m_window)
|
||||
{
|
||||
MakeWindowTransparent(m_window.get());
|
||||
UpdateGrid(0, 0);
|
||||
if (flashZones)
|
||||
{
|
||||
MakeWindowTransparent(m_window.get());
|
||||
UpdateGrid(0, 0);
|
||||
if (flashZones)
|
||||
{
|
||||
FlashZones();
|
||||
}
|
||||
FlashZones();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ZoneWindow::ShowZoneWindow(bool activate, bool fadeIn) noexcept
|
||||
{
|
||||
if (m_window)
|
||||
if (!m_window)
|
||||
{
|
||||
m_flashMode = false;
|
||||
|
||||
UINT flags = SWP_NOSIZE | SWP_NOMOVE;
|
||||
if (!activate)
|
||||
{
|
||||
WI_SetFlag(flags, SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
if (!fadeIn)
|
||||
{
|
||||
WI_SetFlag(flags, SWP_SHOWWINDOW);
|
||||
}
|
||||
|
||||
HWND windowInsertAfter = m_windowMoveSize;
|
||||
if (windowInsertAfter == nullptr)
|
||||
{
|
||||
windowInsertAfter = HWND_TOPMOST;
|
||||
}
|
||||
|
||||
SetWindowPos(m_window.get(), windowInsertAfter, 0, 0, 0, 0, flags);
|
||||
|
||||
if (fadeIn)
|
||||
{
|
||||
AnimateWindow(m_window.get(), m_showAnimationDuration, AW_BLEND);
|
||||
InvalidateRect(m_window.get(), nullptr, true);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return E_FAIL;
|
||||
}
|
||||
return E_FAIL;
|
||||
|
||||
m_flashMode = false;
|
||||
|
||||
UINT flags = SWP_NOSIZE | SWP_NOMOVE;
|
||||
if (!activate)
|
||||
{
|
||||
WI_SetFlag(flags, SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
if (!fadeIn)
|
||||
{
|
||||
WI_SetFlag(flags, SWP_SHOWWINDOW);
|
||||
}
|
||||
|
||||
HWND windowInsertAfter = m_windowMoveSize;
|
||||
if (windowInsertAfter == nullptr)
|
||||
{
|
||||
windowInsertAfter = HWND_TOPMOST;
|
||||
}
|
||||
|
||||
SetWindowPos(m_window.get(), windowInsertAfter, 0, 0, 0, 0, flags);
|
||||
|
||||
if (fadeIn)
|
||||
{
|
||||
AnimateWindow(m_window.get(), m_showAnimationDuration, AW_BLEND);
|
||||
InvalidateRect(m_window.get(), nullptr, true);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ZoneWindow::HideZoneWindow() noexcept
|
||||
@ -356,54 +359,56 @@ void ZoneWindow::InitializeZoneSets() noexcept
|
||||
|
||||
void ZoneWindow::LoadZoneSetsFromRegistry() noexcept
|
||||
{
|
||||
if (wil::unique_hkey key{ RegistryHelpers::OpenKey(m_workArea) })
|
||||
wil::unique_hkey key{RegistryHelpers::OpenKey(m_workArea)};
|
||||
if (!key)
|
||||
{
|
||||
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)
|
||||
return;
|
||||
}
|
||||
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.Version == VERSION_PERSISTEDDATA)
|
||||
{
|
||||
if (data.Version == VERSION_PERSISTEDDATA)
|
||||
GUID zoneSetId;
|
||||
if (SUCCEEDED_LOG(CLSIDFromString(value, &zoneSetId)))
|
||||
{
|
||||
GUID zoneSetId;
|
||||
if (SUCCEEDED_LOG(CLSIDFromString(value, &zoneSetId)))
|
||||
auto zoneSet = MakeZoneSet(ZoneSetConfig(
|
||||
zoneSetId,
|
||||
data.LayoutId,
|
||||
m_monitor,
|
||||
m_workArea,
|
||||
data.Layout,
|
||||
0,
|
||||
static_cast<int>(data.PaddingInner),
|
||||
static_cast<int>(data.PaddingOuter)));
|
||||
|
||||
if (zoneSet)
|
||||
{
|
||||
auto zoneSet = MakeZoneSet(ZoneSetConfig(
|
||||
zoneSetId,
|
||||
data.LayoutId,
|
||||
m_monitor,
|
||||
m_workArea,
|
||||
data.Layout,
|
||||
0,
|
||||
static_cast<int>(data.PaddingInner),
|
||||
static_cast<int>(data.PaddingOuter)));
|
||||
|
||||
if (zoneSet)
|
||||
for (UINT j = 0; j < data.ZoneCount; j++)
|
||||
{
|
||||
for (UINT j = 0; j < data.ZoneCount; j++)
|
||||
{
|
||||
zoneSet->AddZone(MakeZone(data.Zones[j]), false);
|
||||
}
|
||||
|
||||
m_zoneSets.emplace_back(zoneSet);
|
||||
|
||||
if (zoneSetId == m_activeZoneSetId)
|
||||
{
|
||||
UpdateActiveZoneSet(zoneSet.get());
|
||||
}
|
||||
zoneSet->AddZone(MakeZone(data.Zones[j]), false);
|
||||
}
|
||||
|
||||
if (zoneSetId == m_activeZoneSetId)
|
||||
{
|
||||
UpdateActiveZoneSet(zoneSet.get());
|
||||
}
|
||||
|
||||
m_zoneSets.emplace_back(std::move(zoneSet));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Migrate from older settings format
|
||||
}
|
||||
|
||||
valueLength = ARRAYSIZE(value);
|
||||
dataSize = sizeof(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Migrate from older settings format
|
||||
}
|
||||
|
||||
valueLength = ARRAYSIZE(value);
|
||||
dataSize = sizeof(data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -716,37 +721,38 @@ void ZoneWindow::DrawZone(wil::unique_hdc& hdc, ColorSetting const& colorSetting
|
||||
}
|
||||
FillRectARGB(hdc, &zoneRect, colorSetting.fillAlpha, colorSetting.fill, false);
|
||||
|
||||
if (!m_flashMode)
|
||||
if (m_flashMode)
|
||||
{
|
||||
COLORREF const colorFill = RGB(255, 255, 255);
|
||||
|
||||
size_t const index = zone->Id();
|
||||
int const padding = 5;
|
||||
int const size = 10;
|
||||
POINT offset = { zoneRect.left + padding, zoneRect.top + padding };
|
||||
if (!IsOccluded(offset, index))
|
||||
{
|
||||
DrawIndex(hdc, offset, index, padding, size, false, false, colorFill); // top left
|
||||
return;
|
||||
}
|
||||
|
||||
offset.x = zoneRect.right - ((padding + size) * 3);
|
||||
if (!IsOccluded(offset, index))
|
||||
{
|
||||
DrawIndex(hdc, offset, index, padding, size, true, false, colorFill); // top right
|
||||
return;
|
||||
}
|
||||
|
||||
offset.y = zoneRect.bottom - ((padding + size) * 3);
|
||||
if (!IsOccluded(offset, index))
|
||||
{
|
||||
DrawIndex(hdc, offset, index, padding, size, true, true, colorFill); // bottom right
|
||||
return;
|
||||
}
|
||||
|
||||
offset.x = zoneRect.left + padding;
|
||||
DrawIndex(hdc, offset, index, padding, size, false, true, colorFill); // bottom left
|
||||
return;
|
||||
}
|
||||
COLORREF const colorFill = RGB(255, 255, 255);
|
||||
|
||||
size_t const index = zone->Id();
|
||||
int const padding = 5;
|
||||
int const size = 10;
|
||||
POINT offset = { zoneRect.left + padding, zoneRect.top + padding };
|
||||
if (!IsOccluded(offset, index))
|
||||
{
|
||||
DrawIndex(hdc, offset, index, padding, size, false, false, colorFill); // top left
|
||||
return;
|
||||
}
|
||||
|
||||
offset.x = zoneRect.right - ((padding + size) * 3);
|
||||
if (!IsOccluded(offset, index))
|
||||
{
|
||||
DrawIndex(hdc, offset, index, padding, size, true, false, colorFill); // top right
|
||||
return;
|
||||
}
|
||||
|
||||
offset.y = zoneRect.bottom - ((padding + size) * 3);
|
||||
if (!IsOccluded(offset, index))
|
||||
{
|
||||
DrawIndex(hdc, offset, index, padding, size, true, true, colorFill); // bottom right
|
||||
return;
|
||||
}
|
||||
|
||||
offset.x = zoneRect.left + padding;
|
||||
DrawIndex(hdc, offset, index, padding, size, false, true, colorFill); // bottom left
|
||||
}
|
||||
|
||||
void ZoneWindow::DrawIndex(wil::unique_hdc& hdc, POINT offset, size_t index, int padding, int size, bool flipX, bool flipY, COLORREF colorFill)
|
||||
@ -817,33 +823,36 @@ void ZoneWindow::DrawActiveZoneSet(wil::unique_hdc& hdc, RECT const& clientRect)
|
||||
ColorSetting const colorFlash { 200, RGB(81, 92, 107), 200, RGB(104, 118, 138), -2 };
|
||||
|
||||
auto zones = m_activeZoneSet->GetZones();
|
||||
size_t colorIndex = zones.size() - 1;
|
||||
const size_t maxColorIndex = min(size(zones) - 1, size(colors) - 1);
|
||||
size_t colorIndex = maxColorIndex;
|
||||
for (auto iter = zones.rbegin(); iter != zones.rend(); iter++)
|
||||
{
|
||||
if (winrt::com_ptr<IZone> zone = iter->try_as<IZone>())
|
||||
winrt::com_ptr<IZone> zone = iter->try_as<IZone>();
|
||||
if (!zone)
|
||||
{
|
||||
if (zone != m_highlightZone)
|
||||
{
|
||||
if (m_flashMode)
|
||||
{
|
||||
DrawZone(hdc, colorFlash, zone);
|
||||
}
|
||||
else if (m_drawHints)
|
||||
{
|
||||
DrawZone(hdc, colorHints, zone);
|
||||
}
|
||||
else if (m_editorMode)
|
||||
{
|
||||
DrawZone(hdc, colorEditorMode, zone);
|
||||
}
|
||||
else
|
||||
{
|
||||
colorViewer.fill = colors[colorIndex];
|
||||
DrawZone(hdc, colorViewer, zone);
|
||||
}
|
||||
}
|
||||
colorIndex--;
|
||||
continue;
|
||||
}
|
||||
if (zone != m_highlightZone)
|
||||
{
|
||||
if (m_flashMode)
|
||||
{
|
||||
DrawZone(hdc, colorFlash, zone);
|
||||
}
|
||||
else if (m_drawHints)
|
||||
{
|
||||
DrawZone(hdc, colorHints, zone);
|
||||
}
|
||||
else if (m_editorMode)
|
||||
{
|
||||
DrawZone(hdc, colorEditorMode, zone);
|
||||
}
|
||||
else
|
||||
{
|
||||
colorViewer.fill = colors[colorIndex];
|
||||
DrawZone(hdc, colorViewer, zone);
|
||||
}
|
||||
}
|
||||
colorIndex = colorIndex != 0 ? colorIndex - 1 : maxColorIndex;
|
||||
}
|
||||
|
||||
if (m_highlightZone)
|
||||
@ -930,7 +939,7 @@ void ZoneWindow::OnPaint(wil::unique_hdc& hdc) noexcept
|
||||
RECT clientRect;
|
||||
GetClientRect(m_window.get(), &clientRect);
|
||||
|
||||
wil::unique_hdc hdcMem;;
|
||||
wil::unique_hdc hdcMem;
|
||||
HPAINTBUFFER bufferedPaint = BeginBufferedPaint(hdc.get(), &clientRect, BPBF_TOPDOWNDIB, nullptr, &hdcMem);
|
||||
if (bufferedPaint)
|
||||
{
|
||||
@ -1284,7 +1293,7 @@ UINT ZoneWindow::GetDpiForMonitor() noexcept
|
||||
}
|
||||
}
|
||||
|
||||
return (dpi == 0) ? 96 : dpi;
|
||||
return (dpi == 0) ? DPIAware::DEFAULT_DPI : dpi;
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
|
@ -18,7 +18,16 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent system-wide input lagging while paused in the debugger
|
||||
//#define DISABLE_LOWLEVEL_KBHOOK_WHEN_DEBUGGED
|
||||
|
||||
void start_lowlevel_keyboard_hook() {
|
||||
#if defined(_DEBUG) && defined(DISABLE_LOWLEVEL_KBHOOK_WHEN_DEBUGGED)
|
||||
if(IsDebuggerPresent()) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!hook_handle) {
|
||||
hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, hook_proc, GetModuleHandle(NULL), NULL);
|
||||
hook_handle_copy = hook_handle;
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "trace.h"
|
||||
#include "general_settings.h"
|
||||
|
||||
#include <common/dpi_aware.h>
|
||||
|
||||
#if _DEBUG && _WIN64
|
||||
#include "unhandled_exception_handler.h"
|
||||
#endif
|
||||
@ -31,6 +33,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
// The app is already running
|
||||
return 0;
|
||||
}
|
||||
|
||||
DPIAware::EnableDPIAwarenessForThisProcess();
|
||||
|
||||
#if _DEBUG && _WIN64
|
||||
//Global error handlers to diagnose errors.
|
||||
|
@ -67,7 +67,7 @@
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
|
||||
<EnableDpiAwareness>false</EnableDpiAwareness>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@ -92,7 +92,7 @@
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
|
||||
<EnableDpiAwareness>false</EnableDpiAwareness>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
@ -60,6 +60,7 @@
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalOptions>/Zm150 %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<CustomBuildStep>
|
||||
<Command>
|
||||
@ -88,6 +89,7 @@
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalOptions>/Zm150 %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
|
Loading…
Reference in New Issue
Block a user