Skip to content

Add F11 fullscreen toggle support#1879

Merged
emako merged 10 commits intomasterfrom
copilot/add-quicklook-fullscreen-support
Apr 1, 2026
Merged

Add F11 fullscreen toggle support#1879
emako merged 10 commits intomasterfrom
copilot/add-quicklook-fullscreen-support

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 13, 2026

Implements F11 key binding to toggle true fullscreen mode (borderless window covering entire screen), particularly useful for video playback.

Implementation

  • KeystrokeDispatcher: Added F11 to valid keys, routes to new PipeMessages.Fullscreen
  • ViewerWindow: Implements fullscreen toggle with state preservation
    • Saves/restores WindowState, WindowStyle, ResizeMode, and bounds
    • Hides window chrome and taskbar in fullscreen
    • Handles maximized → fullscreen transition via RestoreBounds
  • DPI-aware positioning: Converts physical screen bounds to DIPs using DisplayDeviceHelper.GetScaleFactorFromWindow()
  • Multi-monitor: Uses Screen.FromHandle() to detect current display

Technical Details

Fullscreen implementation uses WindowStyle.None + ResizeMode.NoResize with manual bounds management rather than WindowState.Maximized to achieve true fullscreen (taskbar hidden).

Window property restoration order minimizes visual flicker:

  1. Restore WindowStyle and ResizeMode
  2. Restore position and size
  3. Restore WindowState last

DPI scaling is critical for high-DPI displays:

var scale = DisplayDeviceHelper.GetScaleFactorFromWindow(this);
var dipWidth = screenBounds.Width / scale.Horizontal;
var dipHeight = screenBounds.Height / scale.Vertical;
this.MoveWindow(screenBounds.Left, screenBounds.Top, dipWidth, dipHeight);
Original prompt

This section details on the original issue you should resolve

<issue_title>Open directly in full screen with F11</issue_title>
<issue_description>Is your feature request related to a problem? Please describe.
I would like to be able to hit for example ALT-SPACE (or similar) to open QuickLook directly in full screen mode. With videos this is often desirable.

Describe the solution you'd like
When I hit ALT-SPACE, instead of opening as a window, QuickLook would open in full screen directly.

</issue_description>

<agent_instructions>新增支持F11全屏显示窗口</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@emako MS's habit is usually implemented using F11, we can consider F11

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Summary by Sourcery

Add support for toggling the viewer window into and out of true fullscreen mode via a new pipe message and keyboard shortcut.

New Features:

  • Allow toggling the viewer window between normal and borderless fullscreen using the F11 key.
  • Expose a fullscreen toggle operation through the pipe messaging system so it can be triggered programmatically.

Enhancements:

  • Preserve and restore the viewer window’s prior size, position, and window chrome when entering and exiting fullscreen, with DPI-aware handling and multi-monitor support.

Copilot AI and others added 9 commits February 13, 2026 04:04
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
…readability)

Co-authored-by: emako <24737061+emako@users.noreply.github.com>
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
Copilot AI changed the title [WIP] Add support to open QuickLook in full screen with ALT-SPACE Add F11 fullscreen toggle support Feb 13, 2026
Copilot AI requested a review from emako February 13, 2026 04:20
@emako emako marked this pull request as ready for review April 1, 2026 03:41
Copilot AI review requested due to automatic review settings April 1, 2026 03:41
@emako emako merged commit acbde61 into master Apr 1, 2026
3 checks passed
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Apr 1, 2026

Reviewer's Guide

Adds an F11-triggered true fullscreen toggle for the viewer window, wiring a new pipe message through the keystroke dispatcher and pipe server to ViewerWindow, which manages fullscreen entry/exit with saved window state, DPI-aware sizing, and multi-monitor support.

Sequence diagram for F11 fullscreen toggle pipeline

