mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-09 20:59:49 +01:00
Compare commits
4 Commits
main
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3e6bc207a | ||
|
|
d2bdda9554 | ||
|
|
3a77770aad | ||
|
|
01920d371d |
126
ARCHITECTURE_NOTES.md
Normal file
126
ARCHITECTURE_NOTES.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# PDF Fullscreen Toggle Fix - Architecture
|
||||
|
||||
## Event Flow Diagram
|
||||
|
||||
```
|
||||
User clicks PDF fullscreen button
|
||||
↓
|
||||
WebView2 (CoreWebView2)
|
||||
ContainsFullScreenElement = true/false
|
||||
↓
|
||||
ContainsFullScreenElementChanged event fires
|
||||
↓
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ BrowserControl.xaml.cs │
|
||||
│ CoreWebView2_ContainsFullScreenElementChanged │
|
||||
│ → FullScreenChanged?.Invoke(isFullScreen) │
|
||||
└─────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ FilePreview.xaml.cs │
|
||||
│ BrowserPreview_FullScreenChanged │
|
||||
│ → FullScreenChanged?.Invoke(this, ...) │
|
||||
└─────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ MainWindow.xaml.cs │
|
||||
│ FilePreviewer_FullScreenChanged │
|
||||
│ → AppWindow.SetPresenter(FullScreen/Default) │
|
||||
└─────────────────────────────────────────────────┘
|
||||
↓
|
||||
Window toggles
|
||||
FullScreen ↔ Windowed mode
|
||||
```
|
||||
|
||||
## Component Responsibilities
|
||||
|
||||
### BrowserControl
|
||||
- **Role**: WebView2 wrapper, direct interface with CoreWebView2
|
||||
- **Responsibility**: Listen to WebView2 events, expose them as custom events
|
||||
- **Key Methods**:
|
||||
- `CoreWebView2_ContainsFullScreenElementChanged()` - Event handler
|
||||
- Raises `FullScreenChanged` event with boolean parameter
|
||||
|
||||
### FilePreview
|
||||
- **Role**: Preview coordinator, manages different preview types
|
||||
- **Responsibility**: Route events from preview controls to main window
|
||||
- **Key Methods**:
|
||||
- `BrowserPreview_FullScreenChanged()` - Event handler
|
||||
- Propagates `FullScreenChanged` event upward
|
||||
|
||||
### MainWindow
|
||||
- **Role**: Application window, manages window-level behavior
|
||||
- **Responsibility**: Handle window presentation mode changes
|
||||
- **Key Methods**:
|
||||
- `FilePreviewer_FullScreenChanged()` - Event handler
|
||||
- Calls `AppWindow.SetPresenter()` to change window mode
|
||||
|
||||
## Key APIs Used
|
||||
|
||||
### CoreWebView2.ContainsFullScreenElementChanged
|
||||
- **Type**: Event
|
||||
- **When**: Fires when PDF viewer's fullscreen button is clicked
|
||||
- **Property**: `CoreWebView2.ContainsFullScreenElement` (bool)
|
||||
- **Documentation**: Part of Microsoft.Web.WebView2.Core namespace
|
||||
|
||||
### AppWindow.SetPresenter()
|
||||
- **Type**: Method
|
||||
- **Parameter**: `AppWindowPresenterKind` enum
|
||||
- **Values**:
|
||||
- `AppWindowPresenterKind.FullScreen` - True fullscreen, hides titlebar
|
||||
- `AppWindowPresenterKind.Default` - Normal overlapped window
|
||||
- **Documentation**: Part of Microsoft.UI.Windowing namespace (WinUI 3)
|
||||
|
||||
## Design Decisions
|
||||
|
||||
### Why Event Propagation?
|
||||
Instead of directly accessing MainWindow from BrowserControl:
|
||||
1. **Separation of Concerns**: BrowserControl shouldn't know about MainWindow
|
||||
2. **Reusability**: BrowserControl can be used in other contexts
|
||||
3. **Testability**: Each component can be tested independently
|
||||
4. **Maintainability**: Clear data flow, easy to debug
|
||||
|
||||
### Why AppWindow.SetPresenter?
|
||||
Alternative approaches considered:
|
||||
1. ~~Manual hiding of titlebar~~ - Complex, doesn't handle all edge cases
|
||||
2. ~~Maximize window~~ - Not true fullscreen, taskbar still visible
|
||||
3. **AppWindow.SetPresenter** ✓ - Native WinUI 3 API, handles everything correctly
|
||||
|
||||
### Why Not Just Hide TitleBar?
|
||||
Setting `ExtendsContentIntoTitleBar = false` and hiding the titlebar isn't sufficient:
|
||||
- Window still has borders
|
||||
- Taskbar remains visible
|
||||
- Window doesn't cover entire screen
|
||||
- Need to manually restore all settings when exiting
|
||||
|
||||
`AppWindowPresenterKind.FullScreen` handles all of this automatically.
|
||||
|
||||
## Edge Cases Handled
|
||||
|
||||
1. **Rapid toggling**: Events are properly subscribed/unsubscribed
|
||||
2. **Navigation between files**: Each file gets its own fullscreen state
|
||||
3. **Escape key**: Existing behavior preserved (closes Peek)
|
||||
4. **Non-PDF files**: Event only fires for PDF viewer, others unaffected
|
||||
5. **Dispose/cleanup**: Properly unsubscribe from events to prevent leaks
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Potential improvements for consideration:
|
||||
1. **Remember fullscreen preference**: Store user's last fullscreen state
|
||||
2. **Keyboard shortcut**: Add F11 or similar to toggle fullscreen
|
||||
3. **Context menu option**: Right-click menu item for fullscreen
|
||||
4. **Status indicator**: Show fullscreen status in UI
|
||||
5. **Per-file-type settings**: Remember fullscreen preference per file type
|
||||
|
||||
## Related Issues
|
||||
|
||||
This fix addresses:
|
||||
- [Peek] How do I un-fullscreen a PDF? (Main issue)
|
||||
- Any future WebView2 fullscreen requirements in PowerToys
|
||||
- Pattern for handling WebView2 element state changes
|
||||
|
||||
## References
|
||||
|
||||
- WebView2 API: https://learn.microsoft.com/en-us/microsoft-edge/webview2/
|
||||
- WinUI 3 AppWindow: https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindow
|
||||
- PowerToys Peek: https://github.com/microsoft/PowerToys/tree/main/src/modules/peek
|
||||
105
TESTING_NOTES.md
Normal file
105
TESTING_NOTES.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# Testing Notes for PDF Fullscreen Toggle Fix
|
||||
|
||||
## Issue
|
||||
[Peek] How do I un-fullscreen a PDF? (#Issue number to be filled)
|
||||
|
||||
## Summary of Changes
|
||||
Fixed the PDF fullscreen toggle functionality in Peek. When viewing PDFs in Peek, clicking the fullscreen button now properly toggles between fullscreen and windowed modes.
|
||||
|
||||
## Files Changed
|
||||
1. `src/modules/peek/Peek.FilePreviewer/Controls/BrowserControl.xaml.cs`
|
||||
- Added `FullScreenChangedHandler` delegate and `FullScreenChanged` event
|
||||
- Subscribed to `CoreWebView2.ContainsFullScreenElementChanged` event
|
||||
- Added event handler `CoreWebView2_ContainsFullScreenElementChanged`
|
||||
|
||||
2. `src/modules/peek/Peek.FilePreviewer/FilePreview.xaml`
|
||||
- Wired up `FullScreenChanged` event handler to BrowserControl
|
||||
|
||||
3. `src/modules/peek/Peek.FilePreviewer/FilePreview.xaml.cs`
|
||||
- Added `FullScreenChanged` event
|
||||
- Added `BrowserPreview_FullScreenChanged` event handler to propagate state
|
||||
|
||||
4. `src/modules/peek/Peek.UI/PeekXAML/MainWindow.xaml`
|
||||
- Wired up `FullScreenChanged` event handler to FilePreview
|
||||
|
||||
5. `src/modules/peek/Peek.UI/PeekXAML/MainWindow.xaml.cs`
|
||||
- Added `FilePreviewer_FullScreenChanged` event handler
|
||||
- Toggles between `AppWindowPresenterKind.FullScreen` and `AppWindowPresenterKind.Default`
|
||||
|
||||
## Manual Testing Steps
|
||||
|
||||
### Prerequisites
|
||||
1. Build PowerToys with the changes
|
||||
2. Have a PDF file ready for testing
|
||||
|
||||
### Test Case 1: Enter and Exit Fullscreen
|
||||
1. Open File Explorer
|
||||
2. Select a PDF file
|
||||
3. Press `Ctrl+Space` to open Peek
|
||||
4. Verify PDF is displayed correctly
|
||||
5. **Click the fullscreen button in the PDF viewer** (usually in bottom-right corner)
|
||||
6. **EXPECTED**: Window enters fullscreen mode, titlebar disappears
|
||||
7. **Click the fullscreen button again**
|
||||
8. **EXPECTED**: Window exits fullscreen mode, titlebar reappears
|
||||
|
||||
### Test Case 2: Escape Key Still Works
|
||||
1. Open a PDF in Peek
|
||||
2. Click the fullscreen button to enter fullscreen
|
||||
3. Press `Escape` key
|
||||
4. **EXPECTED**: Window exits fullscreen AND Peek closes (existing behavior)
|
||||
|
||||
### Test Case 3: Multiple Toggle Cycles
|
||||
1. Open a PDF in Peek
|
||||
2. Click fullscreen button (enter fullscreen)
|
||||
3. Click fullscreen button (exit fullscreen)
|
||||
4. Click fullscreen button (enter fullscreen again)
|
||||
5. Click fullscreen button (exit fullscreen again)
|
||||
6. **EXPECTED**: All toggles work correctly without any stuck states
|
||||
|
||||
### Test Case 4: Navigation Between Files
|
||||
1. Select multiple PDF files in File Explorer
|
||||
2. Open Peek with `Ctrl+Space`
|
||||
3. Enter fullscreen mode
|
||||
4. Use arrow keys to navigate to next/previous PDF
|
||||
5. **EXPECTED**: Fullscreen state persists across file navigation
|
||||
|
||||
### Test Case 5: Non-PDF Files
|
||||
1. Open a non-PDF file (e.g., image, text file) in Peek
|
||||
2. **EXPECTED**: No fullscreen button appears, behavior unchanged
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
### Before Fix
|
||||
- Clicking fullscreen button hides titlebar but doesn't properly put window in fullscreen
|
||||
- Clicking fullscreen button again does nothing (stuck in pseudo-fullscreen)
|
||||
- Only way to exit is pressing Escape (which closes Peek entirely)
|
||||
|
||||
### After Fix
|
||||
- Clicking fullscreen button properly enters fullscreen mode
|
||||
- Titlebar automatically hides
|
||||
- Window fills entire screen
|
||||
- Clicking fullscreen button again exits fullscreen
|
||||
- Titlebar reappears
|
||||
- Window returns to previous size/position
|
||||
|
||||
## Technical Details
|
||||
|
||||
The fix leverages WebView2's `ContainsFullScreenElementChanged` event which fires when:
|
||||
1. User clicks the PDF viewer's fullscreen button (enters fullscreen)
|
||||
2. User clicks the fullscreen button again (exits fullscreen)
|
||||
|
||||
The event chain is:
|
||||
1. `CoreWebView2.ContainsFullScreenElementChanged` fires in BrowserControl
|
||||
2. BrowserControl raises `FullScreenChanged` event
|
||||
3. FilePreview propagates the event to MainWindow
|
||||
4. MainWindow calls `AppWindow.SetPresenter()` with appropriate presenter kind
|
||||
|
||||
## Verification
|
||||
After testing, verify:
|
||||
- [ ] PDF fullscreen button enters fullscreen mode
|
||||
- [ ] PDF fullscreen button exits fullscreen mode (toggle works)
|
||||
- [ ] Titlebar visibility toggles correctly
|
||||
- [ ] Window size changes correctly
|
||||
- [ ] Escape key still closes Peek when in fullscreen
|
||||
- [ ] Navigation between PDFs maintains fullscreen state
|
||||
- [ ] No regressions with other file types
|
||||
@@ -43,10 +43,14 @@ namespace Peek.FilePreviewer.Controls
|
||||
|
||||
public delegate void DOMContentLoadedHandler(CoreWebView2? sender, CoreWebView2DOMContentLoadedEventArgs? args);
|
||||
|
||||
public delegate void FullScreenChangedHandler(bool isFullScreen);
|
||||
|
||||
public event NavigationCompletedHandler? NavigationCompleted;
|
||||
|
||||
public event DOMContentLoadedHandler? DOMContentLoaded;
|
||||
|
||||
public event FullScreenChangedHandler? FullScreenChanged;
|
||||
|
||||
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
|
||||
nameof(Source),
|
||||
typeof(Uri),
|
||||
@@ -111,6 +115,7 @@ namespace Peek.FilePreviewer.Controls
|
||||
{
|
||||
PreviewBrowser.CoreWebView2.DOMContentLoaded -= CoreWebView2_DOMContentLoaded;
|
||||
PreviewBrowser.CoreWebView2.ContextMenuRequested -= CoreWebView2_ContextMenuRequested;
|
||||
PreviewBrowser.CoreWebView2.ContainsFullScreenElementChanged -= CoreWebView2_ContainsFullScreenElementChanged;
|
||||
RemoveResourceFilter();
|
||||
}
|
||||
}
|
||||
@@ -211,6 +216,7 @@ namespace Peek.FilePreviewer.Controls
|
||||
PreviewBrowser.CoreWebView2.DOMContentLoaded += CoreWebView2_DOMContentLoaded;
|
||||
PreviewBrowser.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;
|
||||
PreviewBrowser.CoreWebView2.ContextMenuRequested += CoreWebView2_ContextMenuRequested;
|
||||
PreviewBrowser.CoreWebView2.ContainsFullScreenElementChanged += CoreWebView2_ContainsFullScreenElementChanged;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -438,5 +444,11 @@ namespace Peek.FilePreviewer.Controls
|
||||
dataPackage.SetText(OpenUriDialogContent.Text);
|
||||
Clipboard.SetContent(dataPackage);
|
||||
}
|
||||
|
||||
private void CoreWebView2_ContainsFullScreenElementChanged(CoreWebView2 sender, object args)
|
||||
{
|
||||
// Notify listeners about fullscreen state change
|
||||
FullScreenChanged?.Invoke(sender.ContainsFullScreenElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
CustomContextMenu="{x:Bind BrowserPreviewer.CustomContextMenu, Mode=OneWay}"
|
||||
DOMContentLoaded="BrowserPreview_DOMContentLoaded"
|
||||
FlowDirection="LeftToRight"
|
||||
FullScreenChanged="BrowserPreview_FullScreenChanged"
|
||||
IsDevFilePreview="{x:Bind BrowserPreviewer.IsDevFilePreview, Mode=OneWay}"
|
||||
NavigationCompleted="PreviewBrowser_NavigationCompleted"
|
||||
Source="{x:Bind BrowserPreviewer.Preview, Mode=OneWay}"
|
||||
|
||||
@@ -34,6 +34,8 @@ namespace Peek.FilePreviewer
|
||||
|
||||
public event EventHandler<PreviewSizeChangedArgs>? PreviewSizeChanged;
|
||||
|
||||
public event EventHandler<bool>? FullScreenChanged;
|
||||
|
||||
public static readonly DependencyProperty ItemProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(Item),
|
||||
@@ -318,6 +320,12 @@ namespace Peek.FilePreviewer
|
||||
}
|
||||
}
|
||||
|
||||
private void BrowserPreview_FullScreenChanged(bool isFullScreen)
|
||||
{
|
||||
// Propagate fullscreen state change to parent (MainWindow)
|
||||
FullScreenChanged?.Invoke(this, isFullScreen);
|
||||
}
|
||||
|
||||
private void ShellPreviewHandlerPreview_HandlerLoaded(object sender, EventArgs e)
|
||||
{
|
||||
if (ShellPreviewHandlerPreviewer != null)
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
|
||||
<fp:FilePreview
|
||||
Grid.Row="1"
|
||||
FullScreenChanged="FilePreviewer_FullScreenChanged"
|
||||
Item="{x:Bind ViewModel.CurrentItem, Mode=OneWay}"
|
||||
NumberOfFiles="{x:Bind ViewModel.DisplayItemCount, Mode=OneWay}"
|
||||
PreviewSizeChanged="FilePreviewer_PreviewSizeChanged"
|
||||
|
||||
@@ -265,6 +265,25 @@ namespace Peek.UI
|
||||
WindowHelpers.BringToForeground(this.GetWindowHandle());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle FullScreenChanged event to toggle the window fullscreen mode.
|
||||
/// </summary>
|
||||
/// <param name="sender">object</param>
|
||||
/// <param name="isFullScreen">bool indicating if fullscreen is requested</param>
|
||||
private void FilePreviewer_FullScreenChanged(object sender, bool isFullScreen)
|
||||
{
|
||||
if (isFullScreen)
|
||||
{
|
||||
// Enter fullscreen mode
|
||||
AppWindow.SetPresenter(AppWindowPresenterKind.FullScreen);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Exit fullscreen mode and return to default overlapped window
|
||||
AppWindow.SetPresenter(AppWindowPresenterKind.Default);
|
||||
}
|
||||
}
|
||||
|
||||
private Size GetMonitorMaxContentSize(Size monitorSize, double scaling)
|
||||
{
|
||||
var titleBarHeight = TitleBarControl.ActualHeight;
|
||||
|
||||
Reference in New Issue
Block a user