Skip to content

Commit

Permalink
add NotificationUtil helper with file watcher and cache
Browse files Browse the repository at this point in the history
  • Loading branch information
davidegiacometti committed Jan 6, 2025
1 parent 809791d commit 97666df
Show file tree
Hide file tree
Showing 11 changed files with 104 additions and 43 deletions.
3 changes: 3 additions & 0 deletions src/common/SettingsAPI/FileWatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#include <string>
#include <functional>

#include <wil/resource.h>
#include <wil/filesystem.h>

class FileWatcher
{
std::wstring m_path;
Expand Down
1 change: 0 additions & 1 deletion src/common/SettingsAPI/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,3 @@
#include <fstream>

#include <common/logger/logger.h>
#include <wil/filesystem.h>
56 changes: 56 additions & 0 deletions src/common/notifications/NotificationUtil.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include "pch.h"
#include "NotificationUtil.h"

#include <common/notifications/notifications.h>
#include <common/notifications/dont_show_again.h>
#include <common/utils/resources.h>
#include <common/SettingsAPI/settings_helpers.h>

// Non-Localizable strings
namespace NonLocalizable
{
const wchar_t RunAsAdminInfoPage[] = L"https://aka.ms/powertoysDetectedElevatedHelp";
const wchar_t ToastNotificationButtonUrl[] = L"powertoys://cant_drag_elevated_disable/";
}

namespace notifications
{
NotificationUtil::NotificationUtil()
{
ReadSettings();
auto settingsfileName = PTSettingsHelper::get_powertoys_general_save_file_location();

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

settingsfile is not a recognized word. (unrecognized-spelling)

m_settingsFileWatcher = std::make_unique<FileWatcher>(settingsfileName, [this]() {

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

settingsfile is not a recognized word. (unrecognized-spelling)
ReadSettings();
});
}

NotificationUtil::~NotificationUtil()
{
m_settingsFileWatcher.reset();
}

void NotificationUtil::WarnIfElevationIsRequired(std::wstring title, std::wstring message, std::wstring button1, std::wstring button2)
{
if (m_warningsElevatedApps && !m_warningShown && !is_toast_disabled(ElevatedDontShowAgainRegistryPath, ElevatedDisableIntervalInDays))
{
std::vector<action_t> actions = {
link_button{ button1, NonLocalizable::RunAsAdminInfoPage },
link_button{ button2, NonLocalizable::ToastNotificationButtonUrl }
};

show_toast_with_activations(message,
title,
{},
std::move(actions));

m_warningShown = true;
}
}

void NotificationUtil::ReadSettings()
{
auto settings = PTSettingsHelper::load_general_settings();
m_warningsElevatedApps = settings.GetNamedBoolean(L"enable_warnings_elevated_apps", true);
}
}
44 changes: 13 additions & 31 deletions src/common/notifications/NotificationUtil.h
Original file line number Diff line number Diff line change
@@ -1,40 +1,22 @@
#pragma once

#include <common/notifications/notifications.h>
#include <common/notifications/dont_show_again.h>
#include <common/utils/resources.h>
#include <common/SettingsAPI/settings_helpers.h>

#include "Generated Files/resource.h"
#include <common/SettingsAPI/FileWatcher.h>

namespace notifications
{
// Non-Localizable strings
namespace NonLocalizable
class NotificationUtil
{
const wchar_t RunAsAdminInfoPage[] = L"https://aka.ms/powertoysDetectedElevatedHelp";
const wchar_t ToastNotificationButtonUrl[] = L"powertoys://cant_drag_elevated_disable/";
}
public:
NotificationUtil();
~NotificationUtil();

inline void WarnIfElevationIsRequired(std::wstring title, std::wstring message, std::wstring button1, std::wstring button2)
{
using namespace NonLocalizable;
void WarnIfElevationIsRequired(std::wstring title, std::wstring message, std::wstring button1, std::wstring button2);

auto settings = PTSettingsHelper::load_general_settings();
auto enableWarningsElevatedApps = settings.GetNamedBoolean(L"enable_warnings_elevated_apps", true);
private:
std::unique_ptr<FileWatcher> m_settingsFileWatcher;
bool m_warningsElevatedApps;
bool m_warningShown = false;

static bool warning_shown = false;
if (enableWarningsElevatedApps && !warning_shown && !is_toast_disabled(ElevatedDontShowAgainRegistryPath, ElevatedDisableIntervalInDays))
{
std::vector<action_t> actions = {
link_button{ button1, RunAsAdminInfoPage },
link_button{ button2, ToastNotificationButtonUrl }
};
show_toast_with_activations(message,
title,
{},
std::move(actions));
warning_shown = true;
}
}
}
void ReadSettings();
};
}
3 changes: 2 additions & 1 deletion src/common/notifications/notifications.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="notifications.h" />
<ClInclude Include="NotificationUtil.h" />
<ClInclude Include="dont_show_again.h" />
<ClInclude Include="NotificationUtil.h" />
<ClInclude Include="pch.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dont_show_again.cpp" />
<ClCompile Include="notifications.cpp" />
<ClCompile Include="NotificationUtil.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
</ClCompile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <common/utils/elevation.h>
#include <common/utils/process_path.h>
#include <common/utils/resources.h>
#include <common/notifications/NotificationUtil.h>

