Skip to content

Commit e4f6aa7

Browse files
authored
fix(idlewatcher): reset idle timer on user input and prevent single-trigger lockup (#3)
- Reworked IdleWatcher loop to re-arm after user activity. - Added _hasTriggered latch and ActivityWindow threshold. - Ensures application launches again after subsequent idle periods. - Added safe try/catch wrapping to prevent loop termination on exceptions. closes #2
1 parent bdfc41c commit e4f6aa7

File tree

1 file changed

+31
-11
lines changed

1 file changed

+31
-11
lines changed

src/Services/IdleWatcher.cs

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ namespace OtexumPulse.Services
1010
{
1111
public sealed class IdleWatcher : IDisposable
1212
{
13+
private bool _hasTriggered = false;
14+
private static readonly TimeSpan ActivityWindow = TimeSpan.FromSeconds(1);
1315
private const int CheckIntervalSeconds = 60;
1416
private CancellationTokenSource _cts = new();
1517
private Task? _loop;
@@ -49,25 +51,43 @@ private async Task LoopAsync()
4951
{
5052
try
5153
{
52-
if (!IsPaused && File.Exists(_s.ExePath))
54+
if (!IsPaused)
5355
{
54-
var idle = WinIdle.GetIdleTime();
55-
if (idle.TotalMinutes >= _s.IdleThresholdMinutes && !IsAppRunning(_s.ExePath))
56+
var exe = _s.ExePath;
57+
if (!string.IsNullOrWhiteSpace(exe) && File.Exists(exe))
5658
{
57-
var psi = new ProcessStartInfo
59+
var idle = WinIdle.GetIdleTime();
60+
61+
// Any user input → reset the once-per-idle trigger latch
62+
if (idle < ActivityWindow)
63+
_hasTriggered = false;
64+
65+
var threshold = TimeSpan.FromMinutes(Math.Max(1, _s.IdleThresholdMinutes));
66+
67+
// Fire once per idle stretch, and don’t relaunch if already running
68+
if (!_hasTriggered && idle >= threshold && !IsAppRunning(exe))
5869
{
59-
FileName = _s.ExePath,
60-
UseShellExecute = true,
61-
WorkingDirectory = Path.GetDirectoryName(_s.ExePath)!
62-
};
63-
Process.Start(psi);
70+
try
71+
{
72+
var wd = Path.GetDirectoryName(exe) ?? Environment.CurrentDirectory;
73+
var psi = new ProcessStartInfo
74+
{
75+
FileName = exe,
76+
UseShellExecute = true,
77+
WorkingDirectory = wd
78+
};
79+
Process.Start(psi);
80+
_hasTriggered = true; // latch until user activity
81+
}
82+
catch { /* swallow and keep the app alive */ }
83+
}
6484
}
6585
}
6686
}
67-
catch { /* keep looping */ }
87+
catch { /* never let the loop die */ }
6888

6989
try { await Task.Delay(TimeSpan.FromSeconds(CheckIntervalSeconds), ct); }
70-
catch { }
90+
catch { /* cancellation or transient error */ }
7191
}
7292
}
7393
}

0 commit comments

Comments
 (0)