Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,6 @@ internal class WindowChromeWorker : DependencyObject

private bool _isHooked = false;

// These fields are for tracking workarounds for WPF 3.5SP1 behaviors.
private bool _isFixedUp = false;
private bool _isUserResizing = false;
private bool _hasUserMovedWindow = false;
private Point _windowPosAtStartOfUserMove = default(Point);

/// <summary>Object that describes the current modifications being made to the chrome.</summary>
private WindowChrome _chromeInfo;

Expand Down Expand Up @@ -81,17 +75,6 @@ public WindowChromeWorker()
new HANDLE_MESSAGE(WM.WINDOWPOSCHANGED, _HandleWindowPosChanged),
new HANDLE_MESSAGE(WM.DWMCOMPOSITIONCHANGED, _HandleDwmCompositionChanged),
};

if (Utility.IsPresentationFrameworkVersionLessThan4)
{
_messageTable.AddRange(new[]
{
new HANDLE_MESSAGE(WM.SETTINGCHANGE, _HandleSettingChange),
new HANDLE_MESSAGE(WM.ENTERSIZEMOVE, _HandleEnterSizeMove),
new HANDLE_MESSAGE(WM.EXITSIZEMOVE, _HandleExitSizeMove),
new HANDLE_MESSAGE(WM.MOVE, _HandleMove),
});
}
}

public void SetWindowChrome(WindowChrome newChrome)
Expand Down Expand Up @@ -205,7 +188,6 @@ private void UnsubscribeWindowEvents()
Utility.RemoveDependencyPropertyChangeListener(_window, Window.TemplateProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup);
Utility.RemoveDependencyPropertyChangeListener(_window, Window.FlowDirectionProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup);
_window.SourceInitialized -= _WindowSourceInitialized;
_window.StateChanged -= _FixupRestoreBounds;
}
}

Expand Down Expand Up @@ -321,9 +303,8 @@ private void _FixupTemplateIssues()
}

Thickness templateFixupMargin = default(Thickness);
Transform templateFixupTransform = null;

var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0);
FrameworkElement rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0);

if (_chromeInfo.NonClientFrameEdges != NonClientFrameEdges.None)
{
Expand Down Expand Up @@ -361,160 +342,7 @@ private void _FixupTemplateIssues()
}
}

if (Utility.IsPresentationFrameworkVersionLessThan4)
{
DpiScale dpi = _window.GetDpi();
RECT rcWindow = NativeMethods.GetWindowRect(_hwnd);
RECT rcAdjustedClient = _GetAdjustedWindowRect(rcWindow);

Rect rcLogicalWindow = DpiHelper.DeviceRectToLogical(new Rect(rcWindow.Left, rcWindow.Top, rcWindow.Width, rcWindow.Height), dpi.DpiScaleX, dpi.DpiScaleY);
Rect rcLogicalClient = DpiHelper.DeviceRectToLogical(new Rect(rcAdjustedClient.Left, rcAdjustedClient.Top, rcAdjustedClient.Width, rcAdjustedClient.Height), dpi.DpiScaleX, dpi.DpiScaleY);

if (!Utility.IsFlagSet((int)_chromeInfo.NonClientFrameEdges, (int)NonClientFrameEdges.Left))
{
#if RIBBON_IN_FRAMEWORK
templateFixupMargin.Right -= SystemParameters.WindowResizeBorderThickness.Left;
#else
templateFixupMargin.Right -= SystemParameters2.Current.WindowResizeBorderThickness.Left;
#endif
}

if (!Utility.IsFlagSet((int)_chromeInfo.NonClientFrameEdges, (int)NonClientFrameEdges.Right))
{
#if RIBBON_IN_FRAMEWORK
templateFixupMargin.Right -= SystemParameters.WindowResizeBorderThickness.Right;
#else
templateFixupMargin.Right -= SystemParameters2.Current.WindowResizeBorderThickness.Right;
#endif
}

if (!Utility.IsFlagSet((int)_chromeInfo.NonClientFrameEdges, (int)NonClientFrameEdges.Top))
{
#if RIBBON_IN_FRAMEWORK
templateFixupMargin.Bottom -= SystemParameters.WindowResizeBorderThickness.Top;
#else
templateFixupMargin.Bottom -= SystemParameters2.Current.WindowResizeBorderThickness.Top;
#endif
}

if (!Utility.IsFlagSet((int)_chromeInfo.NonClientFrameEdges, (int)NonClientFrameEdges.Bottom))
{
#if RIBBON_IN_FRAMEWORK
templateFixupMargin.Bottom -= SystemParameters.WindowResizeBorderThickness.Bottom;
#else
templateFixupMargin.Bottom -= SystemParameters2.Current.WindowResizeBorderThickness.Bottom;
#endif
}

#if RIBBON_IN_FRAMEWORK
templateFixupMargin.Bottom -= SystemParameters.WindowCaptionHeight;
#else
templateFixupMargin.Bottom -= SystemParameters2.Current.WindowCaptionHeight;
#endif

// The negative thickness on the margin doesn't properly get applied in RTL layouts.
// The width is right, but there is a black bar on the right.
// To fix this we just add an additional RenderTransform to the root element.
// This works fine, but if the window is dynamically changing its FlowDirection then this can have really bizarre side effects.
// This will mostly work if the FlowDirection is dynamically changed, but there aren't many real scenarios that would call for
// that so I'm not addressing the rest of the quirkiness.
if (_window.FlowDirection == FlowDirection.RightToLeft)
{
Thickness nonClientThickness = new Thickness(
rcLogicalWindow.Left - rcLogicalClient.Left,
rcLogicalWindow.Top - rcLogicalClient.Top,
rcLogicalClient.Right - rcLogicalWindow.Right,
rcLogicalClient.Bottom - rcLogicalWindow.Bottom);

templateFixupTransform = new MatrixTransform(1, 0, 0, 1, -(nonClientThickness.Left + nonClientThickness.Right), 0);
}
else
{
templateFixupTransform = null;
}

rootElement.RenderTransform = templateFixupTransform;
}

