Screen backdrop (schema v5/v6) + five-scene catalog + webcam polish: live desktop/game capture as a permanent non-deletable bottom layer (Source.IsBackdrop), auto full-screen game detection (Win32FullScreenDetector) else primary display, GraphicsCapturePicker re-designation, refcounted shared ScreenCaptureManager, Live-only backdrop by policy (HasBackdrop + v5-v6 backfill + EnforceBackdropPolicy, checkbox gone), SceneCatalog (Starting/Live/BRB/Chat/Ending) with + button re-adding missing scenes, webcam mid-session transparent-container fix (GetPreviewBitmap propagation), Chat half-screen-area cap, 'Add Webcam' always opens the picker (SwapWebcamIdentityAsync, no silent resurrect), WindowsRuntimeMarshal frame-read + 5s-throttled errors, docs updated, tests (65 passing)

This commit is contained in:
2026-08-07 14:15:50 -07:00
parent e037ba027b
commit ad9b3e1e48
27 changed files with 2232 additions and 116 deletions
+38 -2
View File
@@ -46,6 +46,16 @@ public partial class MainWindow : Window
_viewModel.Shutdown();
}
private void MainWindow_Activated(object? sender, EventArgs e)
{
_viewModel.RefreshBackdropAutoCapture();
}
private void MainWindow_Deactivated(object? sender, EventArgs e)
{
_viewModel.NoteBackgroundWindow();
}
private void UpdateTaskbarOverlay()
{
TaskbarInfo.Overlay = _viewModel.IsLive
@@ -91,6 +101,16 @@ public partial class MainWindow : Window
}
}
private void AddSceneButton_Click(object sender, RoutedEventArgs e)
{
if (sender is Button { ContextMenu: { } menu } button)
{
menu.PlacementTarget = button;
menu.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
menu.IsOpen = true;
}
}
// ─── Preview image selection / move / resize ───
private bool _isDraggingOverlay;
private bool _isResizing;
@@ -166,6 +186,22 @@ public partial class MainWindow : Window
_viewModel.RemoveSourceCommand.Execute(element);
}
private void BackdropMenu_ChangeCapture(object sender, RoutedEventArgs e)
{
_ = _viewModel.ChangeBackdropCaptureAsync();
}
private void BackdropMenu_RefreshCapture(object sender, RoutedEventArgs e)
{
_viewModel.RefreshBackdropAutoCapture();
}
private void SourceMenu_Remove(object sender, RoutedEventArgs e)
{
if (sender is MenuItem { DataContext: SceneElement element })
_viewModel.RemoveSourceCommand.Execute(element);
}
private void OpacitySlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
=> OpacityValueText.Text = $"{Math.Round(e.NewValue * 100)}%";
@@ -227,8 +263,8 @@ public partial class MainWindow : Window
else if (_isResizing)
{
var isWebcam = selected is WebcamSceneConfig;
var maxW = isWebcam ? MainViewModel.WebcamMaxWidth : 1920;
var maxH = isWebcam ? MainViewModel.WebcamMaxHeight : 1080;
var maxW = isWebcam ? MainViewModel.MaxWebcamWidthFor(_viewModel.ActiveScene?.Name) : 1920;
var maxH = isWebcam ? MainViewModel.MaxWebcamHeightFor(_viewModel.ActiveScene?.Name) : 1080;
var newW = Math.Clamp(p.X - selected.X, 32, maxW);
var newH = newW / _resizeAspect;
if (newH > maxH)