fix(core): drive auto-lock idle from real input, not widget focus
The auto-lock idle clock was reset whenever any ImGui item was active, so a text field left focused (a half-filled send form, say) counted as continuous activity and kept the wallet unlocked indefinitely, well past the configured idle timeout. - The idle clock is now fed by real input events (key, text, mouse, touch, pen, gamepad button) as they are ingested on the main thread, plus a still-held mouse button so a drag or scrollbar grab that emits no new event still counts. A focused but untouched widget no longer does. - A new header-only IdleTracker owns the clock and never moves backwards, so an event stamped before the previous one cannot shorten the idle time. Behaviour change: a form left focused and idle past the timeout now auto-locks. The form's buffers are app state and survive the lock and unlock, so nothing typed is lost. Tests: a new IdleTracker case covers idle time growing with no events (enough to trip a 900s lock), activity resetting it, the clock never moving backwards, and a query before the last activity reading zero rather than a negative value. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -479,7 +479,7 @@ void App::applyUnlockSuccess(const std::string& passphrase, int timeout) {
|
||||
lock_error_msg_.clear();
|
||||
lock_attempts_ = 0;
|
||||
memset(lock_passphrase_buf_, 0, sizeof(lock_passphrase_buf_));
|
||||
last_interaction_ = std::chrono::steady_clock::now();
|
||||
idle_.noteActivity();
|
||||
state_.encrypted = true;
|
||||
state_.locked = false;
|
||||
state_.unlocked_until = std::time(nullptr) + timeout;
|
||||
@@ -726,17 +726,16 @@ void App::checkAutoLock() {
|
||||
|| (xmrig_manager_ && xmrig_manager_->isRunning());
|
||||
if (miningActive) {
|
||||
// Keep resetting the idle timer so we don't lock the instant mining stops
|
||||
last_interaction_ = std::chrono::steady_clock::now();
|
||||
idle_.noteActivity();
|
||||
return;
|
||||
}
|
||||
|
||||
int timeout = settings_ ? settings_->getAutoLockTimeout() : 300;
|
||||
if (timeout <= 0) return; // disabled
|
||||
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
float elapsed = std::chrono::duration<float>(now - last_interaction_).count();
|
||||
const double elapsed = idle_.idleSeconds();
|
||||
|
||||
if (elapsed >= (float)timeout) {
|
||||
if (elapsed >= (double)timeout) {
|
||||
// Lite has no daemon `walletlock` — App::lockWallet() early-returns without rpc_, so route
|
||||
// lite through lockLiteWallet() (locks the backend + tears down the chat session so no
|
||||
// decrypted store / unlocked DB key survives the idle lock). In full-node builds
|
||||
|
||||
Reference in New Issue
Block a user