From 0f7f9778c16d459a487dda0f476792991a92f816 Mon Sep 17 00:00:00 2001 From: "hemn.still" Date: Fri, 30 Jan 2015 15:16:24 +0400 Subject: [PATCH 1/2] Fix GetDeviceCoordinates. In some cases PresentationSource.FromVisual(this) may return null. --- .../NotifyIconWpf/Interop/SystemInfo.cs | 39 +++++++++++++++++++ .../Source/NotifyIconWpf/NotifyIconWpf.csproj | 1 + .../Source/NotifyIconWpf/TaskbarIcon.cs | 20 +--------- 3 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/Interop/SystemInfo.cs 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/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 884eedc..e59a5d5 100644 --- a/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/TaskbarIcon.cs +++ b/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/TaskbarIcon.cs @@ -962,25 +962,7 @@ namespace Hardcodet.Wpf.TaskbarNotification /// 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)}; + return new Point() { X = (int)(point.X / SystemInfo.DpiXFactor), Y = (int)(point.Y / SystemInfo.DpiYFactor) }; } #region Dispose / Exit From 111b48153ee2b8a473cafd8b7de6cdd1bd02ed07 Mon Sep 17 00:00:00 2001 From: "hemn.still" Date: Mon, 2 Feb 2015 18:45:16 +0400 Subject: [PATCH 2/2] GetTrayLocation now return with GetDeviceCoordinates. Fix in the case of multi-monitor. Add extension point CustomPopupPosition to show Balloon on custom position. AppBarInfo.WorkArea now return appbar workarea. Before it returns screen workarea. --- .../Source/NotifyIconWpf/Interop/TrayInfo.cs | 47 ++++++++++--------- .../Source/NotifyIconWpf/TaskbarIcon.cs | 25 +++++----- 2 files changed, 36 insertions(+), 36 deletions(-) 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/TaskbarIcon.cs b/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/TaskbarIcon.cs index e59a5d5..26af691 100644 --- a/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/TaskbarIcon.cs +++ b/Hardcodet.NotifyIcon.Wpf/Source/NotifyIconWpf/TaskbarIcon.cs @@ -145,6 +145,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. @@ -217,8 +225,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; @@ -394,7 +402,7 @@ namespace Hardcodet.Wpf.TaskbarNotification WinApi.GetCursorPos(ref cursorPosition); } - cursorPosition = GetDeviceCoordinates(cursorPosition); + cursorPosition = TrayInfo.GetDeviceCoordinates(cursorPosition); bool isLeftClickCommandInvoked = false; @@ -954,16 +962,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) - { - return new Point() { X = (int)(point.X / SystemInfo.DpiXFactor), Y = (int)(point.Y / SystemInfo.DpiYFactor) }; - } + #region Dispose / Exit