mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-07 09:28:03 +08:00
[AlwaysOnTop] Improve performance and power consumption (#15993)
This commit is contained in:
parent
ddf96e28b8
commit
3e7b04891d
3
.github/actions/spell-check/expect.txt
vendored
3
.github/actions/spell-check/expect.txt
vendored
@ -488,6 +488,7 @@ DQTYPE
|
|||||||
DRAWFRAME
|
DRAWFRAME
|
||||||
drawingcolor
|
drawingcolor
|
||||||
dreamsofameaningfullife
|
dreamsofameaningfullife
|
||||||
|
DRect
|
||||||
drivedetectionwarning
|
drivedetectionwarning
|
||||||
dshow
|
dshow
|
||||||
dst
|
dst
|
||||||
@ -1194,6 +1195,7 @@ mdpreviewhandler
|
|||||||
MEDIASUBTYPE
|
MEDIASUBTYPE
|
||||||
mediatype
|
mediatype
|
||||||
Melman
|
Melman
|
||||||
|
memcmp
|
||||||
memcpy
|
memcpy
|
||||||
memset
|
memset
|
||||||
MENUITEMINFO
|
MENUITEMINFO
|
||||||
@ -2103,6 +2105,7 @@ uap
|
|||||||
udit
|
udit
|
||||||
Udp
|
Udp
|
||||||
uefi
|
uefi
|
||||||
|
UHash
|
||||||
UIA
|
UIA
|
||||||
Uid
|
Uid
|
||||||
uint
|
uint
|
||||||
|
@ -1,6 +1,18 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
|
||||||
#include "FrameDrawer.h"
|
#include "FrameDrawer.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
size_t D2DRectUHash(D2D1_SIZE_U rect)
|
||||||
|
{
|
||||||
|
using pod_repr_t = uint64_t;
|
||||||
|
static_assert(sizeof(D2D1_SIZE_U) == sizeof(pod_repr_t));
|
||||||
|
std::hash<pod_repr_t> hasher{};
|
||||||
|
return hasher(*reinterpret_cast<const pod_repr_t*>(&rect));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<FrameDrawer> FrameDrawer::Create(HWND window)
|
std::unique_ptr<FrameDrawer> FrameDrawer::Create(HWND window)
|
||||||
{
|
{
|
||||||
auto self = std::make_unique<FrameDrawer>(window);
|
auto self = std::make_unique<FrameDrawer>(window);
|
||||||
@ -12,63 +24,55 @@ std::unique_ptr<FrameDrawer> FrameDrawer::Create(HWND window)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameDrawer::FrameDrawer(FrameDrawer&& other) :
|
|
||||||
m_window(other.m_window),
|
|
||||||
m_renderTarget(std::move(other.m_renderTarget)),
|
|
||||||
m_sceneRect(std::move(other.m_sceneRect)),
|
|
||||||
m_renderThread(std::move(m_renderThread))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
FrameDrawer::FrameDrawer(HWND window) :
|
FrameDrawer::FrameDrawer(HWND window) :
|
||||||
m_window(window), m_renderTarget(nullptr)
|
m_window(window)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameDrawer::~FrameDrawer()
|
bool FrameDrawer::CreateRenderTargets(const RECT& clientRect)
|
||||||
{
|
{
|
||||||
m_abortThread = true;
|
HRESULT hr;
|
||||||
m_renderThread.join();
|
|
||||||
|
|
||||||
if (m_renderTarget)
|
constexpr float DPI = 96.f; // Always using the default in DPI-aware mode
|
||||||
|
const auto renderTargetProperties = D2D1::RenderTargetProperties(
|
||||||
|
D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
||||||
|
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
|
||||||
|
DPI,
|
||||||
|
DPI);
|
||||||
|
|
||||||
|
const auto renderTargetSize = D2D1::SizeU(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top);
|
||||||
|
const auto rectHash = D2DRectUHash(renderTargetSize);
|
||||||
|
if (m_renderTarget && rectHash == m_renderTargetSizeHash)
|
||||||
{
|
{
|
||||||
m_renderTarget->Release();
|
// Already at the desired size -> do nothing
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_renderTarget = nullptr;
|
||||||
|
|
||||||
|
const auto hwndRenderTargetProperties = D2D1::HwndRenderTargetProperties(m_window, renderTargetSize, D2D1_PRESENT_OPTIONS_NONE);
|
||||||
|
|
||||||
|
hr = GetD2DFactory()->CreateHwndRenderTarget(renderTargetProperties, hwndRenderTargetProperties, m_renderTarget.put());
|
||||||
|
|
||||||
|
if (!SUCCEEDED(hr) || !m_renderTarget)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_renderTargetSizeHash = rectHash;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameDrawer::Init()
|
bool FrameDrawer::Init()
|
||||||
{
|
{
|
||||||
RECT clientRect;
|
RECT clientRect;
|
||||||
|
|
||||||
// Obtain the size of the drawing area.
|
|
||||||
if (!GetClientRect(m_window, &clientRect))
|
if (!GetClientRect(m_window, &clientRect))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT hr;
|
return CreateRenderTargets(clientRect);
|
||||||
|
|
||||||
// Create a Direct2D render target
|
|
||||||
// We should always use the DPI value of 96 since we're running in DPI aware mode
|
|
||||||
auto renderTargetProperties = D2D1::RenderTargetProperties(
|
|
||||||
D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
|
||||||
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
|
|
||||||
96.f,
|
|
||||||
96.f);
|
|
||||||
|
|
||||||
auto renderTargetSize = D2D1::SizeU(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top);
|
|
||||||
auto hwndRenderTargetProperties = D2D1::HwndRenderTargetProperties(m_window, renderTargetSize);
|
|
||||||
|
|
||||||
hr = GetD2DFactory()->CreateHwndRenderTarget(renderTargetProperties, hwndRenderTargetProperties, &m_renderTarget);
|
|
||||||
|
|
||||||
if (!SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_renderThread = std::thread([this]() { RenderLoop(); });
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameDrawer::Hide()
|
void FrameDrawer::Hide()
|
||||||
@ -79,19 +83,64 @@ void FrameDrawer::Hide()
|
|||||||
void FrameDrawer::Show()
|
void FrameDrawer::Show()
|
||||||
{
|
{
|
||||||
ShowWindow(m_window, SW_SHOWNA);
|
ShowWindow(m_window, SW_SHOWNA);
|
||||||
|
Render();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameDrawer::SetBorderRect(RECT windowRect, COLORREF color, float thickness)
|
void FrameDrawer::SetBorderRect(RECT windowRect, COLORREF color, float thickness)
|
||||||
{
|
{
|
||||||
std::unique_lock lock(m_mutex);
|
const auto newSceneRect = DrawableRect{
|
||||||
|
|
||||||
auto borderColor = ConvertColor(color);
|
|
||||||
|
|
||||||
m_sceneRect = DrawableRect{
|
|
||||||
.rect = ConvertRect(windowRect),
|
.rect = ConvertRect(windowRect),
|
||||||
.borderColor = borderColor,
|
.borderColor = ConvertColor(color),
|
||||||
.thickness = thickness
|
.thickness = thickness
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const bool colorUpdated = std::memcmp(&m_sceneRect.borderColor, &newSceneRect.borderColor, sizeof(newSceneRect.borderColor));
|
||||||
|
const bool thicknessUpdated = m_sceneRect.thickness != newSceneRect.thickness;
|
||||||
|
const bool needsRedraw = colorUpdated || thicknessUpdated;
|
||||||
|
|
||||||
|
RECT clientRect;
|
||||||
|
|
||||||
|
if (!GetClientRect(m_window, &clientRect))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sceneRect = newSceneRect;
|
||||||
|
|
||||||
|
const auto renderTargetSize = D2D1::SizeU(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top);
|
||||||
|
|
||||||
|
const auto rectHash = D2DRectUHash(renderTargetSize);
|
||||||
|
|
||||||
|
const bool atTheDesiredSize = (rectHash == m_renderTargetSizeHash) && m_renderTarget;
|
||||||
|
if (!atTheDesiredSize)
|
||||||
|
{
|
||||||
|
const bool resizeOk = m_renderTarget && SUCCEEDED(m_renderTarget->Resize(renderTargetSize));
|
||||||
|
if (!resizeOk)
|
||||||
|
{
|
||||||
|
if (!CreateRenderTargets(clientRect))
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to create render targets");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_renderTargetSizeHash = rectHash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colorUpdated)
|
||||||
|
{
|
||||||
|
m_borderBrush = nullptr;
|
||||||
|
if (m_renderTarget)
|
||||||
|
{
|
||||||
|
m_renderTarget->CreateSolidColorBrush(m_sceneRect.borderColor, m_borderBrush.put());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!atTheDesiredSize || needsRedraw)
|
||||||
|
{
|
||||||
|
Render();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ID2D1Factory* FrameDrawer::GetD2DFactory()
|
ID2D1Factory* FrameDrawer::GetD2DFactory()
|
||||||
@ -127,46 +176,18 @@ D2D1_RECT_F FrameDrawer::ConvertRect(RECT rect)
|
|||||||
return D2D1::RectF((float)rect.left, (float)rect.top, (float)rect.right, (float)rect.bottom);
|
return D2D1::RectF((float)rect.left, (float)rect.top, (float)rect.right, (float)rect.bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameDrawer::RenderResult FrameDrawer::Render()
|
void FrameDrawer::Render()
|
||||||
{
|
{
|
||||||
std::unique_lock lock(m_mutex);
|
|
||||||
|
|
||||||
if (!m_renderTarget)
|
if (!m_renderTarget)
|
||||||
{
|
return;
|
||||||
return RenderResult::Failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_renderTarget->BeginDraw();
|
m_renderTarget->BeginDraw();
|
||||||
|
|
||||||
// Draw backdrop
|
|
||||||
m_renderTarget->Clear(D2D1::ColorF(0.f, 0.f, 0.f, 0.f));
|
m_renderTarget->Clear(D2D1::ColorF(0.f, 0.f, 0.f, 0.f));
|
||||||
|
|
||||||
ID2D1SolidColorBrush* borderBrush = nullptr;
|
if (m_borderBrush)
|
||||||
m_renderTarget->CreateSolidColorBrush(m_sceneRect.borderColor, &borderBrush);
|
|
||||||
|
|
||||||
if (borderBrush)
|
|
||||||
{
|
{
|
||||||
m_renderTarget->DrawRectangle(m_sceneRect.rect, borderBrush, m_sceneRect.thickness);
|
m_renderTarget->DrawRectangle(m_sceneRect.rect, m_borderBrush.get(), m_sceneRect.thickness);
|
||||||
borderBrush->Release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The lock must be released here, as EndDraw() will wait for vertical sync
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
m_renderTarget->EndDraw();
|
m_renderTarget->EndDraw();
|
||||||
return RenderResult::Ok;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void FrameDrawer::RenderLoop()
|
|
||||||
{
|
|
||||||
while (!m_abortThread)
|
|
||||||
{
|
|
||||||
auto result = Render();
|
|
||||||
if (result == RenderResult::Failed)
|
|
||||||
{
|
|
||||||
Logger::error("Render failed");
|
|
||||||
Hide();
|
|
||||||
m_abortThread = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include <d2d1.h>
|
#include <d2d1.h>
|
||||||
|
#include <winrt/base.h>
|
||||||
#include <dwrite.h>
|
#include <dwrite.h>
|
||||||
|
|
||||||
class FrameDrawer
|
class FrameDrawer
|
||||||
@ -10,8 +12,7 @@ public:
|
|||||||
static std::unique_ptr<FrameDrawer> Create(HWND window);
|
static std::unique_ptr<FrameDrawer> Create(HWND window);
|
||||||
|
|
||||||
FrameDrawer(HWND window);
|
FrameDrawer(HWND window);
|
||||||
FrameDrawer(FrameDrawer&& other);
|
FrameDrawer(FrameDrawer&& other) = default;
|
||||||
~FrameDrawer();
|
|
||||||
|
|
||||||
bool Init();
|
bool Init();
|
||||||
|
|
||||||
@ -20,6 +21,8 @@ public:
|
|||||||
void SetBorderRect(RECT windowRect, COLORREF color, float thickness);
|
void SetBorderRect(RECT windowRect, COLORREF color, float thickness);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool CreateRenderTargets(const RECT& clientRect);
|
||||||
|
|
||||||
struct DrawableRect
|
struct DrawableRect
|
||||||
{
|
{
|
||||||
D2D1_RECT_F rect;
|
D2D1_RECT_F rect;
|
||||||
@ -27,25 +30,15 @@ private:
|
|||||||
float thickness;
|
float thickness;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum struct RenderResult
|
|
||||||
{
|
|
||||||
Ok,
|
|
||||||
Failed,
|
|
||||||
};
|
|
||||||
|
|
||||||
static ID2D1Factory* GetD2DFactory();
|
static ID2D1Factory* GetD2DFactory();
|
||||||
static IDWriteFactory* GetWriteFactory();
|
static IDWriteFactory* GetWriteFactory();
|
||||||
static D2D1_COLOR_F ConvertColor(COLORREF color);
|
static D2D1_COLOR_F ConvertColor(COLORREF color);
|
||||||
static D2D1_RECT_F ConvertRect(RECT rect);
|
static D2D1_RECT_F ConvertRect(RECT rect);
|
||||||
RenderResult Render();
|
void Render();
|
||||||
void RenderLoop();
|
|
||||||
|
|
||||||
HWND m_window = nullptr;
|
HWND m_window = nullptr;
|
||||||
ID2D1HwndRenderTarget* m_renderTarget = nullptr;
|
size_t m_renderTargetSizeHash = {};
|
||||||
|
winrt::com_ptr<ID2D1HwndRenderTarget> m_renderTarget;
|
||||||
std::mutex m_mutex;
|
winrt::com_ptr<ID2D1SolidColorBrush> m_borderBrush;
|
||||||
DrawableRect m_sceneRect;
|
DrawableRect m_sceneRect = {};
|
||||||
|
|
||||||
std::atomic<bool> m_abortThread = false;
|
|
||||||
std::thread m_renderThread;
|
|
||||||
};
|
};
|
@ -31,18 +31,10 @@ std::optional<RECT> GetFrameRect(HWND window)
|
|||||||
}
|
}
|
||||||
|
|
||||||
WindowBorder::WindowBorder(HWND window) :
|
WindowBorder::WindowBorder(HWND window) :
|
||||||
SettingsObserver({SettingId::FrameColor, SettingId::FrameThickness, SettingId::FrameAccentColor }),
|
|
||||||
m_window(nullptr),
|
|
||||||
m_trackingWindow(window),
|
|
||||||
m_frameDrawer(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
WindowBorder::WindowBorder(WindowBorder&& other) :
|
|
||||||
SettingsObserver({ SettingId::FrameColor, SettingId::FrameThickness, SettingId::FrameAccentColor }),
|
SettingsObserver({ SettingId::FrameColor, SettingId::FrameThickness, SettingId::FrameAccentColor }),
|
||||||
m_window(other.m_window),
|
m_window(nullptr),
|
||||||
m_trackingWindow(other.m_trackingWindow),
|
m_trackingWindow(window),
|
||||||
m_frameDrawer(std::move(other.m_frameDrawer))
|
m_frameDrawer(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +64,12 @@ std::unique_ptr<WindowBorder> WindowBorder::Create(HWND window, HINSTANCE hinsta
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr uint32_t REFRESH_BORDER_TIMER_ID = 123;
|
||||||
|
constexpr uint32_t REFRESH_BORDER_INTERVAL = 100;
|
||||||
|
}
|
||||||
|
|
||||||
bool WindowBorder::Init(HINSTANCE hinstance)
|
bool WindowBorder::Init(HINSTANCE hinstance)
|
||||||
{
|
{
|
||||||
if (!m_trackingWindow)
|
if (!m_trackingWindow)
|
||||||
@ -136,6 +134,8 @@ bool WindowBorder::Init(HINSTANCE hinstance)
|
|||||||
|
|
||||||
UpdateBorderProperties();
|
UpdateBorderProperties();
|
||||||
m_frameDrawer->Show();
|
m_frameDrawer->Show();
|
||||||
|
m_timer_id = SetTimer(m_window, REFRESH_BORDER_TIMER_ID, REFRESH_BORDER_INTERVAL, nullptr);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ void WindowBorder::UpdateBorderPosition() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
RECT rect = rectOpt.value();
|
RECT rect = rectOpt.value();
|
||||||
SetWindowPos(m_window, m_trackingWindow, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOREDRAW);
|
SetWindowPos(m_window, m_trackingWindow, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOREDRAW | SWP_NOACTIVATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowBorder::UpdateBorderProperties() const
|
void WindowBorder::UpdateBorderProperties() const
|
||||||
@ -170,7 +170,9 @@ void WindowBorder::UpdateBorderProperties() const
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RECT windowRect = windowRectOpt.value();
|
const RECT windowRect = windowRectOpt.value();
|
||||||
|
SetWindowPos(m_window, m_trackingWindow, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, SWP_NOREDRAW | SWP_NOACTIVATE);
|
||||||
|
|
||||||
RECT frameRect{ 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top };
|
RECT frameRect{ 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top };
|
||||||
|
|
||||||
COLORREF color;
|
COLORREF color;
|
||||||
@ -192,8 +194,22 @@ LRESULT WindowBorder::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexce
|
|||||||
{
|
{
|
||||||
switch (message)
|
switch (message)
|
||||||
{
|
{
|
||||||
|
case WM_TIMER:
|
||||||
|
{
|
||||||
|
switch (wparam)
|
||||||
|
{
|
||||||
|
case REFRESH_BORDER_TIMER_ID:
|
||||||
|
KillTimer(m_window, m_timer_id);
|
||||||
|
m_timer_id = SetTimer(m_window, REFRESH_BORDER_TIMER_ID, REFRESH_BORDER_INTERVAL, nullptr);
|
||||||
|
UpdateBorderPosition();
|
||||||
|
UpdateBorderProperties();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case WM_NCDESTROY:
|
case WM_NCDESTROY:
|
||||||
{
|
{
|
||||||
|
KillTimer(m_window, m_timer_id);
|
||||||
::DefWindowProc(m_window, message, wparam, lparam);
|
::DefWindowProc(m_window, message, wparam, lparam);
|
||||||
SetWindowLongPtr(m_window, GWLP_USERDATA, 0);
|
SetWindowLongPtr(m_window, GWLP_USERDATA, 0);
|
||||||
}
|
}
|
||||||
@ -231,7 +247,7 @@ void WindowBorder::SettingsUpdate(SettingId id)
|
|||||||
UpdateBorderProperties();
|
UpdateBorderProperties();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SettingId::FrameColor:
|
case SettingId::FrameColor:
|
||||||
{
|
{
|
||||||
UpdateBorderProperties();
|
UpdateBorderProperties();
|
||||||
@ -246,5 +262,4 @@ void WindowBorder::SettingsUpdate(SettingId id)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,8 @@ class FrameDrawer;
|
|||||||
class WindowBorder : public SettingsObserver
|
class WindowBorder : public SettingsObserver
|
||||||
{
|
{
|
||||||
WindowBorder(HWND window);
|
WindowBorder(HWND window);
|
||||||
WindowBorder(WindowBorder&& other);
|
WindowBorder(WindowBorder&& other) = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static std::unique_ptr<WindowBorder> Create(HWND window, HINSTANCE hinstance);
|
static std::unique_ptr<WindowBorder> Create(HWND window, HINSTANCE hinstance);
|
||||||
~WindowBorder();
|
~WindowBorder();
|
||||||
@ -32,8 +32,9 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HWND m_window;
|
UINT_PTR m_timer_id = {};
|
||||||
HWND m_trackingWindow;
|
HWND m_window = {};
|
||||||
|
HWND m_trackingWindow = {};
|
||||||
std::unique_ptr<FrameDrawer> m_frameDrawer;
|
std::unique_ptr<FrameDrawer> m_frameDrawer;
|
||||||
|
|
||||||
LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept;
|
LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept;
|
||||||
|
@ -4,4 +4,7 @@
|
|||||||
#include <winrt/base.h>
|
#include <winrt/base.h>
|
||||||
#include <wil/resource.h>
|
#include <wil/resource.h>
|
||||||
#include <ProjectTelemetry.h>
|
#include <ProjectTelemetry.h>
|
||||||
#include <common/logger/logger.h>
|
#include <common/logger/logger.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <array>
|
Loading…
Reference in New Issue
Block a user