Пример #1
0
        private void SetRoundingRegion(NativeMethods.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.
            NativeMethods.WINDOWPLACEMENT wpl = new NativeMethods.WINDOWPLACEMENT();
            NativeMethods.GetWindowPlacement(handle, wpl);

            if (wpl.showCmd == NativeMethods.SW_SHOWMAXIMIZED && IsDwmEnabled == true)
            {
                int left;
                int top;

                if (wp.HasValue)
                {
                    left = wp.Value.x;
                    top = wp.Value.y;
                }
                else
                {
                    NativeMethods.Rect r = new NativeMethods.Rect();
                    NativeMethods.GetWindowRect(handle, ref r);
                    left = r.Left;
                    top = r.Top;
                }

                IntPtr hMon = NativeMethods.MonitorFromWindow(handle, MONITOR_DEFAULTTONEAREST);

                NativeMethods.MonitorInfo mi = new NativeMethods.MonitorInfo();
                NativeMethods.GetMonitorInfo(hMon, mi);
                NativeMethods.Rect rcMax = mi.Work;
                // The location of maximized window takes into account the border that Windows was
                // going to remove, so we also need to consider it.
                rcMax.Left -= left; rcMax.Right -= left;
                rcMax.Top -= top; rcMax.Bottom -= top;

                IntPtr hrgn = IntPtr.Zero;
                try
                {
                    hrgn = NativeMethods.CreateRectRgnIndirect(ref rcMax);
                    NativeMethods.SetWindowRgn(handle, hrgn, NativeMethods.IsWindowVisible(handle));
                    hrgn = IntPtr.Zero;
                }
                finally
                {
                    NativeMethods.DeleteObject(hrgn);
                }
            }
            else
            {
                Size windowSize;

                // Use the size if it's specified.
                if (null != wp && !IsFlagSet(wp.Value.flags, NativeMethods.SWP_NOSIZE))
                {
                    windowSize = new Size((double)wp.Value.cx, (double)wp.Value.cy);
                }
                else if (null != wp && (lastRoundingState == WindowState))
                {
                    return;
                }
                else
                {
                    NativeMethods.Rect r = new NativeMethods.Rect();
                    NativeMethods.GetWindowRect(handle, ref r);
                    Rect rect = new Rect(r.Left, r.Top, r.Right - r.Left, r.Bottom - r.Top);
                    windowSize = rect.Size;
                }

                lastRoundingState = WindowState;

                IntPtr hrgn = IntPtr.Zero;
                try
                {
                    double shortestDimension = Math.Min(windowSize.Width, windowSize.Height);

                    double topLeftRadius = DpiHelper.LogicalPixelsToDevice(new Point(CornerRadius.TopLeft, 0)).X;
                    topLeftRadius = Math.Min(topLeftRadius, shortestDimension / 2);

                    if (IsUniform(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(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);

                        CreateAndCombineRoundRectRgn(hrgn, topRightRegionRect, topRightRadius);

                        double bottomLeftRadius = /*DpiHelper.LogicalPixelsToDevice*/(new Point(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);

                        CreateAndCombineRoundRectRgn(hrgn, bottomLeftRegionRect, bottomLeftRadius);

                        double bottomRightRadius = DpiHelper.LogicalPixelsToDevice(new Point(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);

                        CreateAndCombineRoundRectRgn(hrgn, bottomRightRegionRect, bottomRightRadius);
                    }

                    NativeMethods.SetWindowRgn(handle, hrgn, NativeMethods.IsWindowVisible(handle));
                    hrgn = IntPtr.Zero;
                }
                finally
                {
                    // Free the memory associated with the HRGN if it wasn't assigned to the HWND.
                    NativeMethods.DeleteObject(hrgn);
                }
            }
        }
        /// <summary>
        /// Implements custom placement for ribbon popup
        /// </summary>
        /// <param name="popupsize"></param>
        /// <param name="targetsize"></param>
        /// <param name="offset"></param>
        /// <returns></returns>
        CustomPopupPlacement[] CustomPopupPlacementMethod(Size popupsize, Size targetsize, Point offset)
        {
            if ((popup != null) && (SelectedTabItem != null))
            {
                // Get current workarea                
                Point tabItemPos = SelectedTabItem.PointToScreen(new Point(0, 0));
                NativeMethods.Rect tabItemRect = new NativeMethods.Rect();
                tabItemRect.Left = (int)tabItemPos.X;
                tabItemRect.Top = (int)tabItemPos.Y;
                tabItemRect.Right = (int)tabItemPos.X + (int)SelectedTabItem.ActualWidth;
                tabItemRect.Bottom = (int)tabItemPos.Y + (int)SelectedTabItem.ActualHeight;

                uint MONITOR_DEFAULTTONEAREST = 0x00000002;
                System.IntPtr monitor = NativeMethods.MonitorFromRect(ref tabItemRect, MONITOR_DEFAULTTONEAREST);
                if (monitor != System.IntPtr.Zero)
                {
                    NativeMethods.MonitorInfo monitorInfo = new NativeMethods.MonitorInfo();
                    monitorInfo.Size = Marshal.SizeOf(monitorInfo);
                    NativeMethods.GetMonitorInfo(monitor, monitorInfo);

                    Point startPoint = PointToScreen(new Point(0, 0));
                    if (FlowDirection == FlowDirection.RightToLeft) startPoint.X -= ActualWidth;
                    double inWindowRibbonWidth = monitorInfo.Work.Right - Math.Max(monitorInfo.Work.Left, startPoint.X);

                    double actualWidth = ActualWidth;
                    if (startPoint.X < monitorInfo.Work.Left)
                    {
                        actualWidth -= monitorInfo.Work.Left - startPoint.X;
                        startPoint.X = monitorInfo.Work.Left;
                    }
                    // Set width
                    popup.Width = Math.Min(actualWidth, inWindowRibbonWidth);
                    return new CustomPopupPlacement[]
                               {
                                   new CustomPopupPlacement(new Point(startPoint.X - tabItemPos.X, SelectedTabItem.ActualHeight-(popup.Child as FrameworkElement).Margin.Top), PopupPrimaryAxis.None),
                                   new CustomPopupPlacement(new Point(startPoint.X - tabItemPos.X, -(SelectedContent as ScrollViewer).ActualHeight-(popup.Child as FrameworkElement).Margin.Bottom), PopupPrimaryAxis.None),
                               };
                }
            }
            return null;
        }
Пример #3
0
        private IntPtr DoHitTest(int msg, IntPtr wParam, IntPtr lParam, out bool handled)
        {
            IntPtr lRet = IntPtr.Zero;
            handled = false;

            // Give DWM a chance at this first.
            if (IsDwmEnabled && (Mouse.Captured == null))
            {
                // If we're on Vista, give the DWM a chance to handle the message first.
                handled = NativeMethods.DwmDefWindowProc(handle, msg, wParam, lParam, ref 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(NativeMethods.LowWord(lParam), NativeMethods.HiWord(lParam));
                NativeMethods.Rect wndPosition = new NativeMethods.Rect();
                NativeMethods.GetWindowRect(handle, ref wndPosition);
                Rect windowPosition = new Rect(wndPosition.Left, wndPosition.Top, wndPosition.Right - wndPosition.Left, wndPosition.Bottom - wndPosition.Top);

                int ht = HitTestNonClientArea(
                    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 != NativeMethods.HTCLIENT) && (mainGrid != null) && mainGrid.IsLoaded)
                {
                    /*int mp = lParam.ToInt32();
                    if (!mainGrid.IsVisible) return IntPtr.Zero;
                    Point ptMouse = new Point((short)(mp & 0x0000FFFF), (short)((mp >> 16) & 0x0000FFFF));
                    //ptMouse = DpiHelper.DevicePixelsToLogical(ptMouse);
                    ptMouse = mainGrid.PointFromScreen(ptMouse);*/
                    var ptMouse = mainGrid.PointFromScreen(mousePosScreen);

                    /*
                    Point mousePosWindow = mousePosScreen;
                    mousePosWindow.Offset(-windowPosition.X, -windowPosition.Y);*/

                    IInputElement inputElement = mainGrid.InputHitTest(ptMouse);
                    if (inputElement != null)
                    {
                        FrameworkElement frameworkElement = inputElement as FrameworkElement;
                        if ((frameworkElement != null) && (frameworkElement.Name == "PART_TitleBar")) ht = NativeMethods.HTCAPTION;
                        else if (inputElement != mainGrid) ht = NativeMethods.HTCLIENT;
                    }
                }

                // Check resize grip
                ResizeGrip grip = (GetTemplateChild("PART_ResizeGrip") as ResizeGrip);
                if ((grip != null) && (grip.IsLoaded) && (grip.InputHitTest(grip.PointFromScreen(mousePosScreen)) != null))
                {
                    if (FlowDirection == FlowDirection.LeftToRight) ht = NativeMethods.HTBOTTOMRIGHT;
                    else ht = NativeMethods.HTBOTTOMLEFT;
                }

                handled = true;
                lRet = new IntPtr(ht);
            }
            return lRet;
        }
Пример #4
0
        private void FixFrameworkIssues()
        {
            // This margin is only necessary if the client rectangle is going to be calculated incorrectly by WPF version less then 4.0
            if (FrameworkHelper.PresentationFrameworkVersion >= new Version("4.0"))
            {
                return;
            }

            if (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(this) == 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.
                Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (ThreadStart)FixFrameworkIssues);
                return;
            }

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

            NativeMethods.Rect rcWindow = new NativeMethods.Rect();
            NativeMethods.GetWindowRect(handle, ref rcWindow);
            NativeMethods.Rect rcAdjustedClient = GetAdjustedWindowRect(rcWindow);

            Rect rcLogicalWindow = DpiHelper.DeviceRectToLogical(new Rect(rcWindow.Left, rcWindow.Top, rcWindow.Right - rcWindow.Left, rcWindow.Bottom - rcWindow.Top));
            Rect rcLogicalClient = DpiHelper.DeviceRectToLogical(new Rect(rcAdjustedClient.Left, rcAdjustedClient.Top, rcAdjustedClient.Right - rcAdjustedClient.Left, rcAdjustedClient.Bottom - rcAdjustedClient.Top));

            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 (FlowDirection == FlowDirection.RightToLeft)
            {
                rootElement.RenderTransform = new MatrixTransform(1, 0, 0, 1, -(nonClientThickness.Left + nonClientThickness.Right), 0);
            }
            else
            {
                rootElement.RenderTransform = null;
            }

            if (!isFixedUp)
            {
                hasUserMovedWindow = false;
                StateChanged += FixRestoreBounds;

                isFixedUp = true;
            }
        }
Пример #5
0
 /// <summary>
 /// Returns screen workarea in witch control is placed
 /// </summary>
 /// <param name="control">Control</param>
 /// <returns>Workarea in witch control is placed</returns>
 public static Rect GetControlWorkArea(FrameworkElement control)
 {
     Point tabItemPos = control.PointToScreen(new Point(0, 0));
     NativeMethods.Rect tabItemRect = new NativeMethods.Rect();
     tabItemRect.Left = (int)tabItemPos.X;
     tabItemRect.Top = (int)tabItemPos.Y;
     tabItemRect.Right = (int)tabItemPos.X + (int)control.ActualWidth;
     tabItemRect.Bottom = (int)tabItemPos.Y + (int)control.ActualHeight;
     uint MONITOR_DEFAULTTONEAREST = 0x00000002;
     System.IntPtr monitor = NativeMethods.MonitorFromRect(ref tabItemRect, MONITOR_DEFAULTTONEAREST);
     if (monitor != System.IntPtr.Zero)
     {
         NativeMethods.MonitorInfo monitorInfo = new NativeMethods.MonitorInfo();
         monitorInfo.Size = Marshal.SizeOf(monitorInfo);
         NativeMethods.GetMonitorInfo(monitor, monitorInfo);
         return new Rect(monitorInfo.Work.Left, monitorInfo.Work.Top, monitorInfo.Work.Right - monitorInfo.Work.Left, monitorInfo.Work.Bottom - monitorInfo.Work.Top);
     }
     return new Rect();
 }
Пример #6
0
        /// <summary>
        /// Implements custom placement for ribbon popup
        /// </summary>
        /// <param name="popupsize"></param>
        /// <param name="targetsize"></param>
        /// <param name="offset"></param>
        /// <returns></returns>
        private CustomPopupPlacement[] CustomPopupPlacementMethod(Size popupsize, Size targetsize, Point offset)
        {
            if (this.DropDownPopup != null
                && this.SelectedTabItem != null)
            {
                // Get current workarea                
                var tabItemPos = this.SelectedTabItem.PointToScreen(new Point(0, 0));
                var tabItemRect = new NativeMethods.Rect
                                      {
                                          Left = (int)tabItemPos.X,
                                          Top = (int)tabItemPos.Y,
                                          Right = (int)tabItemPos.X + (int)this.SelectedTabItem.ActualWidth,
                                          Bottom = (int)tabItemPos.Y + (int)this.SelectedTabItem.ActualHeight
                                      };

                const uint MONITOR_DEFAULTTONEAREST = 0x00000002;

                var monitor = NativeMethods.MonitorFromRect(ref tabItemRect, MONITOR_DEFAULTTONEAREST);
                if (monitor != IntPtr.Zero)
                {
                    var monitorInfo = new NativeMethods.MonitorInfo();
                    monitorInfo.Size = Marshal.SizeOf(monitorInfo);
                    NativeMethods.GetMonitorInfo(monitor, monitorInfo);

                    var startPoint = this.PointToScreen(new Point(0, 0));
                    if (this.FlowDirection == FlowDirection.RightToLeft)
                    {
                        startPoint.X -= this.ActualWidth;
                    }

                    var inWindowRibbonWidth = monitorInfo.Work.Right - Math.Max(monitorInfo.Work.Left, startPoint.X);

                    var actualWidth = this.ActualWidth;
                    if (startPoint.X < monitorInfo.Work.Left)
                    {
                        actualWidth -= monitorInfo.Work.Left - startPoint.X;
                        startPoint.X = monitorInfo.Work.Left;
                    }

                    // Set width
                    this.DropDownPopup.Width = Math.Min(actualWidth, inWindowRibbonWidth);
                    return new[]
                               {
                                   new CustomPopupPlacement(new Point(startPoint.X - tabItemPos.X, this.SelectedTabItem.ActualHeight - ((FrameworkElement)this.DropDownPopup.Child).Margin.Top), PopupPrimaryAxis.None),
                                   new CustomPopupPlacement(new Point(startPoint.X - tabItemPos.X, -((ScrollViewer)this.SelectedContent).ActualHeight - ((FrameworkElement)this.DropDownPopup.Child).Margin.Bottom), PopupPrimaryAxis.None)
                               };
                }
            }

            return null;
        }
        private void FixRestoreBounds(object sender, EventArgs e)
        {
            if (WindowState == WindowState.Maximized || 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;
                    NativeMethods.WINDOWPLACEMENT wp = new NativeMethods.WINDOWPLACEMENT();
                    NativeMethods.GetWindowPlacement(handle, wp);

                    NativeMethods.Rect adjustedDeviceRc = /*GetAdjustedWindowRect(*/new NativeMethods.Rect { Bottom = 100, Right = 100 }/*)*/;
                    Point adjustedTopLeft = /*DpiHelper.DevicePixelsToLogical(*/
                        new Point(
                            wp.rcNormalPosition.Left - adjustedDeviceRc.Left,
                            wp.rcNormalPosition.Top - adjustedDeviceRc.Top)/*)*/;

                    Top = adjustedTopLeft.Y;
                    Left = adjustedTopLeft.X;
                }
            }
        }
        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            switch (msg)
            {
                case NativeMethods.WM_SETTEXT:
                case NativeMethods.WM_SETICON:
                    {
                        bool modified = ModifyStyle(NativeMethods.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(handle, msg, wParam, lParam);

                        // Put back the style we removed.
                        if (modified)
                        {
                            ModifyStyle(0, NativeMethods.WS_VISIBLE);
                        }
                        handled = true;
                        return lRet;
                    }
                case NativeMethods.WM_NCACTIVATE:
                    {
                        // 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(handle, NativeMethods.WM_NCACTIVATE, wParam, new IntPtr(-1));
                        IsNonClientAreaActive = (wParam != IntPtr.Zero);
                        handled = true;
                        return lRet;
                    }
                case NativeMethods.WM_NCCALCSIZE:
                    {
                        handled = true;
                        return new IntPtr((int)NativeMethods.WVR_REDRAW);
                    }
                case NativeMethods.WM_NCHITTEST:
                    {
                        IntPtr lRet = IntPtr.Zero;
                        handled = false;

                        // Give DWM a chance at this first.
                        if (IsDwmEnabled)
                        {
                            // If we're on Vista, give the DWM a chance to handle the message first.
                            handled = NativeMethods.DwmDefWindowProc(handle, msg, wParam, lParam, ref 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(NativeMethods.LowWord(lParam), NativeMethods.HiWord(lParam));
                            NativeMethods.Rect wndPosition = new NativeMethods.Rect();
                            NativeMethods.GetWindowRect(handle, ref wndPosition);
                            Rect windowPosition = new Rect(wndPosition.Left, wndPosition.Top, wndPosition.Right - wndPosition.Left, wndPosition.Bottom - wndPosition.Top);

                            int ht = HitTestNonClientArea(
                                /*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 != NativeMethods.HTCLIENT) && (mainGrid != null))
                            {
                                Point mousePosWindow = mousePosScreen;
                                mousePosWindow.Offset(-windowPosition.X, -windowPosition.Y);
                                //mousePosWindow = /*DpiHelper.DevicePixelsToLogical(*/mousePosWindow/*)*/;
                                IInputElement inputElement = mainGrid.InputHitTest(mousePosWindow);
                                if (inputElement != null)
                                {
                                    if ((inputElement as FrameworkElement).Name == "PART_TitleBar") ht = NativeMethods.HTCAPTION;
                                    else if (inputElement != mainGrid) ht = NativeMethods.HTCLIENT;
                                }
                            }
                            handled = true;
                            lRet = new IntPtr((int)ht);
                        }
                        return lRet;
                    }
                case NativeMethods.WM_NCRBUTTONUP:
                    {
                        // Emulate the system behavior of clicking the right mouse button over the caption area
                        // to bring up the system menu.
                        if (NativeMethods.HTCAPTION == wParam.ToInt32())
                        {
                            ShowSystemMenuPhysicalCoordinates(new Point(NativeMethods.LowWord(lParam), NativeMethods.HiWord(lParam)));
                        }
                        handled = false;
                        return IntPtr.Zero;
                    }
                case NativeMethods.WM_SIZE:
                    {
                        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;
                    }
                case NativeMethods.WM_WINDOWPOSCHANGED:
                    {

                        if (!IsDwmEnabled)
                        {
                            var wp = (NativeMethods.WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(NativeMethods.WINDOWPOS));
                            SetRoundingRegion(wp);
                        }

                        // Still want to pass this to DefWndProc
                        handled = false;
                        return IntPtr.Zero;
                    }
                case NativeMethods.WM_DWMCOMPOSITIONCHANGED:
                    {
                        IsDwmEnabled = NativeMethods.IsDwmEnabled();

                        UpdateFrameState(false);

                        handled = false;
                        return IntPtr.Zero;
                    }
            }

            if (PresentationFrameworkVersion < new Version("4.0"))
            {
                switch (msg)
                {
                    case NativeMethods.WM_SETTINGCHANGE:
                        {
                            FixFrameworkIssues();

                            handled = false;
                            return IntPtr.Zero;
                        }
                    case NativeMethods.WM_ENTERSIZEMOVE:
                        {
                            isUserResizing = true;

                            if (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(Left, 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;
                        }
                    case NativeMethods.WM_EXITSIZEMOVE:
                        {
                            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 (WindowState == WindowState.Maximized)
                            {
                                Top = windowPosAtStartOfUserMove.Y;
                                Left = windowPosAtStartOfUserMove.X;
                            }

                            handled = false;
                            return IntPtr.Zero;
                        }
                    case NativeMethods.WM_MOVE:
                        {
                            if (isUserResizing)
                            {
                                hasUserMovedWindow = true;
                            }

                            handled = false;
                            return IntPtr.Zero;
                        }
                }
            }

            return IntPtr.Zero;
        }
        /// <summary>
        /// Responds to the condition in which the value of the Popup.IsOpen property 
        /// changes from false to true.
        /// </summary>
        /// <param name="e">The event arguments.</param>
        protected override void OnOpened(EventArgs e)
        {
            base.OnOpened(e);
            
            isFirstMouseUp = true;

            PopupAnimation = PopupAnimation.None;

            if(Child!=null)hwndSource = (HwndSource)PresentationSource.FromVisual(this.Child);
            if (hwndSource != null)
            {
                hwndSource.AddHook(WindowProc);
                // Set popup non-topmost to fix bug with tooltips
                NativeMethods.Rect rect = new NativeMethods.Rect();
                if (NativeMethods.GetWindowRect(hwndSource.Handle, ref rect))
                {
                    NativeMethods.SetWindowPos(hwndSource.Handle, new IntPtr(-2), rect.Left, rect.Top, (int) this.Width,
                                               (int) this.Height,
                                               NativeMethods.SWP_NOMOVE | NativeMethods.SWP_NOSIZE |
                                               NativeMethods.SWP_NOACTIVATE);
                }
            }
            openedPopups.Add(this);

            Activate();                                    
        }