diff --git a/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/App.xaml.cs b/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/App.xaml.cs index ad7bc1f5ee..2b0b75127f 100644 --- a/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/App.xaml.cs +++ b/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/App.xaml.cs @@ -10,8 +10,6 @@ using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Telemetry; using Microsoft.UI.Dispatching; using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Media; using Microsoft.Windows.AppLifecycle; using PowerDisplay.Helpers; using PowerDisplay.Serialization; @@ -75,11 +73,7 @@ namespace PowerDisplay /// private void OnUnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) { - // Try to display error information - ShowStartupError(e.Exception); - - // Mark exception as handled to prevent app crash - e.Handled = true; + Logger.LogError("Unhandled exception", e.Exception); } /// @@ -196,7 +190,7 @@ namespace PowerDisplay } catch (Exception ex) { - ShowStartupError(ex); + Logger.LogError("PowerDisplay startup failed", ex); } } @@ -260,66 +254,6 @@ namespace PowerDisplay CancellationToken.None); } - /// - /// Show startup error - /// - private void ShowStartupError(Exception ex) - { - try - { - Logger.LogError($"PowerDisplay startup failed: {ex.Message}"); - - var errorWindow = new Window { Title = "PowerDisplay - Startup Error" }; - var panel = new StackPanel { Margin = new Thickness(20), Spacing = 16 }; - - panel.Children.Add(new TextBlock - { - Text = "PowerDisplay Startup Failed", - FontSize = 20, - FontWeight = Microsoft.UI.Text.FontWeights.SemiBold, - }); - - panel.Children.Add(new TextBlock - { - Text = $"Error: {ex.Message}", - FontSize = 14, - TextWrapping = TextWrapping.Wrap, - }); - - panel.Children.Add(new TextBlock - { - Text = $"Details:\n{ex}", - FontSize = 12, - TextWrapping = TextWrapping.Wrap, - Foreground = new SolidColorBrush(Microsoft.UI.Colors.Gray), - Margin = new Thickness(0, 10, 0, 0), - }); - - var closeButton = new Button - { - Content = "Close", - HorizontalAlignment = HorizontalAlignment.Right, - Margin = new Thickness(0, 10, 0, 0), - }; - closeButton.Click += (_, _) => errorWindow.Close(); - panel.Children.Add(closeButton); - - errorWindow.Content = new ScrollViewer - { - Content = panel, - VerticalScrollBarVisibility = ScrollBarVisibility.Auto, - MaxHeight = 600, - MaxWidth = 800, - }; - - errorWindow.Activate(); - } - catch - { - Environment.Exit(1); - } - } - /// /// Gets the main window instance /// diff --git a/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/IdentifyWindow.xaml b/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/IdentifyWindow.xaml index e4284b239d..8a5124361a 100644 --- a/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/IdentifyWindow.xaml +++ b/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/IdentifyWindow.xaml @@ -1,11 +1,11 @@ - - + /// Interaction logic for IdentifyWindow.xaml /// - public sealed partial class IdentifyWindow : Window, IDisposable + public sealed partial class IdentifyWindow : Window { + // Window size in device-independent units (DIU) + private const int WindowWidthDiu = 300; + private const int WindowHeightDiu = 280; + private AppWindow? _appWindow; - private DesktopAcrylicController? _acrylicController; - private SystemBackdropConfiguration? _configurationSource; - private bool _disposed; + private double _dpiScale = 1.0; + + [LibraryImport("user32.dll")] + private static partial uint GetDpiForWindow(IntPtr hwnd); public IdentifyWindow(int number) { @@ -49,6 +54,9 @@ namespace PowerDisplay.PowerDisplayXAML var windowId = Win32Interop.GetWindowIdFromWindow(hwnd); _appWindow = AppWindow.GetFromWindowId(windowId); + // Get DPI scale for this window + _dpiScale = GetDpiForWindow(hwnd) / 96.0; + if (_appWindow != null) { // Remove title bar using OverlappedPresenter @@ -61,38 +69,17 @@ namespace PowerDisplay.PowerDisplayXAML presenter.IsMaximizable = false; } - // Set window size to fit the large number (200pt font) - _appWindow.Resize(new SizeInt32 { Width = 300, Height = 280 }); + // Set window size scaled for DPI + // AppWindow.Resize expects physical pixels + int physicalWidth = (int)(WindowWidthDiu * _dpiScale); + int physicalHeight = (int)(WindowHeightDiu * _dpiScale); + _appWindow.Resize(new SizeInt32 { Width = physicalWidth, Height = physicalHeight }); } // Set window topmost and hide from taskbar WindowHelper.SetWindowTopmost(hwnd, true); WindowHelper.HideFromTaskbar(hwnd); WindowHelper.DisableWindowMovingAndResizing(hwnd); - - // Configure 90% transparent acrylic backdrop - ConfigureAcrylicBackdrop(); - } - - private void ConfigureAcrylicBackdrop() - { - if (!DesktopAcrylicController.IsSupported()) - { - return; - } - - _configurationSource = new SystemBackdropConfiguration(); - _acrylicController = new DesktopAcrylicController(); - - // Set 90% transparency (TintOpacity 0.1 = 10% tint = 90% transparent) - _acrylicController.TintColor = Windows.UI.Color.FromArgb(255, 0, 0, 0); - _acrylicController.TintOpacity = 0.1f; - _acrylicController.LuminosityOpacity = 0f; - - // Add target using WinRT cast - var target = WinRT.CastExtensions.As(this); - _acrylicController.AddSystemBackdropTarget(target); - _acrylicController.SetSystemBackdropConfiguration(_configurationSource); } /// @@ -106,26 +93,16 @@ namespace PowerDisplay.PowerDisplayXAML } var workArea = displayArea.WorkArea; - int windowWidth = 300; - int windowHeight = 280; + + // Window size in physical pixels (already scaled for DPI) + int physicalWidth = (int)(WindowWidthDiu * _dpiScale); + int physicalHeight = (int)(WindowHeightDiu * _dpiScale); // Calculate center position (WorkArea coordinates are in physical pixels) - int x = workArea.X + ((workArea.Width - windowWidth) / 2); - int y = workArea.Y + ((workArea.Height - windowHeight) / 2); + int x = workArea.X + ((workArea.Width - physicalWidth) / 2); + int y = workArea.Y + ((workArea.Height - physicalHeight) / 2); _appWindow.Move(new PointInt32(x, y)); } - - public void Dispose() - { - if (_disposed) - { - return; - } - - _disposed = true; - _acrylicController?.Dispose(); - _acrylicController = null; - } } } diff --git a/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/MainWindow.xaml b/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/MainWindow.xaml index d747fd252c..80ec7fba87 100644 --- a/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/MainWindow.xaml +++ b/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/MainWindow.xaml @@ -193,7 +193,6 @@ Minimum="{x:Bind MinBrightness, Mode=OneWay}" PointerCaptureLost="Slider_PointerCaptureLost" Tag="Brightness" - ValueChanged="Slider_ValueChanged" Value="{x:Bind Brightness, Mode=OneWay}" /> @@ -226,7 +225,6 @@ Minimum="0" PointerCaptureLost="Slider_PointerCaptureLost" Tag="Contrast" - ValueChanged="Slider_ValueChanged" Value="{x:Bind ContrastPercent, Mode=OneWay}" /> @@ -260,7 +258,6 @@ Minimum="{x:Bind MinVolume, Mode=OneWay}" PointerCaptureLost="Slider_PointerCaptureLost" Tag="Volume" - ValueChanged="Slider_ValueChanged" Value="{x:Bind Volume, Mode=OneWay}" /> diff --git a/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/MainWindow.xaml.cs b/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/MainWindow.xaml.cs index 08c28ad8f0..e20fa83a4a 100644 --- a/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/MainWindow.xaml.cs +++ b/src/modules/powerdisplay/PowerDisplay/PowerDisplayXAML/MainWindow.xaml.cs @@ -9,12 +9,9 @@ using System.Threading.Tasks; using ManagedCommon; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.UI; -using Microsoft.UI.Composition; using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Media; -using Microsoft.UI.Xaml.Media.Animation; using PowerDisplay.Common.Models; using PowerDisplay.Configuration; using PowerDisplay.Helpers; @@ -602,17 +599,6 @@ namespace PowerDisplay } } - /// - /// Slider ValueChanged event handler - does nothing during drag - /// This allows the slider UI to update smoothly without triggering hardware operations - /// - private void Slider_ValueChanged(object sender, Microsoft.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e) - { - // During drag, this event fires 60-120 times per second - // We intentionally do nothing here to keep UI smooth - // The actual ViewModel update happens in PointerCaptureLost after drag completes - } - /// /// Slider PointerCaptureLost event handler - updates ViewModel when drag completes /// This is the WinUI3 recommended way to detect drag completion @@ -663,75 +649,6 @@ namespace PowerDisplay Logger.LogDebug($"[UI] ViewModel property {propertyName} updated successfully"); } - /// - /// Input source item click handler - switches the monitor input source - /// - private async void InputSourceItem_Click(object sender, RoutedEventArgs e) - { - Logger.LogInfo("[UI] InputSourceItem_Click: Event triggered!"); - - if (sender is not Button button) - { - Logger.LogWarning("[UI] InputSourceItem_Click: sender is not Button"); - return; - } - - Logger.LogInfo($"[UI] InputSourceItem_Click: Button clicked, Tag type = {button.Tag?.GetType().Name ?? "null"}, DataContext type = {button.DataContext?.GetType().Name ?? "null"}"); - - // Get the InputSourceItem from Tag (not DataContext - Flyout doesn't inherit DataContext properly) - var inputSourceItem = button.Tag as InputSourceItem; - if (inputSourceItem == null) - { - Logger.LogWarning("[UI] InputSourceItem_Click: Tag is not InputSourceItem"); - return; - } - - Logger.LogInfo($"[UI] InputSourceItem_Click: InputSourceItem found - Value=0x{inputSourceItem.Value:X2}, Name={inputSourceItem.Name}, MonitorId={inputSourceItem.MonitorId}"); - - int inputSourceValue = inputSourceItem.Value; - string monitorId = inputSourceItem.MonitorId; - - // Use MonitorId for direct lookup (Flyout popup is not in visual tree) - MonitorViewModel? monitorVm = null; - - if (!string.IsNullOrEmpty(monitorId) && _viewModel != null) - { - monitorVm = _viewModel.Monitors.FirstOrDefault(m => m.Id == monitorId); - Logger.LogInfo($"[UI] InputSourceItem_Click: Found MonitorViewModel by ID: {monitorVm?.Name ?? "null"}"); - } - - // Fallback: search through all monitors (for backwards compatibility) - if (monitorVm == null && _viewModel != null) - { - Logger.LogInfo("[UI] InputSourceItem_Click: MonitorId lookup failed, trying fallback search"); - foreach (var vm in _viewModel.Monitors) - { - if (vm.SupportsInputSource && vm.AvailableInputSources != null) - { - if (vm.AvailableInputSources.Any(s => s.Value == inputSourceValue)) - { - monitorVm = vm; - Logger.LogInfo($"[UI] InputSourceItem_Click: Found MonitorViewModel by fallback: {vm.Name}"); - break; - } - } - } - } - - if (monitorVm == null) - { - Logger.LogWarning("[UI] InputSourceItem_Click: Could not find MonitorViewModel"); - return; - } - - Logger.LogInfo($"[UI] Switching input source for {monitorVm.Name} to 0x{inputSourceValue:X2} ({inputSourceItem.Name})"); - - // Set the input source - await monitorVm.SetInputSourceAsync(inputSourceValue); - - Logger.LogInfo("[UI] InputSourceItem_Click: SetInputSourceAsync completed"); - } - /// /// Input source ListView selection changed handler - switches the monitor input source /// @@ -766,13 +683,6 @@ namespace PowerDisplay // Set the input source await monitorVm.SetInputSourceAsync(selectedItem.Value); - - // Close the flyout after selection - if (listView.Parent is StackPanel stackPanel && - stackPanel.Parent is Flyout flyout) - { - flyout.Hide(); - } } ///