sequenceDiagram
    actor User
    participant KeystrokeDispatcher
    participant PipeServerManager
    participant ViewWindowManager
    participant ViewerWindow

    User->>KeystrokeDispatcher: press F11 (key down)
    KeystrokeDispatcher->>PipeServerManager: SendMessage(PipeMessages.Fullscreen)
    PipeServerManager->>PipeServerManager: MessageReceived(Fullscreen)
    PipeServerManager-->>ViewWindowManager: GetInstance().ToggleFullscreen()
    ViewWindowManager->>ViewerWindow: ToggleFullscreen()
    alt entering fullscreen
        ViewerWindow->>ViewerWindow: save preFullscreen state
        ViewerWindow->>ViewerWindow: detect screen via Screen.FromHandle
        ViewerWindow->>ViewerWindow: get DPI via GetScaleFactorFromWindow
        ViewerWindow->>ViewerWindow: WindowState = Normal
        ViewerWindow->>ViewerWindow: WindowStyle = None
        ViewerWindow->>ViewerWindow: ResizeMode = NoResize
        ViewerWindow->>ViewerWindow: MoveWindow to screen bounds
    else exiting fullscreen
        ViewerWindow->>ViewerWindow: restore WindowStyle and ResizeMode
        ViewerWindow->>ViewerWindow: restore Left, Top, Width, Height
        ViewerWindow->>ViewerWindow: restore WindowState
    end
Loading

Class diagram for new fullscreen-related members

classDiagram
    class KeystrokeDispatcher {
        - HashSet~Keys~ _validKeys
        + KeystrokeDispatcher()
        - void InvokeRoutine(Keys key, bool isKeyDown)
    }

    class PipeMessages {
        <<static>>
        + string Toggle
        + string Forget
        + string Close
        + string Quit
        + string Fullscreen
    }

    class PipeServerManager {
        + void Dispose()
        + static void SendMessage(string message)
        - bool MessageReceived(string msg)
    }

    class ViewWindowManager {
        - static ViewWindowManager _instance
        - ViewerWindow _viewerWindow
        + static ViewWindowManager GetInstance()
        + void ReloadPreview()
        + void ToggleFullscreen()
    }

    class ViewerWindow {
        + event PropertyChangedEventHandler PropertyChanged
        - bool _canOldPluginResize
        - bool _pinned
        - bool _isFullscreen
        - WindowState _preFullscreenWindowState
        - WindowStyle _preFullscreenWindowStyle
        - ResizeMode _preFullscreenResizeMode
        - Rect _preFullscreenBounds
        + void RunAndClose()
        + void ToggleFullscreen()
        - void PositionWindow(Size size)
    }

    KeystrokeDispatcher ..> PipeServerManager : sends PipeMessages
    PipeServerManager ..> PipeMessages : uses
    PipeServerManager ..> ViewWindowManager : invokes
    ViewWindowManager o--> ViewerWindow : manages
    ViewWindowManager ..> PipeMessages : uses Fullscreen
    ViewerWindow ..> DisplayDeviceHelper : uses GetScaleFactorFromWindow
    ViewerWindow ..> System_Windows_Forms_Screen : uses FromHandle
    class DisplayDeviceHelper
    class System_Windows_Forms_Screen
Loading

File-Level Changes

Change Details Files
Implement true fullscreen toggle behavior in ViewerWindow with state preservation and DPI-aware, multi-monitor positioning.
  • Add ToggleFullscreen() to enter/exit fullscreen while saving/restoring window state, style, resize mode, and bounds
  • Handle transitions from maximized windows using RestoreBounds when entering fullscreen
  • Use WinForms.Screen.FromHandle and DisplayDeviceHelper.GetScaleFactorFromWindow to compute the current monitor bounds and convert to WPF DIPs before resizing/moving the window
  • Hide window chrome and disable resizing in fullscreen using WindowStyle.None and ResizeMode.NoResize
  • Store pre-fullscreen values in new private fields on ViewerWindow for correct restoration order and reduced flicker
QuickLook/ViewerWindow.Actions.cs
QuickLook/ViewerWindow.Properties.cs
Expose fullscreen toggle from the window manager and wire it through the pipe messaging system.
  • Add ToggleFullscreen() method on ViewWindowManager that delegates to the current ViewerWindow when visible
  • Introduce a new PipeMessages.Fullscreen constant and handle it in PipeServerManager by dispatching to ViewWindowManager.ToggleFullscreen on the UI thread
QuickLook/ViewWindowManager.cs
QuickLook/PipeServerManager.cs
Add F11 key support to trigger the fullscreen toggle via pipes.
  • Extend the set of valid keys in KeystrokeDispatcher to include Keys.F11
  • On F11 key down, send the new PipeMessages.Fullscreen message via PipeServerManager
QuickLook/KeystrokeDispatcher.cs

Assessment against linked issues

