Skip to content

Commit 2d4e820

Browse files
committed
Merge branch 'main' into PanZoomRewrite
2 parents ace3a7e + c023d6a commit 2d4e820

3 files changed

Lines changed: 51 additions & 24 deletions

File tree

Src/FlyPhotos/App.xaml.cs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.Threading;
66
using System.Threading.Tasks;
77
using Windows.ApplicationModel.Activation;
8-
using FlyPhotos.Core.Model;
98
using FlyPhotos.Infra.Configuration;
109
using FlyPhotos.Infra.Localization;
1110
using FlyPhotos.Services;
@@ -85,20 +84,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs args)
8584
private void LaunchPhotoDisplayWindow(string selectedFilePath, bool extLaunch)
8685
{
8786
_photoDisplayWindow = new PhotoDisplayWindow(selectedFilePath, extLaunch);
88-
switch (AppConfig.Settings.WindowLaunchMode)
89-
{
90-
case WindowLaunchMode.Maximized:
91-
_photoDisplayWindow.Maximize();
92-
_photoDisplayWindow.Activate();
93-
break;
94-
case WindowLaunchMode.FullScreen:
95-
_photoDisplayWindow.Activate();
96-
_photoDisplayWindow.EnterFullScreenOnLaunch();
97-
break; // Activate already called above
98-
case WindowLaunchMode.LastWindowState:
99-
_photoDisplayWindow.Activate();
100-
break;
101-
}
87+
_photoDisplayWindow.ActivateForStartup();
10288
}
10389

10490
/// <summary>

Src/FlyPhotos/UI/Behaviors/WindowPlacementManager.cs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ public sealed partial class WindowPlacementManager : IDisposable
9696
/// <summary>Indicates whether the manager has been disposed to prevent further event handling.</summary>
9797
private bool _isDisposed;
9898

99+
/// <summary>
100+
/// Snapshot of <c>IsMaximized</c> from the loaded saved state, captured before
101+
/// <see cref="CaptureOverlappedGeometry"/> can overwrite <see cref="_state"/>.
102+
/// Used by <see cref="WasMaximized"/> so the value is stable after <c>Activate()</c>.
103+
/// </summary>
104+
private readonly bool _loadedAsMaximized;
105+
99106
// Win32 show-command constants supplementary to Win32Methods
100107

101108
/// <summary>SW_SHOWNORMAL – activate and show in original size/position.</summary>
@@ -116,6 +123,15 @@ public sealed partial class WindowPlacementManager : IDisposable
116123
/// </summary>
117124
public string? Data => Serialize();
118125

126+
/// <summary>
127+
/// <see langword="true" /> if the loaded saved state had the window maximized.
128+
/// The caller uses this to drive a post-<c>Activate</c> maximize so that
129+
/// <c>ExtendsContentIntoTitleBar</c> is already stable before the window goes maximized,
130+
/// avoiding the position jag that occurs when <c>SW_SHOWMAXIMIZED</c> is applied inside
131+
/// <c>WM_SHOWWINDOW</c> during <c>Activate()</c>.
132+
/// </summary>
133+
public bool WasMaximized => _loadedAsMaximized;
134+
119135
/// <summary>
120136
/// <see langword="true" /> if the monitor layout encoded in the loaded data
121137
/// did not match the current monitor configuration – meaning the saved
@@ -156,6 +172,12 @@ public WindowPlacementManager(Window window, string? serialisedData)
156172
MonitorLayoutChanged = loadedState != null; // true only when there WAS data
157173
}
158174

175+
// Capture the loaded maximized flag NOW, before CaptureOverlappedGeometry can
176+
// overwrite _state. WasMaximized reads this field; _state.IsMaximized is mutable
177+
// and will be set to false by CaptureOverlappedGeometry when ApplySavedPlacement
178+
// applies SW_SHOWNORMAL during Activate().
179+
_loadedAsMaximized = _state?.IsMaximized == true;
180+
159181
// WM_SHOWWINDOW fires before the first paint, so placement is applied
160182
// in one shot with no visible flicker.
161183
_monitor = new WindowMessageMonitor(_window);
@@ -196,6 +218,13 @@ private void ApplySavedPlacement()
196218
{
197219
if (_state is not { } state) return;
198220

221+
// When the saved state is maximized, skip SetWindowPlacement entirely.
222+
// Changing window geometry inside WM_SHOWWINDOW (even with SW_SHOWNORMAL) while
223+
// ExtendsContentIntoTitleBar hasn't yet settled causes the same position jag as
224+
// the original SW_SHOWMAXIMIZED bug. The caller (ActivateForStartup) drives
225+
// Maximize() after Activate() returns, at which point the title bar is stable.
226+
if (state.IsMaximized) return;
227+
199228
Win32Methods.GetWindowPlacement(_hwnd, out var wp);
200229
wp.length = (uint)Marshal.SizeOf<Win32Methods.WINDOWPLACEMENT>();
201230

@@ -207,10 +236,7 @@ private void ApplySavedPlacement()
207236
Bottom = state.Y + state.Height
208237
};
209238

210-
// Always restore as an overlapped window – never back into full-screen.
211-
wp.showCmd = state.IsMaximized
212-
? Win32Methods.SW_SHOWMAXIMIZED
213-
: SW_SHOWNORMAL;
239+
wp.showCmd = SW_SHOWNORMAL;
214240

215241
// Bracket SetWindowPlacement with the flag so that WM_DPICHANGED fired
216242
// by moving the window to a different-DPI monitor is suppressed above.

Src/FlyPhotos/UI/Views/PhotoDisplayWindow.xaml.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -824,13 +824,28 @@ private async Task LaunchExternalAppAsync(int index)
824824
}
825825

826826
/// <summary>
827-
/// Enters full-screen mode at launch, using the same <see cref="WindowFullScreenManager.ToggleFullScreen"/> path
828-
/// as the interactive F11 toggle. This ensures PauseTracking is set, the exit-full-screen button is shown,
829-
/// and <c>_wasMaximizedBeforeFullScreen</c> is recorded correctly so exiting later works properly.
827+
/// Activates the window and applies the configured launch mode (maximized, full-screen,
828+
/// or last window state). <c>Activate()</c> is always called first so that
829+
/// <c>ExtendsContentIntoTitleBar</c> is stable before any maximize, avoiding the
830+
/// top-edge position jag that occurs when <c>SW_SHOWMAXIMIZED</c> is applied inside
831+
/// <c>WM_SHOWWINDOW</c> before the title-bar geometry has settled.
830832
/// </summary>
831-
internal void EnterFullScreenOnLaunch()
833+
internal void ActivateForStartup()
832834
{
833-
_windFullScreenManager.ToggleFullScreen(ButtonFullScreenClose);
835+
Activate();
836+
switch (AppConfig.Settings.WindowLaunchMode)
837+
{
838+
case WindowLaunchMode.Maximized:
839+
this.Maximize();
840+
break;
841+
case WindowLaunchMode.FullScreen:
842+
_windFullScreenManager.ToggleFullScreen(ButtonFullScreenClose);
843+
break;
844+
case WindowLaunchMode.LastWindowState:
845+
if (_windPlacementManager.WasMaximized)
846+
this.Maximize();
847+
break;
848+
}
834849
}
835850

836851
private async Task HandleMouseWheelNavigation(int delta, bool isHorizontalScroll)

0 commit comments

Comments
 (0)