Fix: prevent mobile web remote desktop freeze on Safari app-switch

by forcing clean WS reconnect on foreground return;

add 30-second grace period on server to avoid cold-start on quick reconnects
This commit is contained in:
yuanyuanxiang
2026-07-10 15:56:32 +02:00
parent 72dcdc5a6f
commit f146af121a
5 changed files with 111 additions and 9 deletions

View File

@@ -1814,6 +1814,16 @@ bool CWebService::StartRemoteDesktop(uint64_t device_id) {
context* ctx = m_pParentDlg->FindHost(device_id);
if (!ctx) return false;
// Cancel any pending grace-period close so the existing session stays alive.
{
std::lock_guard<std::mutex> lk(m_PendingCloseMutex);
auto it = m_PendingCloseTimers.find(device_id);
if (it != m_PendingCloseTimers.end()) {
it->second->store(true);
m_PendingCloseTimers.erase(it);
}
}
// Check if there's already a Web session for this device
// Only reuse if Web has already triggered AND a Web dialog exists
// This ensures MFC and Web have independent dialogs
@@ -1854,11 +1864,36 @@ void CWebService::StopRemoteDesktop(uint64_t device_id) {
}
}
// If no more web clients watching, close only the Web session dialog
// MFC dialogs remain open
// If no more web clients watching, defer close by 30 s so a quick
// mobile reconnect (e.g. switching to a TOTP app) reuses the existing
// CScreenSpyDlg without a full cold-start.
if (watchingCount == 0) {
ClearWebTriggered(device_id);
m_pParentDlg->CloseWebRemoteDesktopByClientID(device_id);
auto cancelled = std::make_shared<std::atomic<bool>>(false);
{
std::lock_guard<std::mutex> lk(m_PendingCloseMutex);
auto it = m_PendingCloseTimers.find(device_id);
if (it != m_PendingCloseTimers.end())
it->second->store(true);
m_PendingCloseTimers[device_id] = cancelled;
}
std::thread([this, device_id, cancelled]() {
std::this_thread::sleep_for(std::chrono::seconds(30));
if (cancelled->load()) return;
{
std::lock_guard<std::mutex> lk(m_PendingCloseMutex);
m_PendingCloseTimers.erase(device_id);
}
int count = 0;
{
std::lock_guard<std::mutex> lock(m_ClientsMutex);
for (const auto& [ws, client] : m_Clients)
if (client.watch_device_id == device_id) count++;
}
if (count == 0 && m_pParentDlg) {
ClearWebTriggered(device_id);
m_pParentDlg->CloseWebRemoteDesktopByClientID(device_id);
}
}).detach();
}
}

View File

@@ -5,6 +5,8 @@
#include <vector>
#include <map>
#include <set>
#include <atomic>
#include <chrono>
#include <mutex>
#include <thread>
#include <memory>
@@ -231,6 +233,13 @@ private:
std::set<uint64_t> m_OfflineDevices; // Devices that went offline since last flush
std::mutex m_DirtyDevicesMutex;
// Grace-period timers: delay CloseWebRemoteDesktopByClientID by 30 s after
// the last web viewer disconnects to allow quick mobile reconnects (e.g.
// switching to a TOTP app briefly). Cancelled by StartRemoteDesktop when a
// viewer reconnects within the window.
std::map<uint64_t, std::shared_ptr<std::atomic<bool>>> m_PendingCloseTimers;
std::mutex m_PendingCloseMutex;
public:
// Check if a device session was triggered by web (should be hidden)
bool IsWebTriggered(uint64_t device_id);