Release v0.6.36: offload notification registration and mitigate Viber paste timing
This commit is contained in:
+18
-1
@@ -358,6 +358,14 @@ class Transaction
|
||||
if (!valid())
|
||||
return false;
|
||||
write(clip);
|
||||
// Viber's Qt editor observes clipboard changes asynchronously. Give it
|
||||
// a chance to discard the data object from Ctrl+C before requesting paste.
|
||||
// Recheck ownership and input below; never retry a possibly applied paste.
|
||||
if (lower(processName(target)) == L"viber")
|
||||
{
|
||||
Sleep(75);
|
||||
diagnosticEvent(L"Paste: Viber clipboard notification settling interval completed");
|
||||
}
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
check();
|
||||
@@ -433,6 +441,7 @@ App::App(HINSTANCE h, bool test, const std::filesystem::path &dataRoot) : instan
|
||||
}
|
||||
App::~App()
|
||||
{
|
||||
if (notificationRegistration) CloseHandle(notificationRegistration);
|
||||
if (syncWorker.joinable()) syncWorker.join();
|
||||
if (updateWorker.joinable())
|
||||
updateWorker.join();
|
||||
@@ -1893,6 +1902,14 @@ LRESULT CALLBACK App::windowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
case WM_TIMER:
|
||||
if (wp == 6)
|
||||
{
|
||||
if (app->notificationRegistration && WaitForSingleObject(app->notificationRegistration, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
DWORD code = ERROR_GEN_FAILURE;
|
||||
GetExitCodeProcess(app->notificationRegistration, &code);
|
||||
if (code) log(L"Screenshot notification registration helper failed: " + std::to_wstring(code));
|
||||
CloseHandle(app->notificationRegistration);
|
||||
app->notificationRegistration = nullptr;
|
||||
}
|
||||
app->releaseIdleMemory(GetTickCount64());
|
||||
app->pollSync();
|
||||
return 0;
|
||||
@@ -2012,7 +2029,7 @@ int App::execute()
|
||||
log(std::wstring(L"Update completed; running version ") + AppVersion);
|
||||
if (startCommand)
|
||||
PostMessageW(window, WM_HOTKEY, startCommand, 0);
|
||||
try { registerScreenshotNotifications(); }
|
||||
try { notificationRegistration = startScreenshotNotificationRegistration(); }
|
||||
catch(const std::exception &e) { log(L"Screenshot notification registration: "+wide(e.what())); }
|
||||
auto screenshotActivation=startScreenshotActivationListener();
|
||||
MSG msg;
|
||||
|
||||
@@ -92,6 +92,7 @@ class App
|
||||
std::condition_variable jobsReady;
|
||||
std::deque<std::function<void()>> jobs;
|
||||
std::thread worker;
|
||||
HANDLE notificationRegistration{};
|
||||
std::thread historySearchWorker;
|
||||
std::condition_variable historySearchReady;
|
||||
std::function<void()> pendingHistorySearch;
|
||||
|
||||
@@ -50,6 +50,30 @@ void registerScreenshotNotifications()
|
||||
// Notify the shell that notification identity/activation registration changed.
|
||||
SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_IDLIST,nullptr,nullptr);
|
||||
}
|
||||
HANDLE startScreenshotNotificationRegistration()
|
||||
{
|
||||
auto path=std::filesystem::path(executable()).parent_path()/L"KSwitcher.Screenshot.exe";
|
||||
auto command=L"\""+path.wstring()+L"\" --register-notifications";
|
||||
STARTUPINFOW startup{sizeof(startup)};
|
||||
startup.dwFlags=STARTF_USESHOWWINDOW; startup.wShowWindow=SW_HIDE;
|
||||
PROCESS_INFORMATION process{};
|
||||
if(!CreateProcessW(path.c_str(),command.data(),nullptr,nullptr,FALSE,CREATE_NO_WINDOW,
|
||||
nullptr,path.parent_path().c_str(),&startup,&process))
|
||||
throw std::runtime_error(utf8(lastError(L"Cannot start notification registration helper")));
|
||||
CloseHandle(process.hThread);
|
||||
return process.hProcess;
|
||||
}
|
||||
void registerScreenshotNotificationsInHelper()
|
||||
{
|
||||
auto process=startScreenshotNotificationRegistration();
|
||||
auto wait=WaitForSingleObject(process,10000);
|
||||
DWORD code=ERROR_GEN_FAILURE;
|
||||
bool completed=wait==WAIT_OBJECT_0 && GetExitCodeProcess(process,&code);
|
||||
CloseHandle(process);
|
||||
if(!completed || code)
|
||||
throw std::runtime_error(completed ? "Notification registration helper failed: "+std::to_string(code)
|
||||
: "Notification registration helper did not complete within 10 seconds");
|
||||
}
|
||||
bool validScreenshotToken(const std::wstring &id)
|
||||
{
|
||||
if(id.size()!=36) return false;
|
||||
|
||||
@@ -206,7 +206,7 @@ bool notifyUpdateAvailable(const std::wstring &version)
|
||||
{
|
||||
try {
|
||||
// Reuse the screenshot notification identity, Windows settings and COM activator.
|
||||
registerScreenshotNotifications();
|
||||
registerScreenshotNotificationsInHelper();
|
||||
ComPtr<Notifications::IToastNotificationManagerStatics> manager;
|
||||
String managerClass(L"Windows.UI.Notifications.ToastNotificationManager");
|
||||
check(RoGetActivationFactory(managerClass.value,IID_PPV_ARGS(&manager)));
|
||||
|
||||
@@ -4,6 +4,10 @@ namespace ks {
|
||||
bool notifyScreenshot(const Clip &);
|
||||
std::string screenshotNotificationError();
|
||||
void registerScreenshotNotifications();
|
||||
// Caller owns the returned process handle; the helper exits after registration.
|
||||
HANDLE startScreenshotNotificationRegistration();
|
||||
// For background notification workers only; bounded wait, never on the UI thread.
|
||||
void registerScreenshotNotificationsInHelper();
|
||||
int runScreenshotToastActivator();
|
||||
DWORD startScreenshotActivationListener();
|
||||
bool validScreenshotToken(const std::wstring &);
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
#include "platform.h"
|
||||
namespace ks
|
||||
{
|
||||
inline constexpr wchar_t AppVersion[] = L"0.6.35";
|
||||
inline constexpr wchar_t AppVersion[] = L"0.6.36";
|
||||
inline constexpr UINT UpdateMessage = WM_APP + 7;
|
||||
inline constexpr UINT UpdateCheckIntervalMs = 6 * 60 * 60 * 1000;
|
||||
inline constexpr UINT UpdateNotificationRetryMs = 5 * 60 * 1000;
|
||||
|
||||
Reference in New Issue
Block a user