#include <workspaces-common/WindowEnumerator.h>
Expand All @@ -11,6 +12,8 @@
#include <WorkspacesLib/AppUtils.h>
#include <WorkspacesLib/PwaHelper.h>

#include "Generated Files/resource.h"

#pragma comment(lib, "ntdll.lib")

namespace SnapshotUtils
Expand Down Expand Up @@ -73,7 +76,9 @@ namespace SnapshotUtils
// Notify the user that running as admin is required to process elevated windows.
if (!is_process_elevated() && IsProcessElevated(pid))
{
notifications::WarnIfElevationIsRequired(GET_RESOURCE_STRING(IDS_PROJECTS),
auto notificationUtil = std::make_unique<notifications::NotificationUtil>();

notificationUtil->WarnIfElevationIsRequired(GET_RESOURCE_STRING(IDS_PROJECTS),
GET_RESOURCE_STRING(IDS_SYSTEM_FOREGROUND_ELEVATED),
GET_RESOURCE_STRING(IDS_SYSTEM_FOREGROUND_ELEVATED_LEARN_MORE),
GET_RESOURCE_STRING(IDS_SYSTEM_FOREGROUND_ELEVATED_DIALOG_DONT_SHOW_AGAIN));
Expand Down
7 changes: 4 additions & 3 deletions src/modules/alwaysontop/AlwaysOnTop/AlwaysOnTop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include <common/utils/process_path.h>

#include <common/utils/elevation.h>
#include <common/notifications/NotificationUtil.h>
#include <Generated Files/resource.h>

#include <interop/shared_constants.h>
Expand All @@ -36,7 +35,8 @@ AlwaysOnTop::AlwaysOnTop(bool useLLKH, DWORD mainThreadId) :
SettingsObserver({SettingId::FrameEnabled, SettingId::Hotkey, SettingId::ExcludeApps}),
m_hinstance(reinterpret_cast<HINSTANCE>(&__ImageBase)),
m_useCentralizedLLKH(useLLKH),
m_mainThreadId(mainThreadId)
m_mainThreadId(mainThreadId),
m_notificationUtil(std::make_unique<notifications::NotificationUtil>())
{
s_instance = this;
DPIAware::EnableDPIAwarenessForThisProcess();
Expand Down Expand Up @@ -64,6 +64,7 @@ AlwaysOnTop::AlwaysOnTop(bool useLLKH, DWORD mainThreadId) :
AlwaysOnTop::~AlwaysOnTop()
{
m_running = false;
m_notificationUtil.reset();

if (m_hPinEvent)
{
Expand Down Expand Up @@ -509,7 +510,7 @@ void AlwaysOnTop::HandleWinHookEvent(WinHookEvent* data) noexcept
{
if (!is_process_elevated() && IsProcessOfWindowElevated(data->hwnd))
{
notifications::WarnIfElevationIsRequired(GET_RESOURCE_STRING(IDS_ALWAYSONTOP), GET_RESOURCE_STRING(IDS_SYSTEM_FOREGROUND_ELEVATED), GET_RESOURCE_STRING(IDS_SYSTEM_FOREGROUND_ELEVATED_LEARN_MORE), GET_RESOURCE_STRING(IDS_SYSTEM_FOREGROUND_ELEVATED_DIALOG_DONT_SHOW_AGAIN));
m_notificationUtil->WarnIfElevationIsRequired(GET_RESOURCE_STRING(IDS_ALWAYSONTOP), GET_RESOURCE_STRING(IDS_SYSTEM_FOREGROUND_ELEVATED), GET_RESOURCE_STRING(IDS_SYSTEM_FOREGROUND_ELEVATED_LEARN_MORE), GET_RESOURCE_STRING(IDS_SYSTEM_FOREGROUND_ELEVATED_DIALOG_DONT_SHOW_AGAIN));
}
RefreshBorders();
}
Expand Down
2 changes: 2 additions & 0 deletions src/modules/alwaysontop/AlwaysOnTop/AlwaysOnTop.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <WindowBorder.h>

#include <common/hooks/WinHookEvent.h>
#include <common/notifications/NotificationUtil.h>

class AlwaysOnTop : public SettingsObserver
{
Expand Down Expand Up @@ -53,6 +54,7 @@ class AlwaysOnTop : public SettingsObserver
std::thread m_thread;
const bool m_useCentralizedLLKH;
bool m_running = true;
std::unique_ptr<notifications::NotificationUtil> m_notificationUtil;

LRESULT WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
void HandleWinHookEvent(WinHookEvent* data) noexcept;
Expand Down
9 changes: 8 additions & 1 deletion src/modules/fancyzones/FancyZonesLib/FancyZones.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <common/utils/EventWaiter.h>
#include <common/utils/winapi_error.h>
#include <common/SettingsAPI/FileWatcher.h>
#include <common/notifications/NotificationUtil.h>

#include <FancyZonesLib/DraggingState.h>
#include <FancyZonesLib/EditorParameters.h>
Expand Down Expand Up @@ -185,6 +186,8 @@ struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZone

EventWaiter m_toggleEditorEventWaiter;

std::unique_ptr<notifications::NotificationUtil> m_notificationUtil;

// If non-recoverable error occurs, trigger disabling of entire FancyZones.
static std::function<void()> disableModuleCallback;

Expand Down Expand Up @@ -266,6 +269,8 @@ FancyZones::Run() noexcept
}
});

m_notificationUtil = std::make_unique<notifications::NotificationUtil>();

SyncVirtualDesktops();

// id format of applied-layouts and app-zone-history was changed in 0.60
Expand All @@ -288,6 +293,8 @@ FancyZones::Destroy() noexcept
m_window = nullptr;
}

m_notificationUtil.reset();

CoUninitialize();
}

Expand All @@ -302,7 +309,7 @@ FancyZones::VirtualDesktopChanged() noexcept

void FancyZones::MoveSizeStart(HWND window, HMONITOR monitor)
{
m_windowMouseSnapper = WindowMouseSnap::Create(window, m_workAreaConfiguration.GetAllWorkAreas());
m_windowMouseSnapper = WindowMouseSnap::Create(window, m_workAreaConfiguration.GetAllWorkAreas(), m_notificationUtil.get());
if (m_windowMouseSnapper)
{
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
Expand Down
12 changes: 8 additions & 4 deletions src/modules/fancyzones/FancyZonesLib/WindowMouseSnap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <FancyZonesLib/trace.h>

#include <common/utils/elevation.h>
#include <common/notifications/NotificationUtil.h>
#include <common/utils/resources.h>

WindowMouseSnap::WindowMouseSnap(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas) :
m_window(window),
Expand All @@ -27,7 +27,7 @@ WindowMouseSnap::~WindowMouseSnap()
ResetWindowTransparency();
}

std::unique_ptr<WindowMouseSnap> WindowMouseSnap::Create(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas)
std::unique_ptr<WindowMouseSnap> WindowMouseSnap::Create(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas, notifications::NotificationUtil* notificationUtil)
{
if (FancyZonesWindowUtils::IsCursorTypeIndicatingSizeEvent() || !FancyZonesWindowProcessing::IsProcessableManually(window))
{
Expand All @@ -36,8 +36,12 @@ std::unique_ptr<WindowMouseSnap> WindowMouseSnap::Create(HWND window, const std:

if (!is_process_elevated() && IsProcessOfWindowElevated(window))
{
// Notifies user if unable to drag elevated window
notifications::WarnIfElevationIsRequired(GET_RESOURCE_STRING(IDS_FANCYZONES), GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED), GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_LEARN_MORE), GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN));
if (notificationUtil != nullptr)
{
// Notifies user if unable to drag elevated window
notificationUtil->WarnIfElevationIsRequired(GET_RESOURCE_STRING(IDS_FANCYZONES), GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED), GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_LEARN_MORE), GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN));
}