Issue Objective Addressed Explanation
#253 Add an F11 keyboard shortcut that triggers a fullscreen action in QuickLook via the existing keystroke/pipe infrastructure.
#253 Implement a true fullscreen mode for the viewer window (borderless, taskbar-hidden, DPI-aware, and reversible) and wire it to the fullscreen command.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="QuickLook/ViewerWindow.Actions.cs" line_range="127" />
<code_context>
+            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);
+        }
+    }
</code_context>
<issue_to_address>
**issue (bug_risk):** Screen coordinates are mixed between physical pixels and DIPs when calling `MoveWindow`, which can break on high-DPI setups.

Here `screenBounds.Left/Top` are still in physical pixels while `dipWidth/dipHeight` are DIPs. Please either convert Left/Top with the same DPI scale, or keep all four values in physical pixels so `MoveWindow` gets a consistent coordinate system.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

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);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Screen coordinates are mixed between physical pixels and DIPs when calling MoveWindow, which can break on high-DPI setups.

Here screenBounds.Left/Top are still in physical pixels while dipWidth/dipHeight are DIPs. Please either convert Left/Top with the same DPI scale, or keep all four values in physical pixels so MoveWindow gets a consistent coordinate system.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an F11 key binding to toggle a “true fullscreen” (borderless, monitor-sized) preview window, routed through the existing pipe-message system and implemented in ViewerWindow with state save/restore.

Changes:

  • Added a new pipe message (PipeMessages.Fullscreen) and dispatch path to toggle fullscreen.
  • Extended the global keystroke dispatcher to recognize F11 and send the fullscreen pipe message.
  • Implemented fullscreen state tracking and window property/bounds preservation in ViewerWindow.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
QuickLook/KeystrokeDispatcher.cs Recognizes Keys.F11 and sends the new fullscreen pipe message.
QuickLook/PipeServerManager.cs Adds PipeMessages.Fullscreen and routes it to ViewWindowManager.ToggleFullscreen().
QuickLook/ViewWindowManager.cs Exposes ToggleFullscreen() and forwards to the active ViewerWindow.
QuickLook/ViewerWindow.Properties.cs Adds fields to track fullscreen state and pre-fullscreen window properties/bounds.
QuickLook/ViewerWindow.Actions.cs Implements the fullscreen toggle behavior (save/restore + monitor/DPI-aware sizing).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +79 to +83
Left = _preFullscreenBounds.Left;
Top = _preFullscreenBounds.Top;
Width = _preFullscreenBounds.Width;
Height = _preFullscreenBounds.Height;

Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Entering/exiting fullscreen changes Width/Height programmatically, but the window’s SizeChanged handler treats any non-ignored resize as user-driven and sets _customWindowSize. This means toggling fullscreen can “lock” future previews to the last fullscreen/restored size instead of auto-sizing to the plugin’s PreferredSize. Consider temporarily suppressing SaveWindowSizeOnSizeChanged during fullscreen transitions (e.g., set _ignoreNextWindowSizeChange for each expected size change or store/restore _customWindowSize around the toggle).

Copilot uses AI. Check for mistakes.
Comment on lines +89 to +96
// Enter fullscreen
_isFullscreen = true;

// Save current window properties before any changes
_preFullscreenWindowState = WindowState;
_preFullscreenWindowStyle = WindowStyle;
_preFullscreenResizeMode = ResizeMode;

Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fullscreen uses WindowState.Normal, so subsequent preview loads (BeginShow → PositionWindow) can still reposition/resize the window and effectively break fullscreen while _isFullscreen remains true. Consider short-circuiting PositionWindow/BeginShow while _isFullscreen is set, or otherwise ensuring plugin-driven resizing doesn’t run during fullscreen.

Copilot uses AI. Check for mistakes.
Comment on lines 135 to +141
case Keys.Space:
PipeServerManager.SendMessage(PipeMessages.Toggle);
break;

case Keys.F11:
PipeServerManager.SendMessage(PipeMessages.Fullscreen);
break;
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

F11 is handled on KeyDown, but low-level hooks receive auto-repeat WM_KEYDOWN events while the key is held. Holding F11 will likely spam toggle requests and rapidly flip fullscreen on/off. Consider de-bouncing (track an "F11 is down" flag like Space) or triggering fullscreen on KeyUp instead.

Copilot uses AI. Check for mistakes.
@emako emako deleted the copilot/add-quicklook-fullscreen-support branch April 1, 2026 03:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Open directly in full screen with F11

3 participants