From acbde61409eb83b08b70c3550d3a6353dc470d99 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Apr 2026 11:42:33 +0800 Subject: [PATCH] Add F11 fullscreen toggle support (#1879) --- QuickLook/KeystrokeDispatcher.cs | 6 ++- QuickLook/PipeServerManager.cs | 7 +++ QuickLook/ViewWindowManager.cs | 8 ++++ QuickLook/ViewerWindow.Actions.cs | 66 ++++++++++++++++++++++++++++ QuickLook/ViewerWindow.Properties.cs | 5 +++ 5 files changed, 91 insertions(+), 1 deletion(-) diff --git a/QuickLook/KeystrokeDispatcher.cs b/QuickLook/KeystrokeDispatcher.cs index c6e38b8..e9db56c 100644 --- a/QuickLook/KeystrokeDispatcher.cs +++ b/QuickLook/KeystrokeDispatcher.cs @@ -46,7 +46,7 @@ internal class KeystrokeDispatcher : IDisposable _validKeys = [ Keys.Up, Keys.Down, Keys.Left, Keys.Right, - Keys.Enter, Keys.Space, Keys.Escape + Keys.Enter, Keys.Space, Keys.Escape, Keys.F11 ]; } @@ -135,6 +135,10 @@ internal class KeystrokeDispatcher : IDisposable case Keys.Space: PipeServerManager.SendMessage(PipeMessages.Toggle); break; + + case Keys.F11: + PipeServerManager.SendMessage(PipeMessages.Fullscreen); + break; } } else diff --git a/QuickLook/PipeServerManager.cs b/QuickLook/PipeServerManager.cs index db13216..92a3b35 100644 --- a/QuickLook/PipeServerManager.cs +++ b/QuickLook/PipeServerManager.cs @@ -36,6 +36,7 @@ public static class PipeMessages public const string Forget = "QuickLook.App.PipeMessages.Forget"; public const string Close = "QuickLook.App.PipeMessages.Close"; public const string Quit = "QuickLook.App.PipeMessages.Quit"; + public const string Fullscreen = "QuickLook.App.PipeMessages.Fullscreen"; } public class PipeServerManager : IDisposable @@ -161,6 +162,12 @@ public class PipeServerManager : IDisposable DispatcherPriority.ApplicationIdle); return false; + case PipeMessages.Fullscreen: + Application.Current.Dispatcher.BeginInvoke( + new Action(() => ViewWindowManager.GetInstance().ToggleFullscreen()), + DispatcherPriority.ApplicationIdle); + return false; + case PipeMessages.Quit: return true; diff --git a/QuickLook/ViewWindowManager.cs b/QuickLook/ViewWindowManager.cs index 3ab9ae3..56b6c5e 100644 --- a/QuickLook/ViewWindowManager.cs +++ b/QuickLook/ViewWindowManager.cs @@ -198,6 +198,14 @@ public class ViewWindowManager : IDisposable BeginShowNewWindow(_invokedPath, matchedPlugin); } + public void ToggleFullscreen() + { + if (!_viewerWindow.IsVisible) + return; + + _viewerWindow.ToggleFullscreen(); + } + private void BeginShowNewWindow(string path, IViewer matchedPlugin) { _viewerWindow.UnloadPlugin(); diff --git a/QuickLook/ViewerWindow.Actions.cs b/QuickLook/ViewerWindow.Actions.cs index 8d1f4cb..90032f0 100644 --- a/QuickLook/ViewerWindow.Actions.cs +++ b/QuickLook/ViewerWindow.Actions.cs @@ -29,9 +29,11 @@ using System.Runtime.ExceptionServices; using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using System.Windows.Interop; using System.Windows.Media; using System.Windows.Threading; using Wpf.Ui.Controls; +using WinForms = System.Windows.Forms; using MenuItem = System.Windows.Controls.MenuItem; namespace QuickLook; @@ -62,6 +64,70 @@ public partial class ViewerWindow Close(); } + internal void ToggleFullscreen() + { + if (_isFullscreen) + { + // Exit fullscreen + _isFullscreen = false; + + // Restore window properties + WindowStyle = _preFullscreenWindowStyle; + ResizeMode = _preFullscreenResizeMode; + + // Restore position and size + Left = _preFullscreenBounds.Left; + Top = _preFullscreenBounds.Top; + Width = _preFullscreenBounds.Width; + Height = _preFullscreenBounds.Height; + + // Restore window state last to avoid flicker + WindowState = _preFullscreenWindowState; + } + else + { + // Enter fullscreen + _isFullscreen = true; + + // Save current window properties before any changes + _preFullscreenWindowState = WindowState; + _preFullscreenWindowStyle = WindowStyle; + _preFullscreenResizeMode = ResizeMode; + + // Get current bounds (account for maximized state) + if (WindowState == WindowState.Maximized) + { + _preFullscreenBounds = RestoreBounds; + } + else + { + _preFullscreenBounds = new Rect(Left, Top, Width, Height); + } + + // Get the screen bounds where the window is currently located + var screen = WinForms.Screen.FromHandle(new WindowInteropHelper(this).Handle); + var screenBounds = screen.Bounds; + + // Get DPI scale factor for proper coordinate conversion + // scale.Horizontal and scale.Vertical contain the DPI scaling ratios (e.g., 1.5 for 150%) + var scale = DisplayDeviceHelper.GetScaleFactorFromWindow(this); + + // Set to normal state first to allow manual positioning + WindowState = WindowState.Normal; + + // Hide window chrome for true fullscreen + WindowStyle = WindowStyle.None; + ResizeMode = ResizeMode.NoResize; + + // Convert screen bounds from physical pixels to DIPs for WPF + var dipWidth = screenBounds.Width / scale.Horizontal; + var dipHeight = screenBounds.Height / scale.Vertical; + + // Use MoveWindow to set position and size with proper DPI handling + this.MoveWindow(screenBounds.Left, screenBounds.Top, dipWidth, dipHeight); + } + } + private void PositionWindow(Size size) { // If the window is now maximized, do not move it diff --git a/QuickLook/ViewerWindow.Properties.cs b/QuickLook/ViewerWindow.Properties.cs index c459f2c..17ce997 100644 --- a/QuickLook/ViewerWindow.Properties.cs +++ b/QuickLook/ViewerWindow.Properties.cs @@ -37,6 +37,11 @@ public partial class ViewerWindow : INotifyPropertyChanged private bool _canOldPluginResize; private bool _pinned; + private bool _isFullscreen; + private WindowState _preFullscreenWindowState; + private WindowStyle _preFullscreenWindowStyle; + private ResizeMode _preFullscreenResizeMode; + private Rect _preFullscreenBounds; public bool Pinned {