rootElement.Margin = templateFixupMargin;

if (Utility.IsPresentationFrameworkVersionLessThan4)
{
if (!_isFixedUp)
{
_hasUserMovedWindow = false;
_window.StateChanged += _FixupRestoreBounds;

_isFixedUp = true;
}
}
}

private void _FixupRestoreBounds(object sender, EventArgs e)
{
Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4);
if (_window.WindowState == WindowState.Maximized || _window.WindowState == WindowState.Minimized)
{
// Old versions of WPF sometimes force their incorrect idea of the Window's location
// on the Win32 restore bounds. If we have reason to think this is the case, then
// try to undo what WPF did after it has done its thing.
if (_hasUserMovedWindow)
{
DpiScale dpi = _window.GetDpi();
_hasUserMovedWindow = false;
WINDOWPLACEMENT wp = NativeMethods.GetWindowPlacement(_hwnd);

RECT adjustedDeviceRc = _GetAdjustedWindowRect(new RECT { Bottom = 100, Right = 100 });
Point adjustedTopLeft = DpiHelper.DevicePixelsToLogical(
new Point(
wp.rcNormalPosition.Left - adjustedDeviceRc.Left,
wp.rcNormalPosition.Top - adjustedDeviceRc.Top),
dpi.DpiScaleX,
dpi.DpiScaleY);

_window.Top = adjustedTopLeft.Y;
_window.Left = adjustedTopLeft.X;
}
}
}

private RECT _GetAdjustedWindowRect(RECT rcWindow)
{
// This should only be used to work around issues in the Framework that were fixed in 4.0
Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4);

var style = (WS)NativeMethods.GetWindowLongPtr(_hwnd, GWL.STYLE);
var exstyle = (WS_EX)NativeMethods.GetWindowLongPtr(_hwnd, GWL.EXSTYLE);

return NativeMethods.AdjustWindowRectEx(rcWindow, style, false, exstyle);
}

// Windows tries hard to hide this state from applications.
// Generally you can tell that the window is in a docked position because the restore bounds from GetWindowPlacement
// don't match the current window location and it's not in a maximized or minimized state.
// Because this isn't doced or supported, it's also not incredibly consistent. Sometimes some things get updated in
// different orders, so this isn't absolutely reliable.
private bool _IsWindowDocked
{
get
{
// We're only detecting this state to work around .Net 3.5 issues.
// This logic won't work correctly when those issues are fixed.
Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4);

if (_window.WindowState != WindowState.Normal)
{
return false;
}

DpiScale dpi = _window.GetDpi();

RECT adjustedOffset = _GetAdjustedWindowRect(new RECT { Bottom = 100, Right = 100 });
Point windowTopLeft = new Point(_window.Left, _window.Top);
windowTopLeft -= (Vector)DpiHelper.DevicePixelsToLogical(new Point(adjustedOffset.Left, adjustedOffset.Top), dpi.DpiScaleX, dpi.DpiScaleY);

return _window.RestoreBounds.Location != windowTopLeft;
}
}

