diff --git a/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/Interop/SystemInfo.cs b/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/Interop/SystemInfo.cs new file mode 100644 index 0000000..8274196 --- /dev/null +++ b/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/Interop/SystemInfo.cs @@ -0,0 +1,39 @@ +using System; +using System.Windows.Interop; + +namespace Hardcodet.Wpf.TaskbarNotification.Interop +{ + public static class SystemInfo + { + private static Tuple dpiFactors; + + private static Tuple DpiFactors + { + get + { + if (dpiFactors == null) + using (var source = new HwndSource(new HwndSourceParameters())) + dpiFactors = Tuple.Create(source.CompositionTarget.TransformToDevice.M11, source.CompositionTarget.TransformToDevice.M22); + return dpiFactors; + } + } + + public static double DpiXFactor + { + get + { + var factors = DpiFactors; + return factors != null ? factors.Item1 : 1; + } + } + + public static double DpiYFactor + { + get + { + var factors = DpiFactors; + return factors != null ? factors.Item2 : 1; + } + } + } +} diff --git a/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/Interop/TrayInfo.cs b/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/Interop/TrayInfo.cs index 468a833..1516e1c 100644 --- a/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/Interop/TrayInfo.cs +++ b/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/Interop/TrayInfo.cs @@ -3,6 +3,7 @@ using System; using System.Drawing; using System.Runtime.InteropServices; +using System.Windows; namespace Hardcodet.Wpf.TaskbarNotification.Interop @@ -18,6 +19,7 @@ namespace Hardcodet.Wpf.TaskbarNotification.Interop /// Tray coordinates. public static Point GetTrayLocation() { + int space = 2; var info = new AppBarInfo(); info.GetSystemTaskBarPosition(); @@ -26,31 +28,42 @@ namespace Hardcodet.Wpf.TaskbarNotification.Interop int x = 0, y = 0; if (info.Edge == AppBarInfo.ScreenEdge.Left) { - x = rcWorkArea.Left + 2; + x = rcWorkArea.Right + space; y = rcWorkArea.Bottom; } else if (info.Edge == AppBarInfo.ScreenEdge.Bottom) { x = rcWorkArea.Right; - y = rcWorkArea.Bottom; + y = rcWorkArea.Bottom - rcWorkArea.Height - space; } else if (info.Edge == AppBarInfo.ScreenEdge.Top) { x = rcWorkArea.Right; - y = rcWorkArea.Top; + y = rcWorkArea.Top + rcWorkArea.Height + space; } else if (info.Edge == AppBarInfo.ScreenEdge.Right) { - x = rcWorkArea.Right; + x = rcWorkArea.Right - rcWorkArea.Width - space; y = rcWorkArea.Bottom; } - return new Point {X = x, Y = y}; + return GetDeviceCoordinates(new Point {X = x, Y = y}); + } + + /// + /// Recalculates OS coordinates in order to support WPFs coordinate + /// system if OS scaling (DPIs) is not 100%. + /// + /// + /// + public static Point GetDeviceCoordinates(Point point) + { + return new Point() { X = (int)(point.X / SystemInfo.DpiXFactor), Y = (int)(point.Y / SystemInfo.DpiYFactor) }; } } - internal class AppBarInfo + public class AppBarInfo { [DllImport("user32.dll")] private static extern IntPtr FindWindow(String lpClassName, String lpWindowName); @@ -80,27 +93,15 @@ namespace Hardcodet.Wpf.TaskbarNotification.Interop get { return (ScreenEdge) m_data.uEdge; } } - public Rectangle WorkArea { - get - { - Int32 bResult = 0; - var rc = new RECT(); - IntPtr rawRect = Marshal.AllocHGlobal(Marshal.SizeOf(rc)); - bResult = SystemParametersInfo(SPI_GETWORKAREA, 0, rawRect, 0); - rc = (RECT) Marshal.PtrToStructure(rawRect, rc.GetType()); - - if (bResult == 1) - { - Marshal.FreeHGlobal(rawRect); - return new Rectangle(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); - } - - return new Rectangle(0, 0, 0, 0); - } + get { return GetRectangle(m_data.rc); } } + private Rectangle GetRectangle(RECT rc) + { + return new Rectangle(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); + } public void GetPosition(string strClassName, string strWindowName) { diff --git a/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/NotifyIconWpf.csproj b/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/NotifyIconWpf.csproj index 981fc5e..4e7a2af 100644 --- a/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/NotifyIconWpf.csproj +++ b/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/NotifyIconWpf.csproj @@ -47,6 +47,7 @@ + Code diff --git a/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/TaskbarIcon.cs b/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/TaskbarIcon.cs index f24b65c..acd23fa 100644 --- a/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/TaskbarIcon.cs +++ b/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/TaskbarIcon.cs @@ -153,6 +153,14 @@ namespace Hardcodet.Wpf.TaskbarNotification #endregion #region Custom Balloons + public delegate Point GetCustomPopupPosition(); + + public GetCustomPopupPosition CustomPopupPosition; + + public Point GetPopupTrayPosition() + { + return TrayInfo.GetTrayLocation(); + } /// /// Shows a custom control as a tooltip in the tray location. @@ -225,8 +233,8 @@ namespace Hardcodet.Wpf.TaskbarNotification popup.Placement = PlacementMode.AbsolutePoint; popup.StaysOpen = true; - Point position = TrayInfo.GetTrayLocation(); - position = GetDeviceCoordinates(position); + + Point position = this.CustomPopupPosition != null ? this.CustomPopupPosition() : this.GetPopupTrayPosition(); popup.HorizontalOffset = position.X - 1; popup.VerticalOffset = position.Y - 1; @@ -402,7 +410,7 @@ namespace Hardcodet.Wpf.TaskbarNotification WinApi.GetCursorPos(ref cursorPosition); } - cursorPosition = GetDeviceCoordinates(cursorPosition); + cursorPosition = TrayInfo.GetDeviceCoordinates(cursorPosition); bool isLeftClickCommandInvoked = false; @@ -962,34 +970,7 @@ namespace Hardcodet.Wpf.TaskbarNotification #endregion - /// - /// Recalculates OS coordinates in order to support WPFs coordinate - /// system if OS scaling (DPIs) is not 100%. - /// - /// - /// - private Point GetDeviceCoordinates(Point point) - { - if (double.IsNaN(scalingFactor)) - { - //calculate scaling factor in order to support non-standard DPIs - var presentationSource = PresentationSource.FromVisual(this); - if (presentationSource == null) - { - scalingFactor = 1; - } - else - { - var transform = presentationSource.CompositionTarget.TransformToDevice; - scalingFactor = 1/transform.M11; - } - } - //on standard DPI settings, just return the point - if (scalingFactor == 1.0) return point; - - return new Point() {X = (int) (point.X*scalingFactor), Y = (int) (point.Y*scalingFactor)}; - } #region Dispose / Exit