Skip to content

Commit 94c3e62

Browse files
sebgodclaude
andcommitted
Report whether the foreground grant was actually made
AllowFor discarded the Win32 result, which made two very different outcomes look identical: the grant being refused because THIS process does not hold the foreground right (normal for a script-launched process, as opposed to a shell double-click), and a grant that succeeded while the raise did nothing. Both present as a window that flashed its taskbar button and stayed put, so neither could be diagnosed. It now returns the result and the hand-off logs a refusal at Debug. Still never fatal: the document is delivered either way, and the fallback is the taskbar flash this exists to improve on. This paid for itself immediately. With it, a real two-instance test could show the grant succeeding, which is what isolated the actual defect to the consumer side: SDL_RaiseWindow moves focus without un-minimising, so a minimised window became the foreground window while parked off-screen at -21333,-21333. Focus going somewhere the user cannot see is worse than not raising at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TY5kFz4Qxox1aAHxPKf2ek
1 parent 02c6920 commit 94c3e62

2 files changed

Lines changed: 32 additions & 8 deletions

File tree

‎src/SharpAstro.AppShell/ForegroundActivation.cs‎

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,40 @@ namespace SharpAstro.AppShell;
2424
public static partial class ForegroundActivation
2525
{
2626
/// <summary>
27-
/// Grant <paramref name="processId"/> the right to bring its window to the front. Best-effort:
28-
/// a false return from the OS is not actionable and is not reported, because the fallback (a
29-
/// flashing taskbar button) is already the behaviour we are trying to improve on.
27+
/// Grant <paramref name="processId"/> the right to bring its window to the front. Returns
28+
/// whether the grant was made, which is NOT the same question as whether the window then came
29+
/// forward.
30+
///
31+
/// <para>The distinction is the whole reason this reports anything. The OS refuses the grant
32+
/// when the CALLER does not itself hold the foreground right -- which is normal for a process
33+
/// started by a script rather than by a user's double-click. Without this return value, that
34+
/// case and a genuinely broken raise are indistinguishable: both look like a window that
35+
/// flashed its taskbar button and stayed put.</para>
36+
///
37+
/// <para>Always true off Windows, where nothing needs granting; a false is never fatal, because
38+
/// the fallback is the taskbar flash this is trying to improve on.</para>
3039
/// </summary>
31-
public static void AllowFor(int processId)
40+
public static bool AllowFor(int processId)
3241
{
33-
if (processId <= 0 || !OperatingSystem.IsWindows())
42+
if (processId <= 0)
3443
{
35-
return;
44+
return false;
45+
}
46+
47+
if (!OperatingSystem.IsWindows())
48+
{
49+
return true;
3650
}
3751

3852
try
3953
{
40-
_ = AllowSetForegroundWindow((uint)processId);
54+
return AllowSetForegroundWindow((uint)processId);
4155
}
4256
catch (Exception)
4357
{
4458
// A missing entry point on some future Windows edition must not break a hand-off whose
4559
// payload has not been sent yet.
60+
return false;
4661
}
4762
}
4863

‎src/SharpAstro.AppShell/InstanceGate.cs‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,16 @@ public static bool TryHandOff(string channel, string payload, TimeSpan timeout,
195195
return false;
196196
}
197197

198-
ForegroundActivation.AllowFor(BitConverter.ToInt32(header));
198+
var holderPid = BitConverter.ToInt32(header);
199+
var granted = ForegroundActivation.AllowFor(holderPid);
200+
if (!granted)
201+
{
202+
// Logged rather than swallowed: the hand-off will still deliver and the document
203+
// will still open, but the window will flash its taskbar button instead of coming
204+
// forward, and this line is the only way to tell that apart from a broken raise.
205+
log?.LogDebug("Foreground grant to process {Pid} was refused; this process may not hold "
206+
+ "the foreground right (normal when launched by a script rather than the shell)", holderPid);
207+
}
199208

200209
var bytes = Encoding.UTF8.GetBytes(payload);
201210
if (bytes.Length > MaxPayloadBytes)

0 commit comments

Comments
 (0)