[FancyZones] Implement File Watcher (#8603)

* Implement File Watcher in FancyZones

* Simplify code, address PR comments

* Add check to result of CreateEventW

* Rebase fix

Removed unneeded newline. If we keep it now, VS will just remove it some other time.
This commit is contained in:
Ivan Stošić 2020-12-16 14:53:48 +01:00 committed by GitHub
parent 540e16b179
commit e2ca4177dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 118 additions and 0 deletions

View File

@ -10,6 +10,7 @@
#include "lib/ZoneWindow.h"
#include "lib/FancyZonesData.h"
#include "lib/ZoneSet.h"
#include "lib/FileWatcher.h"
#include "lib/WindowMoveHandler.h"
#include "lib/FancyZonesWinHookEventIDs.h"
#include "lib/util.h"
@ -50,6 +51,9 @@ public:
m_settings(settings),
m_windowMoveHandler(settings, [this]() {
PostMessageW(m_window, WM_PRIV_LOCATIONCHANGE, NULL, NULL);
}),
m_fileWatcher(FancyZonesDataInstance().GetZonesSettingsFileName(), [this]() {
PostMessageW(m_window, WM_PRIV_FILE_UPDATE, NULL, NULL);
})
{
m_settings->SetCallback(this);
@ -221,6 +225,7 @@ private:
void MoveWindowIntoZone(HWND window, winrt::com_ptr<IZoneWindow> zoneWindow, const std::vector<size_t>& zoneIndexSet) noexcept;
void OnEditorExitEvent() noexcept;
void UpdateZoneSets() noexcept;
bool ShouldProcessSnapHotkey(DWORD vkCode) noexcept;
std::vector<std::pair<HMONITOR, RECT>> GetRawMonitorData() noexcept;
@ -232,6 +237,7 @@ private:
HWND m_window{};
WindowMoveHandler m_windowMoveHandler;
MonitorWorkAreaHandler m_workAreaHandler;
FileWatcher m_fileWatcher;
winrt::com_ptr<IFancyZonesSettings> m_settings{};
GUID m_previousDesktopId{}; // UUID of previously active virtual desktop.
@ -249,6 +255,7 @@ private:
static UINT WM_PRIV_VD_SWITCH; // Scheduled when virtual desktop switch occurs
static UINT WM_PRIV_VD_UPDATE; // Scheduled on virtual desktops update (creation/deletion)
static UINT WM_PRIV_EDITOR; // Scheduled when the editor exits
static UINT WM_PRIV_FILE_UPDATE; // Scheduled when the a watched file is updated
static UINT WM_PRIV_LOWLEVELKB; // Scheduled when we receive a key down press
@ -266,6 +273,7 @@ UINT FancyZones::WM_PRIV_VD_INIT = RegisterWindowMessage(L"{469818a8-00fa-4069-b
UINT FancyZones::WM_PRIV_VD_SWITCH = RegisterWindowMessage(L"{128c2cb0-6bdf-493e-abbe-f8705e04aa95}");
UINT FancyZones::WM_PRIV_VD_UPDATE = RegisterWindowMessage(L"{b8b72b46-f42f-4c26-9e20-29336cf2f22e}");
UINT FancyZones::WM_PRIV_EDITOR = RegisterWindowMessage(L"{87543824-7080-4e91-9d9c-0404642fc7b6}");
UINT FancyZones::WM_PRIV_FILE_UPDATE = RegisterWindowMessage(L"{632f17a9-55a7-45f1-a4db-162e39271d92}");
UINT FancyZones::WM_PRIV_LOWLEVELKB = RegisterWindowMessage(L"{763c03a3-03d9-4cde-8d71-f0358b0b4b52}");
// IFancyZones
@ -856,6 +864,11 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
auto hwnd = reinterpret_cast<HWND>(wparam);
WindowCreated(hwnd);
}
else if (message == WM_PRIV_FILE_UPDATE)
{
FancyZonesDataInstance().LoadFancyZonesData();
UpdateZoneSets();
}
else
{
return DefWindowProc(window, message, wparam, lparam);
@ -1296,7 +1309,11 @@ void FancyZones::OnEditorExitEvent() noexcept
{
// Collect information about changes in zone layout after editor exited.
FancyZonesDataInstance().ParseDataFromTmpFiles();
UpdateZoneSets();
}
void FancyZones::UpdateZoneSets() noexcept
{
for (auto workArea : m_workAreaHandler.GetAllWorkAreas())
{
workArea->UpdateActiveZoneSet();

View File

@ -59,6 +59,11 @@ public:
return appZoneHistoryMap;
}
inline const std::wstring& GetZonesSettingsFileName() const
{
return zonesSettingsFileName;
}
bool AddDevice(const std::wstring& deviceId);
void CloneDeviceInfo(const std::wstring& source, const std::wstring& destination);
void UpdatePrimaryDesktopData(const std::wstring& desktopId);

View File

@ -40,6 +40,7 @@
<ClInclude Include="FancyZones.h" />
<ClInclude Include="FancyZonesDataTypes.h" />
<ClInclude Include="FancyZonesWinHookEventIDs.h" />
<ClInclude Include="FileWatcher.h" />
<ClInclude Include="GenericKeyHook.h" />
<ClInclude Include="FancyZonesData.h" />
<ClInclude Include="JsonHelpers.h" />
@ -64,6 +65,7 @@
<ClCompile Include="FancyZonesDataTypes.cpp" />
<ClCompile Include="FancyZonesWinHookEventIDs.cpp" />
<ClCompile Include="FancyZonesData.cpp" />
<ClCompile Include="FileWatcher.cpp" />
<ClCompile Include="JsonHelpers.cpp" />
<ClCompile Include="MonitorWorkAreaHandler.cpp" />
<ClCompile Include="OnThreadExecutor.cpp" />

View File

@ -78,6 +78,9 @@
<ClInclude Include="ZoneWindowDrawing.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FileWatcher.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@ -134,6 +137,9 @@
<ClCompile Include="OnThreadExecutor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FileWatcher.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@ -0,0 +1,68 @@
#include "pch.h"
#include "FileWatcher.h"
std::optional<FILETIME> FileWatcher::MyFileTime()
{
HANDLE hFile = CreateFileW(m_path.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
std::optional<FILETIME> result;
if (hFile != INVALID_HANDLE_VALUE)
{
FILETIME lastWrite;
if (GetFileTime(hFile, nullptr, nullptr, &lastWrite))
{
result = lastWrite;
}
CloseHandle(hFile);
}
return result;
}
void FileWatcher::Run()
{
while (1)
{
auto lastWrite = MyFileTime();
if (!m_lastWrite.has_value())
{
m_lastWrite = lastWrite;
}
else if (lastWrite.has_value())
{
if (m_lastWrite->dwHighDateTime != lastWrite->dwHighDateTime ||
m_lastWrite->dwLowDateTime != lastWrite->dwLowDateTime)
{
m_lastWrite = lastWrite;
m_callback();
}
}
if (WaitForSingleObject(m_abortEvent, m_refreshPeriod) == WAIT_OBJECT_0)
{
return;
}
}
}
FileWatcher::FileWatcher(const std::wstring& path, std::function<void()> callback, DWORD refreshPeriod) :
m_refreshPeriod(refreshPeriod),
m_path(path),
m_callback(callback)
{
m_abortEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
if (m_abortEvent)
{
m_thread = std::thread([this]() { Run(); });
}
}
FileWatcher::~FileWatcher()
{
if (m_abortEvent)
{
SetEvent(m_abortEvent);
m_thread.join();
CloseHandle(m_abortEvent);
}
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "pch.h"
class FileWatcher
{
DWORD m_refreshPeriod;
std::wstring m_path;
std::optional<FILETIME> m_lastWrite;
std::function<void()> m_callback;
HANDLE m_abortEvent;
std::thread m_thread;
std::optional<FILETIME> MyFileTime();
void Run();
public:
FileWatcher(const std::wstring& path, std::function<void()> callback, DWORD refreshPeriod = 1000);
~FileWatcher();
};

View File

@ -21,6 +21,7 @@
#include <functional>
#include <unordered_set>
#include <ShObjIdl.h>
#include <optional>
#pragma comment(lib, "windowsapp")