return nullptr;
}

Expand Down
3 changes: 2 additions & 1 deletion src/modules/fancyzones/FancyZonesLib/WindowMouseSnap.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <FancyZonesLib/HighlightedZones.h>
#include <common/notifications/NotificationUtil.h>

class WorkArea;

Expand All @@ -9,7 +10,7 @@ class WindowMouseSnap
WindowMouseSnap(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas);

public:
static std::unique_ptr<WindowMouseSnap> Create(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas);
static std::unique_ptr<WindowMouseSnap> Create(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas, notifications::NotificationUtil* notificationUtil);
~WindowMouseSnap();

bool MoveSizeStart(HMONITOR monitor, bool isSnapping);
Expand Down

1 comment on commit 97666df

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@check-spelling-bot Report

🔴 Please review

See the 📜action log or 📝 job summary for details.

Unrecognized words (1)

settingsfile

These words are not needed and should be removed accctrl aclapi appdata Appium appmodel atlbase atlcom atlfile atlstr bootstrapper caniuse ceq cguid Cmds cne codicon comdef commandline commctrl commdlg comutil consts contentdialog cppwinrt CRSEL crx dcommon dcomp DCs desktopwindowxamlsource devpkey dxgidebug dxgiformat emmintrin Emoji endpointvolume evntrace exdisp Functiondiscoverykeys guiddef hinstance hstring Intelli ipreviewhandlervisualssetfont junja Knownfolders lmcons LONGLONG lpt LTRB mfapi mfidl mfobjects mftransform Minimatch mmdeviceapi mmsystem msedge msiquery newdev nodoc notlike ntfs Objbase objidl outputtype pathcch Pnp Preinstalled processthreadsapi propkey propvarutil redistributable Renamer reparse restrictederrorinfo roadmap ruleset runtimes shellapi shellscalingapi shldisp shlobj stl strsafe strutil subquery SWC tailwindcss tapp thumbcache tlhelp Toolset touchpad Tsd uninstantiated uniquifier Unknwn unregistering urlmon USERDATA Uxtheme verrsrc wcautil wincodec Wincodecsdk windef windowsapp windowsx winerror winevt winexe winforms winsdkver winternl wsl wtsapi

To accept these unrecognized words as correct and remove the previously acknowledged and now absent words, you could run the following commands

... in a clone of the [email protected]:microsoft/PowerToys.git repository
on the users/davidegiacometti/issue-36586 branch (ℹ️ how do I use this?):

curl -s -S -L 'https://raw.githubusercontent.com/check-spelling/check-spelling/v0.0.24/apply.pl' |
perl - 'https://github.com/microsoft/PowerToys/actions/runs/12636361310/attempts/1'
If the flagged items are 🤯 false positives

If items relate to a ...

  • binary file (or some other file you wouldn't want to check at all).

    Please add a file path to the excludes.txt file matching the containing file.

    File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

    ^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

  • well-formed pattern.

    If you can write a pattern that would match it,
    try adding it to the patterns.txt file.

    Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

    Note that patterns can't match multiline strings.

Please sign in to comment.