using System; using System.Runtime.InteropServices; using System.Windows; namespace FSI.Lib.Wpf.ExtensionMethods { public static class WindowExtensions { #region Public Methods public static bool ActivateCenteredToMouse(this Window window) { ComputeTopLeft(ref window); return window.Activate(); } public static void ShowCenteredToMouse(this Window window) { // in case the default start-up location isn't set to Manual WindowStartupLocation oldLocation = window.WindowStartupLocation; // set location to manual -> window will be placed by Top and Left property window.WindowStartupLocation = WindowStartupLocation.Manual; ComputeTopLeft(ref window); window.Show(); window.WindowStartupLocation = oldLocation; } #endregion #region Methods private static void ComputeTopLeft(ref Window window) { W32Point pt = new W32Point(); if (!GetCursorPos(ref pt)) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } // 0x00000002: return nearest monitor if pt is not contained in any monitor. IntPtr monHandle = MonitorFromPoint(pt, 0x00000002); W32MonitorInfo monInfo = new W32MonitorInfo(); monInfo.Size = Marshal.SizeOf(typeof(W32MonitorInfo)); if (!GetMonitorInfo(monHandle, ref monInfo)) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } // use WorkArea struct to include the taskbar position. W32Rect monitor = monInfo.WorkArea; double offsetX = Math.Round(window.Width / 2); double offsetY = Math.Round(window.Height / 2); double top = pt.Y - offsetY; double left = pt.X - offsetX; Rect screen = new Rect( new Point(monitor.Left, monitor.Top), new Point(monitor.Right, monitor.Bottom)); Rect wnd = new Rect( new Point(left, top), new Point(left + window.Width, top + window.Height)); window.Top = wnd.Top; window.Left = wnd.Left; if (!screen.Contains(wnd)) { if (wnd.Top < screen.Top) { double diff = Math.Abs(screen.Top - wnd.Top); window.Top = wnd.Top + diff; } if (wnd.Bottom > screen.Bottom) { double diff = wnd.Bottom - screen.Bottom; window.Top = wnd.Top - diff; } if (wnd.Left < screen.Left) { double diff = Math.Abs(screen.Left - wnd.Left); window.Left = wnd.Left + diff; } if (wnd.Right > screen.Right) { double diff = wnd.Right - screen.Right; window.Left = wnd.Left - diff; } } } #endregion #region W32 API [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetCursorPos(ref W32Point pt); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetMonitorInfo(IntPtr hMonitor, ref W32MonitorInfo lpmi); [DllImport("user32.dll")] private static extern IntPtr MonitorFromPoint(W32Point pt, uint dwFlags); [StructLayout(LayoutKind.Sequential)] public struct W32Point { public int X; public int Y; } [StructLayout(LayoutKind.Sequential)] internal struct W32MonitorInfo { public int Size; public W32Rect Monitor; public W32Rect WorkArea; public uint Flags; } [StructLayout(LayoutKind.Sequential)] internal struct W32Rect { public int Left; public int Top; public int Right; public int Bottom; } #endregion } }