#region WindowProc and Message Handlers
Expand Down Expand Up @@ -778,79 +606,6 @@ private IntPtr _HandleDwmCompositionChanged(WM uMsg, IntPtr wParam, IntPtr lPara
return IntPtr.Zero;
}

private IntPtr _HandleSettingChange(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
{
// There are several settings that can cause fixups for the template to become invalid when changed.
// These shouldn't be required on the v4 framework.
Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4);

_FixupTemplateIssues();

handled = false;
return IntPtr.Zero;
}

private IntPtr _HandleEnterSizeMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
{
// This is only intercepted to deal with bugs in Window in .Net 3.5 and below.
Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4);

_isUserResizing = true;

// On Win7 if the user is dragging the window out of the maximized state then we don't want to use that location
// as a restore point.
Assert.Implies(_window.WindowState == WindowState.Maximized, Utility.IsOSWindows7OrNewer);
if (_window.WindowState != WindowState.Maximized)
{
// Check for the docked window case. The window can still be restored when it's in this position so
// try to account for that and not update the start position.
if (!_IsWindowDocked)
{
_windowPosAtStartOfUserMove = new Point(_window.Left, _window.Top);
}
// Realistically we also don't want to update the start position when moving from one docked state to another (or to and from maximized),
// but it's tricky to detect and this is already a workaround for a bug that's fixed in newer versions of the framework.
// Not going to try to handle all cases.
}

handled = false;
return IntPtr.Zero;
}

private IntPtr _HandleExitSizeMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
{
// This is only intercepted to deal with bugs in Window in .Net 3.5 and below.
Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4);

_isUserResizing = false;

// On Win7 the user can change the Window's state by dragging the window to the top of the monitor.
// If they did that, then we need to try to update the restore bounds or else WPF will put the window at the maximized location (e.g. (-8,-8)).
if (_window.WindowState == WindowState.Maximized)
{
Assert.IsTrue(Utility.IsOSWindows7OrNewer);
_window.Top = _windowPosAtStartOfUserMove.Y;
_window.Left = _windowPosAtStartOfUserMove.X;
}

handled = false;
return IntPtr.Zero;
}

private IntPtr _HandleMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
{
// This is only intercepted to deal with bugs in Window in .Net 3.5 and below.
Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4);

if (_isUserResizing)
{
_hasUserMovedWindow = true;
}

handled = false;
return IntPtr.Zero;
}

#endregion

/// <summary>Add and remove a native WindowStyle from the HWND.</summary>
Expand Down Expand Up @@ -1378,19 +1133,10 @@ private void _UnhookCustomChrome()

private void _RestoreFrameworkIssueFixups()
{
var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0);
FrameworkElement rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0);

// Undo anything that was done before.
rootElement.Margin = new Thickness();

// This margin is only necessary if the client rect is going to be calculated incorrectly by WPF.
// This bug was fixed in V4 of the framework.
if (Utility.IsPresentationFrameworkVersionLessThan4)
{
Assert.IsTrue(_isFixedUp);
_window.StateChanged -= _FixupRestoreBounds;
_isFixedUp = false;
}
}

private void _RestoreGlassFrame()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,16 +126,6 @@ public static bool IsOSWindows7OrNewer
/// </summary>
public static bool IsWindows11_22H2OrNewer => _osVersion.Build >= 22621;


/// <summary>
/// Is this using WPF4?
/// </summary>
/// <remarks>
/// There are a few specific bugs in Window in 3.5SP1 and below that require workarounds
/// when handling WM_NCCALCSIZE on the HWND.
/// </remarks>
public static bool IsPresentationFrameworkVersionLessThan4 => false;

public static BitmapFrame GetBestMatch(IList<BitmapFrame> frames, int width, int height)
{
return _GetBestMatch(frames, _GetBitDepth(), width, height);
Expand Down