152 lines
5.2 KiB
C#
152 lines
5.2 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Windows;
|
||
using Microsoft.Data.Sqlite;
|
||
using Xunit;
|
||
using ytLive.Services;
|
||
using ytLive.ViewModels;
|
||
|
||
namespace ytLive.Tests;
|
||
|
||
/// <summary>
|
||
/// The desktop-"lock" bug (2026-10-10): at launch the main window ACTIVES
|
||
/// (WPF default <c>ShowActivated = true</c>), and when the creator is already
|
||
/// playing an exclusive-fullscreen game, activating LlamaCasty makes Windows
|
||
/// drop that game to the taskbar; the app's 1920×1040 window then sits over the
|
||
/// whole work area, so the desktop looks locked and the game can't be reached
|
||
/// with the mouse. Fix: the window opens WITHOUT activating when a full-screen
|
||
/// game owns the foreground at launch — <c>ShowActivated = !FullscreenGameRunningNow</c>.
|
||
/// These tests pin that rule using the <c>FullScreenDetectorOverride</c> seam,
|
||
/// so no real Win32 foreground state is touched.
|
||
/// </summary>
|
||
[Collection("RealApp")]
|
||
public sealed class DesktopLockTests
|
||
{
|
||
private readonly RealAppHost _app;
|
||
|
||
public DesktopLockTests(RealAppHost app) => _app = app;
|
||
|
||
[Fact]
|
||
public void MainWindow_Does_Not_Steal_Focus_When_A_Fullscreen_Game_Is_Foreground()
|
||
{
|
||
_app.Run(() =>
|
||
{
|
||
using var _ = new TempLayout();
|
||
MainViewModel.FullScreenDetectorOverride = new StubFullScreenDetector(foregroundMonitor: 0);
|
||
try
|
||
{
|
||
var window = new MainWindow();
|
||
try
|
||
{
|
||
// The regression: a full-screen game already owns the screen, so
|
||
// the window must open WITHOUT activating to keep the game live.
|
||
Assert.False(window.ShowActivated,
|
||
"launching while a full-screen game owns the foreground must not steal focus");
|
||
}
|
||
finally
|
||
{
|
||
window.Close();
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
MainViewModel.FullScreenDetectorOverride = null;
|
||
}
|
||
});
|
||
}
|
||
|
||
[Fact]
|
||
public void MainWindow_Normal_Launch_Still_Activates()
|
||
{
|
||
_app.Run(() =>
|
||
{
|
||
using var _ = new TempLayout();
|
||
MainViewModel.FullScreenDetectorOverride = new StubFullScreenDetector(foregroundMonitor: null);
|
||
try
|
||
{
|
||
var window = new MainWindow();
|
||
try
|
||
{
|
||
// No game running: behaviour is exactly as before the fix.
|
||
Assert.True(window.ShowActivated,
|
||
"a normal launch (no full-screen game) must keep the default activate-on-show");
|
||
}
|
||
finally
|
||
{
|
||
window.Close();
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
MainViewModel.FullScreenDetectorOverride = null;
|
||
}
|
||
});
|
||
}
|
||
|
||
[Fact]
|
||
public void FullscreenGameRunningNow_Reflects_The_Foreground_Monitor()
|
||
{
|
||
_app.Run(() =>
|
||
{
|
||
MainViewModel.FullScreenDetectorOverride = new StubFullScreenDetector(foregroundMonitor: 0);
|
||
try
|
||
{
|
||
var gameVm = new MainViewModel();
|
||
Assert.True(gameVm.FullscreenGameRunningNow);
|
||
}
|
||
finally
|
||
{
|
||
MainViewModel.FullScreenDetectorOverride = null;
|
||
}
|
||
|
||
MainViewModel.FullScreenDetectorOverride = new StubFullScreenDetector(foregroundMonitor: null);
|
||
try
|
||
{
|
||
var idleVm = new MainViewModel();
|
||
Assert.False(idleVm.FullscreenGameRunningNow);
|
||
}
|
||
finally
|
||
{
|
||
MainViewModel.FullScreenDetectorOverride = null;
|
||
}
|
||
});
|
||
}
|
||
|
||
private sealed class TempLayout : IDisposable
|
||
{
|
||
private readonly string _path;
|
||
|
||
public TempLayout()
|
||
{
|
||
_path = Path.Combine(Path.GetTempPath(), $"ytLive-desktoplock-{Guid.NewGuid():N}.db");
|
||
using (var schema = new LayoutStore(_path)) { }
|
||
SqliteConnection.ClearAllPools();
|
||
MainViewModel.LayoutPathOverride = _path;
|
||
}
|
||
|
||
public void Dispose()
|
||
{
|
||
MainViewModel.LayoutPathOverride = null;
|
||
SqliteConnection.ClearAllPools();
|
||
try { File.Delete(_path); } catch { /* best-effort cleanup */ }
|
||
}
|
||
}
|
||
|
||
/// <summary>A deterministic stand-in for <see cref="Win32FullScreenDetector"/>:
|
||
/// claims a full-screen window owns the given foreground monitor (or none).</summary>
|
||
#pragma warning disable CS0067 // fullscreen-changed wiring is not part of this seam
|
||
private sealed class StubFullScreenDetector : IFullScreenDetector
|
||
{
|
||
private readonly int? _foregroundMonitor;
|
||
|
||
public StubFullScreenDetector(int? foregroundMonitor) => _foregroundMonitor = foregroundMonitor;
|
||
|
||
public int? GetForegroundFullScreenMonitorIndex() => _foregroundMonitor;
|
||
public int PrimaryMonitorIndex() => 0;
|
||
public IReadOnlyList<DisplayInfo> GetDisplays() => Array.Empty<DisplayInfo>();
|
||
public event Action<int?>? FullscreenMonitorChanged;
|
||
public void StartWatching() { }
|
||
public void StopWatching() { }
|
||
}
|
||
} |