| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218 |
- /*************************************************************************************
- Extended WPF Toolkit
- Copyright (C) 2007-2013 Xceed Software Inc.
- This program is provided to you under the terms of the Microsoft Public
- License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
- For more features, controls, and fast professional support,
- pick up the Plus Edition at http://xceed.com/wpf_toolkit
- Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
- ***********************************************************************************/
- /**************************************************************************\
- Copyright Microsoft Corporation. All Rights Reserved.
- \**************************************************************************/
- namespace Microsoft.Windows.Shell
- {
- using System;
- using System.Collections.Generic;
- using System.Diagnostics.CodeAnalysis;
- using System.Runtime.InteropServices;
- using System.Threading;
- using System.Windows;
- using System.Windows.Interop;
- using System.Windows.Media;
- using System.Windows.Threading;
- using Standard;
- using HANDLE_MESSAGE = System.Collections.Generic.KeyValuePair<Standard.WM, Standard.MessageHandler>;
- using System.Windows.Controls.Primitives;
- internal class WindowChromeWorker : DependencyObject
- {
- // Delegate signature used for Dispatcher.BeginInvoke.
- private delegate void _Action();
- #region Fields
- private const SWP _SwpFlags = SWP.FRAMECHANGED | SWP.NOSIZE | SWP.NOMOVE | SWP.NOZORDER | SWP.NOOWNERZORDER | SWP.NOACTIVATE;
- private readonly List<HANDLE_MESSAGE> _messageTable;
- /// <summary>The Window that's chrome is being modified.</summary>
- private Window _window;
- /// <summary>Underlying HWND for the _window.</summary>
- private IntPtr _hwnd;
- private HwndSource _hwndSource = null;
- 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);
- // Field to track attempts to force off Device Bitmaps on Win7.
- private int _blackGlassFixupAttemptCount;
- /// <summary>Object that describes the current modifications being made to the chrome.</summary>
- private WindowChrome _chromeInfo;
- // Keep track of this so we can detect when we need to apply changes. Tracking these separately
- // as I've seen using just one cause things to get enough out of sync that occasionally the caption will redraw.
- private WindowState _lastRoundingState;
- private WindowState _lastMenuState;
- private bool _isGlassEnabled;
- #endregion
- 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)
- {
- _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)
- {
- VerifyAccess();
- Assert.IsNotNull(_window);
- if (newChrome == _chromeInfo)
- {
- // Nothing's changed.
- return;
- }
- if (_chromeInfo != null)
- {
- _chromeInfo.PropertyChangedThatRequiresRepaint -= _OnChromePropertyChangedThatRequiresRepaint;
- }
- _chromeInfo = newChrome;
- if (_chromeInfo != null)
- {
- _chromeInfo.PropertyChangedThatRequiresRepaint += _OnChromePropertyChangedThatRequiresRepaint;
- }
- _ApplyNewCustomChrome();
- }
- private void _OnChromePropertyChangedThatRequiresRepaint(object sender, EventArgs e)
- {
- _UpdateFrameState(true);
- }
- public static readonly DependencyProperty WindowChromeWorkerProperty = DependencyProperty.RegisterAttached(
- "WindowChromeWorker",
- typeof(WindowChromeWorker),
- typeof(WindowChromeWorker),
- new PropertyMetadata(null, _OnChromeWorkerChanged));
- private static void _OnChromeWorkerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var w = (Window)d;
- var cw = (WindowChromeWorker)e.NewValue;
- // The WindowChromeWorker object should only be set on the window once, and never to null.
- Assert.IsNotNull(w);
- Assert.IsNotNull(cw);
- Assert.IsNull(cw._window);
- cw._SetWindow(w);
- }
- private void _SetWindow(Window window)
- {
- Assert.IsNull(_window);
- Assert.IsNotNull(window);
- _window = window;
- // There are potentially a couple funny states here.
- // The window may have been shown and closed, in which case it's no longer usable.
- // We shouldn't add any hooks in that case, just exit early.
- // If the window hasn't yet been shown, then we need to make sure to remove hooks after it's closed.
- _hwnd = new WindowInteropHelper(_window).Handle;
- if (Utility.IsPresentationFrameworkVersionLessThan4)
- {
- // On older versions of the framework the client size of the window is incorrectly calculated.
- // We need to modify the template to fix this on behalf of the user.
- Utility.AddDependencyPropertyChangeListener(_window, Window.TemplateProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup);
- Utility.AddDependencyPropertyChangeListener(_window, Window.FlowDirectionProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup);
- }
- _window.Closed += _UnsetWindow;
- // Use whether we can get an HWND to determine if the Window has been loaded.
- if (IntPtr.Zero != _hwnd)
- {
- // We've seen that the HwndSource can't always be retrieved from the HWND, so cache it early.
- // Specifically it seems to sometimes disappear when the OS theme is changing.
- _hwndSource = HwndSource.FromHwnd(_hwnd);
- Assert.IsNotNull(_hwndSource);
- _window.ApplyTemplate();
- if (_chromeInfo != null)
- {
- _ApplyNewCustomChrome();
- }
- }
- else
- {
- _window.SourceInitialized += (sender, e) =>
- {
- _hwnd = new WindowInteropHelper(_window).Handle;
- Assert.IsNotDefault(_hwnd);
- _hwndSource = HwndSource.FromHwnd(_hwnd);
- Assert.IsNotNull(_hwndSource);
- if (_chromeInfo != null)
- {
- _ApplyNewCustomChrome();
- }
- };
- }
- }
- private void _UnsetWindow(object sender, EventArgs e)
- {
- if (Utility.IsPresentationFrameworkVersionLessThan4)
- {
- Utility.RemoveDependencyPropertyChangeListener(_window, Window.TemplateProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup);
- Utility.RemoveDependencyPropertyChangeListener(_window, Window.FlowDirectionProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup);
- }
- if (_chromeInfo != null)
- {
- _chromeInfo.PropertyChangedThatRequiresRepaint -= _OnChromePropertyChangedThatRequiresRepaint;
- }
- _RestoreStandardChromeState(true);
- }
- [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
- public static WindowChromeWorker GetWindowChromeWorker(Window window)
- {
- Verify.IsNotNull(window, "window");
- return (WindowChromeWorker)window.GetValue(WindowChromeWorkerProperty);
- }
- [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
- public static void SetWindowChromeWorker(Window window, WindowChromeWorker chrome)
- {
- Verify.IsNotNull(window, "window");
- window.SetValue(WindowChromeWorkerProperty, chrome);
- }
- private void _OnWindowPropertyChangedThatRequiresTemplateFixup(object sender, EventArgs e)
- {
- Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4);
- if (_chromeInfo != null && _hwnd != IntPtr.Zero)
- {
- // Assume that when the template changes it's going to be applied.
- // We don't have a good way to externally hook into the template
- // actually being applied, so we asynchronously post the fixup operation
- // at Loaded priority, so it's expected that the visual tree will be
- // updated before _FixupFrameworkIssues is called.
- _window.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (_Action)_FixupFrameworkIssues);
- }
- }
- private void _ApplyNewCustomChrome()
- {
- if (_hwnd == IntPtr.Zero)
- {
- // Not yet hooked.
- return;
- }
- if (_chromeInfo == null)
- {
- _RestoreStandardChromeState(false);
- return;
- }
- if (!_isHooked)
- {
- _hwndSource.AddHook(_WndProc);
- _isHooked = true;
- }
- _FixupFrameworkIssues();
- // Force this the first time.
- _UpdateSystemMenu(_window.WindowState);
- _UpdateFrameState(true);
- NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, _SwpFlags);
- }
- private void _FixupFrameworkIssues()
- {
- Assert.IsNotNull(_chromeInfo);
- Assert.IsNotNull(_window);
- // 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)
- {
- return;
- }
- if (_window.Template == null)
- {
- // Nothing to fixup yet. This will get called again when a template does get set.
- return;
- }
- // Guard against the visual tree being empty.
- if (VisualTreeHelper.GetChildrenCount(_window) == 0)
- {
- // The template isn't null, but we don't have a visual tree.
- // Hope that ApplyTemplate is in the queue and repost this, because there's not much we can do right now.
- _window.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (_Action)_FixupFrameworkIssues);
- return;
- }
- var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0);
- RECT rcWindow = NativeMethods.GetWindowRect(_hwnd);
- RECT rcAdjustedClient = _GetAdjustedWindowRect(rcWindow);
- Rect rcLogicalWindow = DpiHelper.DeviceRectToLogical(new Rect(rcWindow.Left, rcWindow.Top, rcWindow.Width, rcWindow.Height));
- Rect rcLogicalClient = DpiHelper.DeviceRectToLogical(new Rect(rcAdjustedClient.Left, rcAdjustedClient.Top, rcAdjustedClient.Width, rcAdjustedClient.Height));
- Thickness nonClientThickness = new Thickness(
- rcLogicalWindow.Left - rcLogicalClient.Left,
- rcLogicalWindow.Top - rcLogicalClient.Top,
- rcLogicalClient.Right - rcLogicalWindow.Right,
- rcLogicalClient.Bottom - rcLogicalWindow.Bottom);
- rootElement.Margin = new Thickness(
- 0,
- 0,
- -(nonClientThickness.Left + nonClientThickness.Right),
- -(nonClientThickness.Top + nonClientThickness.Bottom));
- // 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)
- {
- rootElement.RenderTransform = new MatrixTransform(1, 0, 0, 1, -(nonClientThickness.Left + nonClientThickness.Right), 0);
- }
- else
- {
- rootElement.RenderTransform = null;
- }
- if (!_isFixedUp)
- {
- _hasUserMovedWindow = false;
- _window.StateChanged += _FixupRestoreBounds;
- _isFixedUp = true;
- }
- }
- // There was a regression in DWM in Windows 7 with regard to handling WM_NCCALCSIZE to effect custom chrome.
- // When windows with glass are maximized on a multimonitor setup the glass frame tends to turn black.
- // Also when windows are resized they tend to flicker black, sometimes staying that way until resized again.
- //
- // This appears to be a bug in DWM related to device bitmap optimizations. At least on RTM Win7 we can
- // evoke a legacy code path that bypasses the bug by calling an esoteric DWM function. This doesn't affect
- // the system, just the application.
- // WPF also tends to call this function anyways during animations, so we're just forcing the issue
- // consistently and a bit earlier.
- [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
- private void _FixupWindows7Issues()
- {
- if (_blackGlassFixupAttemptCount > 5)
- {
- // Don't keep trying if there's an endemic problem with this.
- return;
- }
- if (Utility.IsOSWindows7OrNewer && NativeMethods.DwmIsCompositionEnabled())
- {
- ++_blackGlassFixupAttemptCount;
- bool success = false;
- try
- {
- DWM_TIMING_INFO? dti = NativeMethods.DwmGetCompositionTimingInfo(_hwnd);
- success = dti != null;
- }
- catch (Exception)
- {
- // We aren't sure of all the reasons this could fail.
- // If we find new ones we should consider making the NativeMethod swallow them as well.
- // Since we have a limited number of retries and this method isn't actually critical, just repost.
- // Disabling this for the published code to reduce debug noise. This will get compiled away for retail binaries anyways.
- //Assert.Fail(e.Message);
- }
- // NativeMethods.DwmGetCompositionTimingInfo swallows E_PENDING.
- // If the call wasn't successful, try again later.
- if (!success)
- {
- Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (_Action)_FixupWindows7Issues);
- }
- else
- {
- // Reset this. We will want to force this again if DWM composition changes.
- _blackGlassFixupAttemptCount = 0;
- }
- }
- }
- 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)
- {
- _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));
- _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;
- }
- 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));
- return _window.RestoreBounds.Location != windowTopLeft;
- }
- }
- #region WindowProc and Message Handlers
- private IntPtr _WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
- {
- // Only expecting messages for our cached HWND.
- Assert.AreEqual(hwnd, _hwnd);
- var message = (WM)msg;
- foreach (var handlePair in _messageTable)
- {
- if (handlePair.Key == message)
- {
- return handlePair.Value(message, wParam, lParam, out handled);
- }
- }
- return IntPtr.Zero;
- }
- private IntPtr _HandleSetTextOrIcon(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
- {
- bool modified = _ModifyStyle(WS.VISIBLE, 0);
- // Setting the caption text and icon cause Windows to redraw the caption.
- // Letting the default WndProc handle the message without the WS_VISIBLE
- // style applied bypasses the redraw.
- IntPtr lRet = NativeMethods.DefWindowProc(_hwnd, uMsg, wParam, lParam);
- // Put back the style we removed.
- if (modified)
- {
- _ModifyStyle(0, WS.VISIBLE);
- }
- handled = true;
- return lRet;
- }
- private IntPtr _HandleNCActivate(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
- {
- // Despite MSDN's documentation of lParam not being used,
- // calling DefWindowProc with lParam set to -1 causes Windows not to draw over the caption.
- // Directly call DefWindowProc with a custom parameter
- // which bypasses any other handling of the message.
- IntPtr lRet = NativeMethods.DefWindowProc(_hwnd, WM.NCACTIVATE, wParam, new IntPtr(-1));
- handled = true;
- return lRet;
- }
- private IntPtr _HandleNCCalcSize(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
- {
- // lParam is an [in, out] that can be either a RECT* (wParam == FALSE) or an NCCALCSIZE_PARAMS*.
- // Since the first field of NCCALCSIZE_PARAMS is a RECT and is the only field we care about
- // we can unconditionally treat it as a RECT.
- // Since we always want the client size to equal the window size, we can unconditionally handle it
- // without having to modify the parameters.
- handled = true;
- return new IntPtr((int)WVR.REDRAW);
- }
- private IntPtr _HandleNCHitTest(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
- {
- IntPtr lRet = IntPtr.Zero;
- handled = false;
- // Give DWM a chance at this first.
- if (Utility.IsOSVistaOrNewer && _chromeInfo.GlassFrameThickness != default(Thickness) && _isGlassEnabled)
- {
- // If we're on Vista, give the DWM a chance to handle the message first.
- handled = NativeMethods.DwmDefWindowProc(_hwnd, uMsg, wParam, lParam, out lRet);
- }
- // Handle letting the system know if we consider the mouse to be in our effective non-client area.
- // If DWM already handled this by way of DwmDefWindowProc, then respect their call.
- if (IntPtr.Zero == lRet)
- {
- var mousePosScreen = new Point(Utility.GET_X_LPARAM(lParam), Utility.GET_Y_LPARAM(lParam));
- Rect windowPosition = _GetWindowRect();
- HT ht = _HitTestNca(
- DpiHelper.DeviceRectToLogical(windowPosition),
- DpiHelper.DevicePixelsToLogical(mousePosScreen));
- // Don't blindly respect HTCAPTION.
- // We want UIElements in the caption area to be actionable so run through a hittest first.
- if (ht != HT.CLIENT)
- {
- Point mousePosWindow = mousePosScreen;
- mousePosWindow.Offset(-windowPosition.X, -windowPosition.Y);
- mousePosWindow = DpiHelper.DevicePixelsToLogical(mousePosWindow);
- IInputElement inputElement = _window.InputHitTest(mousePosWindow);
- if (inputElement != null && WindowChrome.GetIsHitTestVisibleInChrome(inputElement))
- {
- ht = HT.CLIENT;
- }
- }
- handled = true;
- lRet = new IntPtr((int)ht);
- }
- return lRet;
- }
- private IntPtr _HandleNCRButtonUp(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
- {
- // Emulate the system behavior of clicking the right mouse button over the caption area
- // to bring up the system menu.
- if (HT.CAPTION == (HT)wParam.ToInt32())
- {
- if (_window.ContextMenu != null)
- {
- _window.ContextMenu.Placement = PlacementMode.MousePoint;
- _window.ContextMenu.IsOpen = true;
- }
- else if (WindowChrome.GetWindowChrome(_window).ShowSystemMenu)
- SystemCommands.ShowSystemMenuPhysicalCoordinates(_window, new Point(Utility.GET_X_LPARAM(lParam), Utility.GET_Y_LPARAM(lParam)));
- }
- handled = false;
- return IntPtr.Zero;
- }
- private IntPtr _HandleSize(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
- {
- const int SIZE_MAXIMIZED = 2;
- // Force when maximized.
- // We can tell what's happening right now, but the Window doesn't yet know it's
- // maximized. Not forcing this update will eventually cause the
- // default caption to be drawn.
- WindowState? state = null;
- if (wParam.ToInt32() == SIZE_MAXIMIZED)
- {
- state = WindowState.Maximized;
- }
- _UpdateSystemMenu(state);
- // Still let the default WndProc handle this.
- handled = false;
- return IntPtr.Zero;
- }
- private IntPtr _HandleWindowPosChanged(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
- {
- // http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx
- // The WM_WINDOWPOSCHANGED message is sent at the end of the window
- // state change process. It sort of combines the other state change
- // notifications, WM_MOVE, WM_SIZE, and WM_SHOWWINDOW. But it doesn't
- // suffer from the same limitations as WM_SHOWWINDOW, so you can
- // reliably use it to react to the window being shown or hidden.
- _UpdateSystemMenu(null);
- if (!_isGlassEnabled)
- {
- Assert.IsNotDefault(lParam);
- var wp = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
- _SetRoundingRegion(wp);
- }
- // Still want to pass this to DefWndProc
- handled = false;
- return IntPtr.Zero;
- }
- private IntPtr _HandleDwmCompositionChanged(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled)
- {
- _UpdateFrameState(false);
- handled = false;
- 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);
- _FixupFrameworkIssues();
- 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>
- /// <param name="removeStyle">The styles to be removed. These can be bitwise combined.</param>
- /// <param name="addStyle">The styles to be added. These can be bitwise combined.</param>
- /// <returns>Whether the styles of the HWND were modified as a result of this call.</returns>
- private bool _ModifyStyle(WS removeStyle, WS addStyle)
- {
- Assert.IsNotDefault(_hwnd);
- var dwStyle = (WS)NativeMethods.GetWindowLongPtr(_hwnd, GWL.STYLE).ToInt32();
- var dwNewStyle = (dwStyle & ~removeStyle) | addStyle;
- if (dwStyle == dwNewStyle)
- {
- return false;
- }
- NativeMethods.SetWindowLongPtr(_hwnd, GWL.STYLE, new IntPtr((int)dwNewStyle));
- return true;
- }
- /// <summary>
- /// Get the WindowState as the native HWND knows it to be. This isn't necessarily the same as what Window thinks.
- /// </summary>
- private WindowState _GetHwndState()
- {
- var wpl = NativeMethods.GetWindowPlacement(_hwnd);
- switch (wpl.showCmd)
- {
- case SW.SHOWMINIMIZED: return WindowState.Minimized;
- case SW.SHOWMAXIMIZED: return WindowState.Maximized;
- }
- return WindowState.Normal;
- }
- /// <summary>
- /// Get the bounding rectangle for the window in physical coordinates.
- /// </summary>
- /// <returns>The bounding rectangle for the window.</returns>
- private Rect _GetWindowRect()
- {
- // Get the window rectangle.
- RECT windowPosition = NativeMethods.GetWindowRect(_hwnd);
- return new Rect(windowPosition.Left, windowPosition.Top, windowPosition.Width, windowPosition.Height);
- }
- /// <summary>
- /// Update the items in the system menu based on the current, or assumed, WindowState.
- /// </summary>
- /// <param name="assumeState">
- /// The state to assume that the Window is in. This can be null to query the Window's state.
- /// </param>
- /// <remarks>
- /// We want to update the menu while we have some control over whether the caption will be repainted.
- /// </remarks>
- private void _UpdateSystemMenu(WindowState? assumeState)
- {
- const MF mfEnabled = MF.ENABLED | MF.BYCOMMAND;
- const MF mfDisabled = MF.GRAYED | MF.DISABLED | MF.BYCOMMAND;
- WindowState state = assumeState ?? _GetHwndState();
- if (null != assumeState || _lastMenuState != state)
- {
- _lastMenuState = state;
- bool modified = _ModifyStyle(WS.VISIBLE, 0);
- IntPtr hmenu = NativeMethods.GetSystemMenu(_hwnd, false);
- if (IntPtr.Zero != hmenu)
- {
- var dwStyle = (WS)NativeMethods.GetWindowLongPtr(_hwnd, GWL.STYLE).ToInt32();
- bool canMinimize = Utility.IsFlagSet((int)dwStyle, (int)WS.MINIMIZEBOX);
- bool canMaximize = Utility.IsFlagSet((int)dwStyle, (int)WS.MAXIMIZEBOX);
- bool canSize = Utility.IsFlagSet((int)dwStyle, (int)WS.THICKFRAME);
- switch (state)
- {
- case WindowState.Maximized:
- NativeMethods.EnableMenuItem(hmenu, SC.RESTORE, mfEnabled);
- NativeMethods.EnableMenuItem(hmenu, SC.MOVE, mfDisabled);
- NativeMethods.EnableMenuItem(hmenu, SC.SIZE, mfDisabled);
- NativeMethods.EnableMenuItem(hmenu, SC.MINIMIZE, canMinimize ? mfEnabled : mfDisabled);
- NativeMethods.EnableMenuItem(hmenu, SC.MAXIMIZE, mfDisabled);
- break;
- case WindowState.Minimized:
- NativeMethods.EnableMenuItem(hmenu, SC.RESTORE, mfEnabled);
- NativeMethods.EnableMenuItem(hmenu, SC.MOVE, mfDisabled);
- NativeMethods.EnableMenuItem(hmenu, SC.SIZE, mfDisabled);
- NativeMethods.EnableMenuItem(hmenu, SC.MINIMIZE, mfDisabled);
- NativeMethods.EnableMenuItem(hmenu, SC.MAXIMIZE, canMaximize ? mfEnabled : mfDisabled);
- break;
- default:
- NativeMethods.EnableMenuItem(hmenu, SC.RESTORE, mfDisabled);
- NativeMethods.EnableMenuItem(hmenu, SC.MOVE, mfEnabled);
- NativeMethods.EnableMenuItem(hmenu, SC.SIZE, canSize ? mfEnabled : mfDisabled);
- NativeMethods.EnableMenuItem(hmenu, SC.MINIMIZE, canMinimize ? mfEnabled : mfDisabled);
- NativeMethods.EnableMenuItem(hmenu, SC.MAXIMIZE, canMaximize ? mfEnabled : mfDisabled);
- break;
- }
- }
- if (modified)
- {
- _ModifyStyle(0, WS.VISIBLE);
- }
- }
- }
- private void _UpdateFrameState(bool force)
- {
- if (IntPtr.Zero == _hwnd)
- {
- return;
- }
- // Don't rely on SystemParameters2 for this, just make the check ourselves.
- bool frameState = NativeMethods.DwmIsCompositionEnabled();
- if (force || frameState != _isGlassEnabled)
- {
- _isGlassEnabled = frameState && _chromeInfo.GlassFrameThickness != default(Thickness);
- if (!_isGlassEnabled)
- {
- _SetRoundingRegion(null);
- }
- else
- {
- _ClearRoundingRegion();
- _ExtendGlassFrame();
- _FixupWindows7Issues();
- }
- NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, _SwpFlags);
- }
- }
- private void _ClearRoundingRegion()
- {
- NativeMethods.SetWindowRgn(_hwnd, IntPtr.Zero, NativeMethods.IsWindowVisible(_hwnd));
- }
- private void _SetRoundingRegion(WINDOWPOS? wp)
- {
- const int MONITOR_DEFAULTTONEAREST = 0x00000002;
- // We're early - WPF hasn't necessarily updated the state of the window.
- // Need to query it ourselves.
- WINDOWPLACEMENT wpl = NativeMethods.GetWindowPlacement(_hwnd);
- if (wpl.showCmd == SW.SHOWMAXIMIZED)
- {
- int left;
- int top;
- if (wp.HasValue)
- {
- left = wp.Value.x;
- top = wp.Value.y;
- }
- else
- {
- Rect r = _GetWindowRect();
- left = (int)r.Left;
- top = (int)r.Top;
- }
- IntPtr hMon = NativeMethods.MonitorFromWindow(_hwnd, MONITOR_DEFAULTTONEAREST);
- MONITORINFO mi = NativeMethods.GetMonitorInfo(hMon);
- RECT rcMax = mi.rcWork;
- // The location of maximized window takes into account the border that Windows was
- // going to remove, so we also need to consider it.
- rcMax.Offset(-left, -top);
- IntPtr hrgn = IntPtr.Zero;
- try
- {
- hrgn = NativeMethods.CreateRectRgnIndirect(rcMax);
- NativeMethods.SetWindowRgn(_hwnd, hrgn, NativeMethods.IsWindowVisible(_hwnd));
- hrgn = IntPtr.Zero;
- }
- finally
- {
- Utility.SafeDeleteObject(ref hrgn);
- }
- }
- else
- {
- Size windowSize;
- // Use the size if it's specified.
- if (null != wp && !Utility.IsFlagSet(wp.Value.flags, (int)SWP.NOSIZE))
- {
- windowSize = new Size((double)wp.Value.cx, (double)wp.Value.cy);
- }
- else if (null != wp && (_lastRoundingState == _window.WindowState))
- {
- return;
- }
- else
- {
- windowSize = _GetWindowRect().Size;
- }
- _lastRoundingState = _window.WindowState;
- IntPtr hrgn = IntPtr.Zero;
- try
- {
- double shortestDimension = Math.Min(windowSize.Width, windowSize.Height);
- double topLeftRadius = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.TopLeft, 0)).X;
- topLeftRadius = Math.Min(topLeftRadius, shortestDimension / 2);
- if (_IsUniform(_chromeInfo.CornerRadius))
- {
- // RoundedRect HRGNs require an additional pixel of padding.
- hrgn = _CreateRoundRectRgn(new Rect(windowSize), topLeftRadius);
- }
- else
- {
- // We need to combine HRGNs for each of the corners.
- // Create one for each quadrant, but let it overlap into the two adjacent ones
- // by the radius amount to ensure that there aren't corners etched into the middle
- // of the window.
- hrgn = _CreateRoundRectRgn(new Rect(0, 0, windowSize.Width / 2 + topLeftRadius, windowSize.Height / 2 + topLeftRadius), topLeftRadius);
- double topRightRadius = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.TopRight, 0)).X;
- topRightRadius = Math.Min(topRightRadius, shortestDimension / 2);
- Rect topRightRegionRect = new Rect(0, 0, windowSize.Width / 2 + topRightRadius, windowSize.Height / 2 + topRightRadius);
- topRightRegionRect.Offset(windowSize.Width / 2 - topRightRadius, 0);
- Assert.AreEqual(topRightRegionRect.Right, windowSize.Width);
- _CreateAndCombineRoundRectRgn(hrgn, topRightRegionRect, topRightRadius);
- double bottomLeftRadius = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.BottomLeft, 0)).X;
- bottomLeftRadius = Math.Min(bottomLeftRadius, shortestDimension / 2);
- Rect bottomLeftRegionRect = new Rect(0, 0, windowSize.Width / 2 + bottomLeftRadius, windowSize.Height / 2 + bottomLeftRadius);
- bottomLeftRegionRect.Offset(0, windowSize.Height / 2 - bottomLeftRadius);
- Assert.AreEqual(bottomLeftRegionRect.Bottom, windowSize.Height);
- _CreateAndCombineRoundRectRgn(hrgn, bottomLeftRegionRect, bottomLeftRadius);
- double bottomRightRadius = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.BottomRight, 0)).X;
- bottomRightRadius = Math.Min(bottomRightRadius, shortestDimension / 2);
- Rect bottomRightRegionRect = new Rect(0, 0, windowSize.Width / 2 + bottomRightRadius, windowSize.Height / 2 + bottomRightRadius);
- bottomRightRegionRect.Offset(windowSize.Width / 2 - bottomRightRadius, windowSize.Height / 2 - bottomRightRadius);
- Assert.AreEqual(bottomRightRegionRect.Right, windowSize.Width);
- Assert.AreEqual(bottomRightRegionRect.Bottom, windowSize.Height);
- _CreateAndCombineRoundRectRgn(hrgn, bottomRightRegionRect, bottomRightRadius);
- }
- NativeMethods.SetWindowRgn(_hwnd, hrgn, NativeMethods.IsWindowVisible(_hwnd));
- hrgn = IntPtr.Zero;
- }
- finally
- {
- // Free the memory associated with the HRGN if it wasn't assigned to the HWND.
- Utility.SafeDeleteObject(ref hrgn);
- }
- }
- }
- private static IntPtr _CreateRoundRectRgn(Rect region, double radius)
- {
- // Round outwards.
- if (DoubleUtilities.AreClose(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));
- }
- // RoundedRect HRGNs require an additional pixel of padding on the bottom right to look correct.
- 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));
- }
- [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "HRGNs")]
- private static void _CreateAndCombineRoundRectRgn(IntPtr hrgnSource, Rect region, double radius)
- {
- IntPtr hrgn = IntPtr.Zero;
- try
- {
- hrgn = _CreateRoundRectRgn(region, radius);
- CombineRgnResult result = NativeMethods.CombineRgn(hrgnSource, hrgnSource, hrgn, RGN.OR);
- if (result == CombineRgnResult.ERROR)
- {
- throw new InvalidOperationException("Unable to combine two HRGNs.");
- }
- }
- catch
- {
- Utility.SafeDeleteObject(ref hrgn);
- throw;
- }
- }
- 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 void _ExtendGlassFrame()
- {
- Assert.IsNotNull(_window);
- // Expect that this might be called on OSes other than Vista.
- if (!Utility.IsOSVistaOrNewer)
- {
- // Not an error. Just not on Vista so we're not going to get glass.
- return;
- }
- if (IntPtr.Zero == _hwnd)
- {
- // Can't do anything with this call until the Window has been shown.
- return;
- }
- // Ensure standard HWND background painting when DWM isn't enabled.
- if (!NativeMethods.DwmIsCompositionEnabled())
- {
- _hwndSource.CompositionTarget.BackgroundColor = SystemColors.WindowColor;
- }
- else
- {
- // This makes the glass visible at a Win32 level so long as nothing else is covering it.
- // The Window's Background needs to be changed independent of this.
- // Apply the transparent background to the HWND
- _hwndSource.CompositionTarget.BackgroundColor = Colors.Transparent;
- // Thickness is going to be DIPs, need to convert to system coordinates.
- Point deviceTopLeft = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.GlassFrameThickness.Left, _chromeInfo.GlassFrameThickness.Top));
- Point deviceBottomRight = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.GlassFrameThickness.Right, _chromeInfo.GlassFrameThickness.Bottom));
- var dwmMargin = new MARGINS
- {
- // err on the side of pushing in glass an extra pixel.
- cxLeftWidth = (int)Math.Ceiling(deviceTopLeft.X),
- cxRightWidth = (int)Math.Ceiling(deviceBottomRight.X),
- cyTopHeight = (int)Math.Ceiling(deviceTopLeft.Y),
- cyBottomHeight = (int)Math.Ceiling(deviceBottomRight.Y),
- };
- NativeMethods.DwmExtendFrameIntoClientArea(_hwnd, ref dwmMargin);
- }
- }
- /// <summary>
- /// Matrix of the HT values to return when responding to NC window messages.
- /// </summary>
- [SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Member")]
- private static readonly HT[,] _HitTestBorders = new[,]
- {
- { HT.TOPLEFT, HT.TOP, HT.TOPRIGHT },
- { HT.LEFT, HT.CLIENT, HT.RIGHT },
- { HT.BOTTOMLEFT, HT.BOTTOM, HT.BOTTOMRIGHT },
- };
- private HT _HitTestNca(Rect windowPosition, Point mousePosition)
- {
- // Determine if hit test is for resizing, default middle (1,1).
- int uRow = 1;
- int uCol = 1;
- bool onResizeBorder = false;
- // Determine if the point is at the top or bottom of the window.
- if (mousePosition.Y >= windowPosition.Top && mousePosition.Y < windowPosition.Top + _chromeInfo.ResizeBorderThickness.Top + _chromeInfo.CaptionHeight)
- {
- onResizeBorder = (mousePosition.Y < (windowPosition.Top + _chromeInfo.ResizeBorderThickness.Top));
- uRow = 0; // top (caption or resize border)
- }
- else if (mousePosition.Y < windowPosition.Bottom && mousePosition.Y >= windowPosition.Bottom - (int)_chromeInfo.ResizeBorderThickness.Bottom)
- {
- uRow = 2; // bottom
- }
- // Determine if the point is at the left or right of the window.
- if (mousePosition.X >= windowPosition.Left && mousePosition.X < windowPosition.Left + (int)_chromeInfo.ResizeBorderThickness.Left)
- {
- uCol = 0; // left side
- }
- else if (mousePosition.X < windowPosition.Right && mousePosition.X >= windowPosition.Right - _chromeInfo.ResizeBorderThickness.Right)
- {
- uCol = 2; // right side
- }
- // If the cursor is in one of the top edges by the caption bar, but below the top resize border,
- // then resize left-right rather than diagonally.
- if (uRow == 0 && uCol != 1 && !onResizeBorder)
- {
- uRow = 1;
- }
- HT ht = _HitTestBorders[uRow, uCol];
- if (ht == HT.TOP && !onResizeBorder)
- {
- ht = HT.CAPTION;
- }
- return ht;
- }
- #region Remove Custom Chrome Methods
- private void _RestoreStandardChromeState(bool isClosing)
- {
- VerifyAccess();
- _UnhookCustomChrome();
- if (!isClosing)
- {
- _RestoreFrameworkIssueFixups();
- _RestoreGlassFrame();
- _RestoreHrgn();
- _window.InvalidateMeasure();
- }
- }
- private void _UnhookCustomChrome()
- {
- Assert.IsNotDefault(_hwnd);
- Assert.IsNotNull(_window);
- if (_isHooked)
- {
- _hwndSource.RemoveHook(_WndProc);
- _isHooked = false;
- }
- }
- private void _RestoreFrameworkIssueFixups()
- {
- // 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);
- var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0);
- // Undo anything that was done before.
- rootElement.Margin = new Thickness();
- _window.StateChanged -= _FixupRestoreBounds;
- _isFixedUp = false;
- }
- }
- private void _RestoreGlassFrame()
- {
- Assert.IsNull(_chromeInfo);
- Assert.IsNotNull(_window);
- // Expect that this might be called on OSes other than Vista
- // and if the window hasn't yet been shown, then we don't need to undo anything.
- if (!Utility.IsOSVistaOrNewer || _hwnd == IntPtr.Zero)
- {
- return;
- }
- _hwndSource.CompositionTarget.BackgroundColor = SystemColors.WindowColor;
- if (NativeMethods.DwmIsCompositionEnabled())
- {
- // If glass is enabled, push it back to the normal bounds.
- var dwmMargin = new MARGINS();
- NativeMethods.DwmExtendFrameIntoClientArea(_hwnd, ref dwmMargin);
- }
- }
- private void _RestoreHrgn()
- {
- _ClearRoundingRegion();
- NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, _SwpFlags);
- }
- #endregion
- }
- }
|