766 lines
33 KiB
C#
766 lines
33 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Runtime.InteropServices;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Interop;
|
|
using System.Windows.Media;
|
|
using System.Windows.Threading;
|
|
using Standard;
|
|
|
|
namespace Microsoft.Windows.Shell
|
|
{
|
|
using HANDLE_MESSAGE = KeyValuePair<WM, MessageHandler>;
|
|
|
|
internal class WindowChromeWorker : DependencyObject
|
|
{
|
|
private const SWP _SwpFlags =
|
|
SWP.NOOWNERZORDER | SWP.DRAWFRAME | SWP.NOACTIVATE | SWP.NOZORDER | SWP.NOMOVE | SWP.NOSIZE;
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId =
|
|
"Member")] private static readonly HT[,] _HitTestBorders =
|
|
{
|
|
{HT.TOPLEFT, HT.TOP, HT.TOPRIGHT}, {HT.LEFT, HT.CLIENT, HT.RIGHT},
|
|
{HT.BOTTOMLEFT, HT.BOTTOM, HT.BOTTOMRIGHT}
|
|
};
|
|
|
|
public static readonly DependencyProperty WindowChromeWorkerProperty =
|
|
DependencyProperty.RegisterAttached("WindowChromeWorker", typeof(WindowChromeWorker),
|
|
typeof(WindowChromeWorker), new PropertyMetadata(null, _OnChromeWorkerChanged));
|
|
|
|
private readonly List<KeyValuePair<WM, MessageHandler>> _messageTable;
|
|
private int _blackGlassFixupAttemptCount;
|
|
private WindowChrome _chromeInfo;
|
|
private bool _hasUserMovedWindow;
|
|
private IntPtr _hwnd;
|
|
private HwndSource _hwndSource;
|
|
private bool _isFixedUp;
|
|
private bool _isGlassEnabled;
|
|
private bool _isHooked;
|
|
private bool _isUserResizing;
|
|
private WindowState _lastMenuState;
|
|
private WindowState _lastRoundingState;
|
|
private Window _window;
|
|
private Point _windowPosAtStartOfUserMove;
|
|
|
|
public WindowChromeWorker()
|
|
{
|
|
_messageTable = new List<HANDLE_MESSAGE>
|
|
{
|
|
new HANDLE_MESSAGE(WM.SETTEXT, _HandleSetTextOrIcon),
|
|
new HANDLE_MESSAGE(WM.SETICON, _HandleSetTextOrIcon),
|
|
new HANDLE_MESSAGE(WM.NCACTIVATE, _HandleNCActivate),
|
|
new HANDLE_MESSAGE(WM.NCCALCSIZE, _HandleNCCalcSize),
|
|
new HANDLE_MESSAGE(WM.NCHITTEST, _HandleNCHitTest),
|
|
new HANDLE_MESSAGE(WM.NCRBUTTONUP, _HandleNCRButtonUp),
|
|
new HANDLE_MESSAGE(WM.SIZE, _HandleSize),
|
|
new HANDLE_MESSAGE(WM.WINDOWPOSCHANGED, _HandleWindowPosChanged),
|
|
new HANDLE_MESSAGE(WM.DWMCOMPOSITIONCHANGED, _HandleDwmCompositionChanged)
|
|
};
|
|
if (Utility.IsPresentationFrameworkVersionLessThan4)
|
|
{
|
|
KeyValuePair<WM, MessageHandler>[] collection =
|
|
{
|
|
new KeyValuePair<WM, MessageHandler>(WM.WININICHANGE, _HandleSettingChange),
|
|
new KeyValuePair<WM, MessageHandler>(WM.ENTERSIZEMOVE, _HandleEnterSizeMove),
|
|
new KeyValuePair<WM, MessageHandler>(WM.EXITSIZEMOVE, _HandleExitSizeMove),
|
|
new KeyValuePair<WM, MessageHandler>(WM.MOVE, _HandleMove)
|
|
};
|
|
_messageTable.AddRange(collection);
|
|
}
|
|
}
|
|
|
|
private bool _IsWindowDocked
|
|
{
|
|
get
|
|
{
|
|
if (_window.WindowState != WindowState.Normal)
|
|
return false;
|
|
var rcWindow = new RECT
|
|
{
|
|
Bottom = 100,
|
|
Right = 100
|
|
};
|
|
var rect = _GetAdjustedWindowRect(rcWindow);
|
|
var point = new Point(_window.Left, _window.Top);
|
|
point -= (Vector) DpiHelper.DevicePixelsToLogical(new Point(rect.Left, rect.Top));
|
|
return _window.RestoreBounds.Location != point;
|
|
}
|
|
}
|
|
|
|
private void _ApplyNewCustomChrome()
|
|
{
|
|
if (_hwnd != IntPtr.Zero)
|
|
if (_chromeInfo == null)
|
|
{
|
|
_RestoreStandardChromeState(false);
|
|
}
|
|
else
|
|
{
|
|
if (!_isHooked)
|
|
{
|
|
_hwndSource.AddHook(_WndProc);
|
|
_isHooked = true;
|
|
}
|
|
_FixupFrameworkIssues();
|
|
_UpdateSystemMenu(_window.WindowState);
|
|
_UpdateFrameState(true);
|
|
NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0,
|
|
SWP.NOOWNERZORDER | SWP.DRAWFRAME | SWP.NOACTIVATE | SWP.NOZORDER | SWP.NOMOVE | SWP.NOSIZE);
|
|
}
|
|
}
|
|
|
|
private void _ClearRoundingRegion()
|
|
{
|
|
NativeMethods.SetWindowRgn(_hwnd, IntPtr.Zero, NativeMethods.IsWindowVisible(_hwnd));
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "HRGNs")]
|
|
private static void _CreateAndCombineRoundRectRgn(IntPtr hrgnSource, Rect region, double radius)
|
|
{
|
|
var zero = IntPtr.Zero;
|
|
try
|
|
{
|
|
zero = _CreateRoundRectRgn(region, radius);
|
|
if (NativeMethods.CombineRgn(hrgnSource, hrgnSource, zero, RGN.OR) == CombineRgnResult.ERROR)
|
|
throw new InvalidOperationException("Unable to combine two HRGNs.");
|
|
}
|
|
catch
|
|
{
|
|
Utility.SafeDeleteObject(ref zero);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
private static IntPtr _CreateRoundRectRgn(Rect region, double radius)
|
|
{
|
|
if (DoubleUtilities.AreClose(0.0, radius))
|
|
return NativeMethods.CreateRectRgn((int) Math.Floor(region.Left), (int) Math.Floor(region.Top),
|
|
(int) Math.Ceiling(region.Right), (int) Math.Ceiling(region.Bottom));
|
|
return NativeMethods.CreateRoundRectRgn((int) Math.Floor(region.Left), (int) Math.Floor(region.Top),
|
|
(int) Math.Ceiling(region.Right) + 1, (int) Math.Ceiling(region.Bottom) + 1, (int) Math.Ceiling(radius),
|
|
(int) Math.Ceiling(radius));
|
|
}
|
|
|
|
private void _ExtendGlassFrame()
|
|
{
|
|
if (Utility.IsOSVistaOrNewer && IntPtr.Zero != _hwnd)
|
|
if (!NativeMethods.DwmIsCompositionEnabled())
|
|
{
|
|
_hwndSource.CompositionTarget.BackgroundColor = SystemColors.WindowColor;
|
|
}
|
|
else
|
|
{
|
|
_hwndSource.CompositionTarget.BackgroundColor = Colors.Transparent;
|
|
var point = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.GlassFrameThickness.Left,
|
|
_chromeInfo.GlassFrameThickness.Top));
|
|
var point2 = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.GlassFrameThickness.Right,
|
|
_chromeInfo.GlassFrameThickness.Bottom));
|
|
var pMarInset = new MARGINS
|
|
{
|
|
cxLeftWidth = (int) Math.Ceiling(point.X),
|
|
cxRightWidth = (int) Math.Ceiling(point2.X),
|
|
cyTopHeight = (int) Math.Ceiling(point.Y),
|
|
cyBottomHeight = (int) Math.Ceiling(point2.Y)
|
|
};
|
|
NativeMethods.DwmExtendFrameIntoClientArea(_hwnd, ref pMarInset);
|
|
}
|
|
}
|
|
|
|
private void _FixupFrameworkIssues()
|
|
{
|
|
if (Utility.IsPresentationFrameworkVersionLessThan4 && _window.Template != null)
|
|
if (VisualTreeHelper.GetChildrenCount(_window) == 0)
|
|
{
|
|
_window.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new _Action(_FixupFrameworkIssues));
|
|
}
|
|
else
|
|
{
|
|
var child = (FrameworkElement) VisualTreeHelper.GetChild(_window, 0);
|
|
var windowRect = NativeMethods.GetWindowRect(_hwnd);
|
|
var rect2 = _GetAdjustedWindowRect(windowRect);
|
|
var rect3 = DpiHelper.DeviceRectToLogical(new Rect(windowRect.Left, windowRect.Top,
|
|
windowRect.Width, windowRect.Height));
|
|
var rect4 = DpiHelper.DeviceRectToLogical(
|
|
new Rect(rect2.Left, rect2.Top, rect2.Width, rect2.Height));
|
|
var thickness = new Thickness(rect3.Left - rect4.Left, rect3.Top - rect4.Top,
|
|
rect4.Right - rect3.Right, rect4.Bottom - rect3.Bottom);
|
|
child.Margin = new Thickness(0.0, 0.0, -(thickness.Left + thickness.Right),
|
|
-(thickness.Top + thickness.Bottom));
|
|
if (_window.FlowDirection == FlowDirection.RightToLeft)
|
|
child.RenderTransform =
|
|
new MatrixTransform(1.0, 0.0, 0.0, 1.0, -(thickness.Left + thickness.Right), 0.0);
|
|
else
|
|
child.RenderTransform = null;
|
|
if (!_isFixedUp)
|
|
{
|
|
_hasUserMovedWindow = false;
|
|
_window.StateChanged += _FixupRestoreBounds;
|
|
_isFixedUp = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void _FixupRestoreBounds(object sender, EventArgs e)
|
|
{
|
|
if ((_window.WindowState == WindowState.Maximized || _window.WindowState == WindowState.Minimized) &&
|
|
_hasUserMovedWindow)
|
|
{
|
|
_hasUserMovedWindow = false;
|
|
var windowPlacement = NativeMethods.GetWindowPlacement(_hwnd);
|
|
var rcWindow = new RECT
|
|
{
|
|
Bottom = 100,
|
|
Right = 100
|
|
};
|
|
var rect = _GetAdjustedWindowRect(rcWindow);
|
|
var point = DpiHelper.DevicePixelsToLogical(new Point(windowPlacement.rcNormalPosition.Left - rect.Left,
|
|
windowPlacement.rcNormalPosition.Top - rect.Top));
|
|
_window.Top = point.Y;
|
|
_window.Left = point.X;
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
|
private void _FixupWindows7Issues()
|
|
{
|
|
if (_blackGlassFixupAttemptCount <= 5 && Utility.IsOSWindows7OrNewer &&
|
|
NativeMethods.DwmIsCompositionEnabled())
|
|
{
|
|
_blackGlassFixupAttemptCount++;
|
|
var hasValue = false;
|
|
try
|
|
{
|
|
hasValue = NativeMethods.DwmGetCompositionTimingInfo(_hwnd).HasValue;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
if (!hasValue)
|
|
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new _Action(_FixupWindows7Issues));
|
|
else
|
|
_blackGlassFixupAttemptCount = 0;
|
|
}
|
|
}
|
|
|
|
private RECT _GetAdjustedWindowRect(RECT rcWindow)
|
|
{
|
|
var windowLongPtr = (WS) (int) NativeMethods.GetWindowLongPtr(_hwnd, GWL.STYLE);
|
|
var dwExStyle = (WS_EX) (int) NativeMethods.GetWindowLongPtr(_hwnd, GWL.EXSTYLE);
|
|
return NativeMethods.AdjustWindowRectEx(rcWindow, windowLongPtr, false, dwExStyle);
|
|
}
|
|
|
|
private WindowState _GetHwndState()
|
|
{
|
|
switch (NativeMethods.GetWindowPlacement(_hwnd).showCmd)
|
|
{
|
|
case SW.SHOWMINIMIZED:
|
|
return WindowState.Minimized;
|
|
|
|
case SW.SHOWMAXIMIZED:
|
|
return WindowState.Maximized;
|
|
}
|
|
return WindowState.Normal;
|
|
}
|
|
|
|
private Rect _GetWindowRect()
|
|
{
|
|
var windowRect = NativeMethods.GetWindowRect(_hwnd);
|
|
return new Rect(windowRect.Left, windowRect.Top, windowRect.Width, windowRect.Height);
|
|
}
|
|
|
|
private IntPtr _HandleDwmCompositionChanged(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
|
|
{
|
|
_UpdateFrameState(false);
|
|
handled = false;
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
private IntPtr _HandleEnterSizeMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
|
|
{
|
|
_isUserResizing = true;
|
|
if (_window.WindowState != WindowState.Maximized && !_IsWindowDocked)
|
|
_windowPosAtStartOfUserMove = new Point(_window.Left, _window.Top);
|
|
handled = false;
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
private IntPtr _HandleExitSizeMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
|
|
{
|
|
_isUserResizing = false;
|
|
if (_window.WindowState == WindowState.Maximized)
|
|
{
|
|
_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)
|
|
{
|
|
if (_isUserResizing)
|
|
_hasUserMovedWindow = true;
|
|
handled = false;
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
private IntPtr _HandleNCActivate(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
|
|
{
|
|
var ptr = NativeMethods.DefWindowProc(_hwnd, WM.NCACTIVATE, wParam, new IntPtr(-1));
|
|
handled = true;
|
|
return ptr;
|
|
}
|
|
|
|
private IntPtr _HandleNCCalcSize(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
|
|
{
|
|
handled = true;
|
|
return new IntPtr(0x300);
|
|
}
|
|
|
|
private IntPtr _HandleNCHitTest(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
|
|
{
|
|
var zero = IntPtr.Zero;
|
|
handled = false;
|
|
if (Utility.IsOSVistaOrNewer && _chromeInfo.GlassFrameThickness != new Thickness() && _isGlassEnabled)
|
|
handled = NativeMethods.DwmDefWindowProc(_hwnd, uMsg, wParam, lParam, out zero);
|
|
if (!(IntPtr.Zero == zero))
|
|
return zero;
|
|
var devicePoint = new Point(Utility.GET_X_LPARAM(lParam), Utility.GET_Y_LPARAM(lParam));
|
|
var deviceRectangle = _GetWindowRect();
|
|
var cLIENT = _HitTestNca(DpiHelper.DeviceRectToLogical(deviceRectangle),
|
|
DpiHelper.DevicePixelsToLogical(devicePoint));
|
|
if (cLIENT != HT.CLIENT)
|
|
{
|
|
var point2 = devicePoint;
|
|
point2.Offset(-deviceRectangle.X, -deviceRectangle.Y);
|
|
point2 = DpiHelper.DevicePixelsToLogical(point2);
|
|
var inputElement = _window.InputHitTest(point2);
|
|
if (inputElement != null && WindowChrome.GetIsHitTestVisibleInChrome(inputElement))
|
|
cLIENT = HT.CLIENT;
|
|
}
|
|
handled = true;
|
|
return new IntPtr((int) cLIENT);
|
|
}
|
|
|
|
private IntPtr _HandleNCRButtonUp(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
|
|
{
|
|
if (2 == wParam.ToInt32())
|
|
SystemCommands.ShowSystemMenuPhysicalCoordinates(_window,
|
|
new Point(Utility.GET_X_LPARAM(lParam), Utility.GET_Y_LPARAM(lParam)));
|
|
handled = false;
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
private IntPtr _HandleSetTextOrIcon(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
|
|
{
|
|
var flag = _ModifyStyle(WS.OVERLAPPED | WS.VISIBLE, WS.OVERLAPPED);
|
|
var ptr = NativeMethods.DefWindowProc(_hwnd, uMsg, wParam, lParam);
|
|
if (flag)
|
|
_ModifyStyle(WS.OVERLAPPED, WS.OVERLAPPED | WS.VISIBLE);
|
|
handled = true;
|
|
return ptr;
|
|
}
|
|
|
|
private IntPtr _HandleSettingChange(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
|
|
{
|
|
_FixupFrameworkIssues();
|
|
handled = false;
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
private IntPtr _HandleSize(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
|
|
{
|
|
WindowState? assumeState = null;
|
|
if (wParam.ToInt32() == 2)
|
|
assumeState = WindowState.Maximized;
|
|
_UpdateSystemMenu(assumeState);
|
|
handled = false;
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
private IntPtr _HandleWindowPosChanged(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
|
|
{
|
|
_UpdateSystemMenu(null);
|
|
if (!_isGlassEnabled)
|
|
{
|
|
var windowpos = (WINDOWPOS) Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
|
|
_SetRoundingRegion(windowpos);
|
|
}
|
|
handled = false;
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
private HT _HitTestNca(Rect windowPosition, Point mousePosition)
|
|
{
|
|
var num = 1;
|
|
var num2 = 1;
|
|
var flag = false;
|
|
if (mousePosition.Y >= windowPosition.Top && mousePosition.Y <
|
|
windowPosition.Top + _chromeInfo.ResizeBorderThickness.Top + _chromeInfo.CaptionHeight)
|
|
{
|
|
flag = mousePosition.Y < windowPosition.Top + _chromeInfo.ResizeBorderThickness.Top;
|
|
num = 0;
|
|
}
|
|
else if (mousePosition.Y < windowPosition.Bottom && mousePosition.Y >=
|
|
windowPosition.Bottom - (int) _chromeInfo.ResizeBorderThickness.Bottom)
|
|
{
|
|
num = 2;
|
|
}
|
|
if (mousePosition.X >= windowPosition.Left &&
|
|
mousePosition.X < windowPosition.Left + (int) _chromeInfo.ResizeBorderThickness.Left)
|
|
num2 = 0;
|
|
else if (mousePosition.X < windowPosition.Right &&
|
|
mousePosition.X >= windowPosition.Right - _chromeInfo.ResizeBorderThickness.Right)
|
|
num2 = 2;
|
|
if (num == 0 && num2 != 1 && !flag)
|
|
num = 1;
|
|
var cAPTION = _HitTestBorders[num, num2];
|
|
if (cAPTION == HT.TOP && !flag)
|
|
cAPTION = HT.CAPTION;
|
|
return cAPTION;
|
|
}
|
|
|
|
private static bool _IsUniform(CornerRadius cornerRadius)
|
|
{
|
|
if (!DoubleUtilities.AreClose(cornerRadius.BottomLeft, cornerRadius.BottomRight))
|
|
return false;
|
|
if (!DoubleUtilities.AreClose(cornerRadius.TopLeft, cornerRadius.TopRight))
|
|
return false;
|
|
if (!DoubleUtilities.AreClose(cornerRadius.BottomLeft, cornerRadius.TopRight))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
private bool _ModifyStyle(WS removeStyle, WS addStyle)
|
|
{
|
|
var ws = (WS) NativeMethods.GetWindowLongPtr(_hwnd, GWL.STYLE).ToInt32();
|
|
var ws2 = (ws & ~removeStyle) | addStyle;
|
|
if (ws == ws2)
|
|
return false;
|
|
NativeMethods.SetWindowLongPtr(_hwnd, GWL.STYLE, new IntPtr((int) ws2));
|
|
return true;
|
|
}
|
|
|
|
private void _OnChromePropertyChangedThatRequiresRepaint(object sender, EventArgs e)
|
|
{
|
|
_UpdateFrameState(true);
|
|
}
|
|
|
|
private static void _OnChromeWorkerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
var window = (Window) d;
|
|
((WindowChromeWorker) e.NewValue)._SetWindow(window);
|
|
}
|
|
|
|
private void _OnWindowPropertyChangedThatRequiresTemplateFixup(object sender, EventArgs e)
|
|
{
|
|
if (_chromeInfo != null && _hwnd != IntPtr.Zero)
|
|
_window.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new _Action(_FixupFrameworkIssues));
|
|
}
|
|
|
|
private void _RestoreFrameworkIssueFixups()
|
|
{
|
|
if (Utility.IsPresentationFrameworkVersionLessThan4)
|
|
{
|
|
var child = (FrameworkElement) VisualTreeHelper.GetChild(_window, 0);
|
|
child.Margin = new Thickness();
|
|
_window.StateChanged -= _FixupRestoreBounds;
|
|
_isFixedUp = false;
|
|
}
|
|
}
|
|
|
|
private void _RestoreGlassFrame()
|
|
{
|
|
if (Utility.IsOSVistaOrNewer && _hwnd != IntPtr.Zero)
|
|
{
|
|
_hwndSource.CompositionTarget.BackgroundColor = SystemColors.WindowColor;
|
|
if (NativeMethods.DwmIsCompositionEnabled())
|
|
{
|
|
var pMarInset = new MARGINS();
|
|
NativeMethods.DwmExtendFrameIntoClientArea(_hwnd, ref pMarInset);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void _RestoreHrgn()
|
|
{
|
|
_ClearRoundingRegion();
|
|
NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0,
|
|
SWP.NOOWNERZORDER | SWP.DRAWFRAME | SWP.NOACTIVATE | SWP.NOZORDER | SWP.NOMOVE | SWP.NOSIZE);
|
|
}
|
|
|
|
private void _RestoreStandardChromeState(bool isClosing)
|
|
{
|
|
VerifyAccess();
|
|
_UnhookCustomChrome();
|
|
if (!isClosing)
|
|
{
|
|
_RestoreFrameworkIssueFixups();
|
|
_RestoreGlassFrame();
|
|
_RestoreHrgn();
|
|
_window.InvalidateMeasure();
|
|
}
|
|
}
|
|
|
|
private void _SetRoundingRegion(WINDOWPOS? wp)
|
|
{
|
|
if (NativeMethods.GetWindowPlacement(_hwnd).showCmd == SW.SHOWMAXIMIZED)
|
|
{
|
|
int x;
|
|
int y;
|
|
if (wp.HasValue)
|
|
{
|
|
x = wp.Value.x;
|
|
y = wp.Value.y;
|
|
}
|
|
else
|
|
{
|
|
var rect = _GetWindowRect();
|
|
x = (int) rect.Left;
|
|
y = (int) rect.Top;
|
|
}
|
|
var rcWork = NativeMethods.GetMonitorInfo(NativeMethods.MonitorFromWindow(_hwnd, 2)).rcWork;
|
|
rcWork.Offset(-x, -y);
|
|
var zero = IntPtr.Zero;
|
|
try
|
|
{
|
|
zero = NativeMethods.CreateRectRgnIndirect(rcWork);
|
|
NativeMethods.SetWindowRgn(_hwnd, zero, NativeMethods.IsWindowVisible(_hwnd));
|
|
zero = IntPtr.Zero;
|
|
}
|
|
finally
|
|
{
|
|
Utility.SafeDeleteObject(ref zero);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Size size;
|
|
if (wp.HasValue && !Utility.IsFlagSet(wp.Value.flags, 1))
|
|
{
|
|
size = new Size(wp.Value.cx, wp.Value.cy);
|
|
}
|
|
else
|
|
{
|
|
if (wp.HasValue && _lastRoundingState == _window.WindowState)
|
|
return;
|
|
size = _GetWindowRect().Size;
|
|
}
|
|
_lastRoundingState = _window.WindowState;
|
|
var hrgnSource = IntPtr.Zero;
|
|
try
|
|
{
|
|
var num3 = Math.Min(size.Width, size.Height);
|
|
var radius =
|
|
Math.Min(DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.TopLeft, 0.0)).X,
|
|
num3 / 2.0);
|
|
if (_IsUniform(_chromeInfo.CornerRadius))
|
|
{
|
|
hrgnSource = _CreateRoundRectRgn(new Rect(size), radius);
|
|
}
|
|
else
|
|
{
|
|
hrgnSource =
|
|
_CreateRoundRectRgn(
|
|
new Rect(0.0, 0.0, size.Width / 2.0 + radius, size.Height / 2.0 + radius), radius);
|
|
var num5 = Math.Min(
|
|
DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.TopRight, 0.0)).X,
|
|
num3 / 2.0);
|
|
var region = new Rect(0.0, 0.0, size.Width / 2.0 + num5, size.Height / 2.0 + num5);
|
|
region.Offset(size.Width / 2.0 - num5, 0.0);
|
|
_CreateAndCombineRoundRectRgn(hrgnSource, region, num5);
|
|
var num6 = Math.Min(
|
|
DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.BottomLeft, 0.0)).X,
|
|
num3 / 2.0);
|
|
var rect4 = new Rect(0.0, 0.0, size.Width / 2.0 + num6, size.Height / 2.0 + num6);
|
|
rect4.Offset(0.0, size.Height / 2.0 - num6);
|
|
_CreateAndCombineRoundRectRgn(hrgnSource, rect4, num6);
|
|
var num7 = Math.Min(
|
|
DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.BottomRight, 0.0)).X,
|
|
num3 / 2.0);
|
|
var rect5 = new Rect(0.0, 0.0, size.Width / 2.0 + num7, size.Height / 2.0 + num7);
|
|
rect5.Offset(size.Width / 2.0 - num7, size.Height / 2.0 - num7);
|
|
_CreateAndCombineRoundRectRgn(hrgnSource, rect5, num7);
|
|
}
|
|
NativeMethods.SetWindowRgn(_hwnd, hrgnSource, NativeMethods.IsWindowVisible(_hwnd));
|
|
hrgnSource = IntPtr.Zero;
|
|
}
|
|
finally
|
|
{
|
|
Utility.SafeDeleteObject(ref hrgnSource);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void _SetWindow(Window window)
|
|
{
|
|
EventHandler handler = null;
|
|
_window = window;
|
|
_hwnd = new WindowInteropHelper(_window).Handle;
|
|
if (Utility.IsPresentationFrameworkVersionLessThan4)
|
|
{
|
|
Utility.AddDependencyPropertyChangeListener(_window, Control.TemplateProperty,
|
|
_OnWindowPropertyChangedThatRequiresTemplateFixup);
|
|
Utility.AddDependencyPropertyChangeListener(_window, FrameworkElement.FlowDirectionProperty,
|
|
_OnWindowPropertyChangedThatRequiresTemplateFixup);
|
|
}
|
|
_window.Closed += _UnsetWindow;
|
|
if (IntPtr.Zero != _hwnd)
|
|
{
|
|
_hwndSource = HwndSource.FromHwnd(_hwnd);
|
|
_window.ApplyTemplate();
|
|
if (_chromeInfo != null)
|
|
_ApplyNewCustomChrome();
|
|
}
|
|
else
|
|
{
|
|
if (handler == null)
|
|
handler = delegate
|
|
{
|
|
_hwnd = new WindowInteropHelper(_window).Handle;
|
|
_hwndSource = HwndSource.FromHwnd(_hwnd);
|
|
if (_chromeInfo != null)
|
|
_ApplyNewCustomChrome();
|
|
};
|
|
_window.SourceInitialized += handler;
|
|
}
|
|
}
|
|
|
|
private void _UnhookCustomChrome()
|
|
{
|
|
if (_isHooked)
|
|
{
|
|
_hwndSource.RemoveHook(_WndProc);
|
|
_isHooked = false;
|
|
}
|
|
}
|
|
|
|
private void _UnsetWindow(object sender, EventArgs e)
|
|
{
|
|
if (Utility.IsPresentationFrameworkVersionLessThan4)
|
|
{
|
|
Utility.RemoveDependencyPropertyChangeListener(_window, Control.TemplateProperty,
|
|
_OnWindowPropertyChangedThatRequiresTemplateFixup);
|
|
Utility.RemoveDependencyPropertyChangeListener(_window, FrameworkElement.FlowDirectionProperty,
|
|
_OnWindowPropertyChangedThatRequiresTemplateFixup);
|
|
}
|
|
if (_chromeInfo != null)
|
|
_chromeInfo.PropertyChangedThatRequiresRepaint -= _OnChromePropertyChangedThatRequiresRepaint;
|
|
_RestoreStandardChromeState(true);
|
|
}
|
|
|
|
private void _UpdateFrameState(bool force)
|
|
{
|
|
if (IntPtr.Zero != _hwnd)
|
|
{
|
|
var flag = NativeMethods.DwmIsCompositionEnabled();
|
|
if (force || flag != _isGlassEnabled)
|
|
{
|
|
_isGlassEnabled = flag && _chromeInfo.GlassFrameThickness != new Thickness();
|
|
if (!_isGlassEnabled)
|
|
{
|
|
_SetRoundingRegion(null);
|
|
}
|
|
else
|
|
{
|
|
_ClearRoundingRegion();
|
|
_ExtendGlassFrame();
|
|
_FixupWindows7Issues();
|
|
}
|
|
NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0,
|
|
SWP.NOOWNERZORDER | SWP.DRAWFRAME | SWP.NOACTIVATE | SWP.NOZORDER | SWP.NOMOVE | SWP.NOSIZE);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void _UpdateSystemMenu(WindowState? assumeState)
|
|
{
|
|
var nullable = assumeState;
|
|
var state = nullable.HasValue ? nullable.GetValueOrDefault() : _GetHwndState();
|
|
if (!assumeState.HasValue && _lastMenuState == state)
|
|
return;
|
|
_lastMenuState = state;
|
|
var flag = _ModifyStyle(WS.OVERLAPPED | WS.VISIBLE, WS.OVERLAPPED);
|
|
var systemMenu = NativeMethods.GetSystemMenu(_hwnd, false);
|
|
if (IntPtr.Zero != systemMenu)
|
|
{
|
|
var ws = (WS) NativeMethods.GetWindowLongPtr(_hwnd, GWL.STYLE).ToInt32();
|
|
var flag2 = Utility.IsFlagSet((int) ws, 0x20000);
|
|
var flag3 = Utility.IsFlagSet((int) ws, 0x10000);
|
|
var flag4 = Utility.IsFlagSet((int) ws, 0x40000);
|
|
switch (state)
|
|
{
|
|
case WindowState.Minimized:
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.RESTORE, MF.BYCOMMAND);
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.MOVE, MF.BYCOMMAND | MF.DISABLED | MF.GRAYED);
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.SIZE, MF.BYCOMMAND | MF.DISABLED | MF.GRAYED);
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.MINIMIZE, MF.BYCOMMAND | MF.DISABLED | MF.GRAYED);
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.MAXIMIZE,
|
|
flag3 ? MF.BYCOMMAND : MF.BYCOMMAND | MF.DISABLED | MF.GRAYED);
|
|
goto Label_01A6;
|
|
|
|
case WindowState.Maximized:
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.RESTORE, MF.BYCOMMAND);
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.MOVE, MF.BYCOMMAND | MF.DISABLED | MF.GRAYED);
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.SIZE, MF.BYCOMMAND | MF.DISABLED | MF.GRAYED);
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.MINIMIZE,
|
|
flag2 ? MF.BYCOMMAND : MF.BYCOMMAND | MF.DISABLED | MF.GRAYED);
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.MAXIMIZE, MF.BYCOMMAND | MF.DISABLED | MF.GRAYED);
|
|
goto Label_01A6;
|
|
}
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.RESTORE, MF.BYCOMMAND | MF.DISABLED | MF.GRAYED);
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.MOVE, MF.BYCOMMAND);
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.SIZE,
|
|
flag4 ? MF.BYCOMMAND : MF.BYCOMMAND | MF.DISABLED | MF.GRAYED);
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.MINIMIZE,
|
|
flag2 ? MF.BYCOMMAND : MF.BYCOMMAND | MF.DISABLED | MF.GRAYED);
|
|
NativeMethods.EnableMenuItem(systemMenu, SC.MAXIMIZE,
|
|
flag3 ? MF.BYCOMMAND : MF.BYCOMMAND | MF.DISABLED | MF.GRAYED);
|
|
}
|
|
Label_01A6:
|
|
if (flag)
|
|
_ModifyStyle(WS.OVERLAPPED, WS.OVERLAPPED | WS.VISIBLE);
|
|
}
|
|
|
|
private IntPtr _WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
|
{
|
|
var uMsg = (WM) msg;
|
|
foreach (var pair in _messageTable)
|
|
if (pair.Key == uMsg)
|
|
return pair.Value(uMsg, wParam, lParam, out handled);
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
|
public static WindowChromeWorker GetWindowChromeWorker(Window window)
|
|
{
|
|
Verify.IsNotNull(window, "window");
|
|
return (WindowChromeWorker) window.GetValue(WindowChromeWorkerProperty);
|
|
}
|
|
|
|
public void SetWindowChrome(WindowChrome newChrome)
|
|
{
|
|
VerifyAccess();
|
|
if (newChrome != _chromeInfo)
|
|
{
|
|
if (_chromeInfo != null)
|
|
_chromeInfo.PropertyChangedThatRequiresRepaint -= _OnChromePropertyChangedThatRequiresRepaint;
|
|
_chromeInfo = newChrome;
|
|
if (_chromeInfo != null)
|
|
_chromeInfo.PropertyChangedThatRequiresRepaint += _OnChromePropertyChangedThatRequiresRepaint;
|
|
_ApplyNewCustomChrome();
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
|
public static void SetWindowChromeWorker(Window window, WindowChromeWorker chrome)
|
|
{
|
|
Verify.IsNotNull(window, "window");
|
|
window.SetValue(WindowChromeWorkerProperty, chrome);
|
|
}
|
|
|
|
private delegate void _Action();
|
|
}
|
|
} |