Updating branch with imported PR from master.

This commit is contained in:
Philipp Sumi
2016-01-01 23:10:00 +01:00
5 changed files with 121 additions and 59 deletions

View File

@@ -0,0 +1,39 @@
using System;
using System.Windows.Interop;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
public static class SystemInfo
{
private static Tuple<double, double> dpiFactors;
private static Tuple<double, double> 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;
}
}
}
}

View File

@@ -3,6 +3,7 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Windows;
namespace Hardcodet.Wpf.TaskbarNotification.Interop namespace Hardcodet.Wpf.TaskbarNotification.Interop
@@ -18,6 +19,7 @@ namespace Hardcodet.Wpf.TaskbarNotification.Interop
/// <returns>Tray coordinates.</returns> /// <returns>Tray coordinates.</returns>
public static Point GetTrayLocation() public static Point GetTrayLocation()
{ {
int space = 2;
var info = new AppBarInfo(); var info = new AppBarInfo();
info.GetSystemTaskBarPosition(); info.GetSystemTaskBarPosition();
@@ -26,31 +28,42 @@ namespace Hardcodet.Wpf.TaskbarNotification.Interop
int x = 0, y = 0; int x = 0, y = 0;
if (info.Edge == AppBarInfo.ScreenEdge.Left) if (info.Edge == AppBarInfo.ScreenEdge.Left)
{ {
x = rcWorkArea.Left + 2; x = rcWorkArea.Right + space;
y = rcWorkArea.Bottom; y = rcWorkArea.Bottom;
} }
else if (info.Edge == AppBarInfo.ScreenEdge.Bottom) else if (info.Edge == AppBarInfo.ScreenEdge.Bottom)
{ {
x = rcWorkArea.Right; x = rcWorkArea.Right;
y = rcWorkArea.Bottom; y = rcWorkArea.Bottom - rcWorkArea.Height - space;
} }
else if (info.Edge == AppBarInfo.ScreenEdge.Top) else if (info.Edge == AppBarInfo.ScreenEdge.Top)
{ {
x = rcWorkArea.Right; x = rcWorkArea.Right;
y = rcWorkArea.Top; y = rcWorkArea.Top + rcWorkArea.Height + space;
} }
else if (info.Edge == AppBarInfo.ScreenEdge.Right) else if (info.Edge == AppBarInfo.ScreenEdge.Right)
{ {
x = rcWorkArea.Right; x = rcWorkArea.Right - rcWorkArea.Width - space;
y = rcWorkArea.Bottom; y = rcWorkArea.Bottom;
} }
return new Point {X = x, Y = y}; return GetDeviceCoordinates(new Point {X = x, Y = y});
}
/// <summary>
/// Recalculates OS coordinates in order to support WPFs coordinate
/// system if OS scaling (DPIs) is not 100%.
/// </summary>
/// <param name="point"></param>
/// <returns></returns>
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")] [DllImport("user32.dll")]
private static extern IntPtr FindWindow(String lpClassName, String lpWindowName); private static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
@@ -80,27 +93,15 @@ namespace Hardcodet.Wpf.TaskbarNotification.Interop
get { return (ScreenEdge) m_data.uEdge; } get { return (ScreenEdge) m_data.uEdge; }
} }
public Rectangle WorkArea public Rectangle WorkArea
{ {
get get { return GetRectangle(m_data.rc); }
{
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);
}
} }
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) public void GetPosition(string strClassName, string strWindowName)
{ {

View File

@@ -47,6 +47,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="BalloonIcon.cs" /> <Compile Include="BalloonIcon.cs" />
<Compile Include="Interop\SystemInfo.cs" />
<Compile Include="Interop\TrayInfo.cs"> <Compile Include="Interop\TrayInfo.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>

View File

@@ -861,6 +861,33 @@ namespace Hardcodet.Wpf.TaskbarNotification
#endregion #endregion
#region NoLeftClickDelay dependency property
/// <summary>
/// Set to true to make left clicks work without delay.
/// </summary>
public static readonly DependencyProperty NoLeftClickDelayProperty =
DependencyProperty.Register("NoLeftClickDelay",
typeof(bool),
typeof(TaskbarIcon),
new FrameworkPropertyMetadata(false));
/// <summary>
/// A property wrapper for the <see cref="NoLeftClickDelayProperty"/>
/// dependency property:<br/>
/// Set to true to make left clicks work without delay.
/// </summary>
[Category(CategoryName)]
[Description("Set to true to make left clicks work without delay.")]
public bool NoLeftClickDelay
{
get { return (bool)GetValue(NoLeftClickDelayProperty); }
set { SetValue(NoLeftClickDelayProperty, value); }
}
#endregion
//EVENTS //EVENTS
#region TrayLeftMouseDown #region TrayLeftMouseDown

View File

@@ -70,9 +70,17 @@ namespace Hardcodet.Wpf.TaskbarNotification
/// <summary> /// <summary>
/// Maintains opened tooltip popups. /// Maintains opened tooltip popups.
/// The time we should wait for a double click.
/// </summary> /// </summary>
private ToolTipObserver toolTipObserver; private ToolTipObserver toolTipObserver;
/// <summary>
/// </summary>
private int doubleClickWaitTime
{
get { return NoLeftClickDelay ? 0 : WinApi.GetDoubleClickTime(); }
}
/// <summary> /// <summary>
/// A timer that is used to close open balloon tooltips. /// A timer that is used to close open balloon tooltips.
/// </summary> /// </summary>
@@ -151,6 +159,14 @@ namespace Hardcodet.Wpf.TaskbarNotification
#endregion #endregion
#region Custom Balloons #region Custom Balloons
public delegate Point GetCustomPopupPosition();
public GetCustomPopupPosition CustomPopupPosition;
public Point GetPopupTrayPosition()
{
return TrayInfo.GetTrayLocation();
}
/// <summary> /// <summary>
/// Shows a custom control as a tooltip in the tray location. /// Shows a custom control as a tooltip in the tray location.
@@ -223,8 +239,8 @@ namespace Hardcodet.Wpf.TaskbarNotification
popup.Placement = PlacementMode.AbsolutePoint; popup.Placement = PlacementMode.AbsolutePoint;
popup.StaysOpen = true; 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.HorizontalOffset = position.X - 1;
popup.VerticalOffset = position.Y - 1; popup.VerticalOffset = position.Y - 1;
@@ -400,7 +416,7 @@ namespace Hardcodet.Wpf.TaskbarNotification
WinApi.GetCursorPos(ref cursorPosition); WinApi.GetCursorPos(ref cursorPosition);
} }
cursorPosition = GetDeviceCoordinates(cursorPosition); cursorPosition = TrayInfo.GetDeviceCoordinates(cursorPosition);
bool isLeftClickCommandInvoked = false; bool isLeftClickCommandInvoked = false;
@@ -415,7 +431,7 @@ namespace Hardcodet.Wpf.TaskbarNotification
LeftClickCommand.ExecuteIfEnabled(LeftClickCommandParameter, LeftClickCommandTarget ?? this); LeftClickCommand.ExecuteIfEnabled(LeftClickCommandParameter, LeftClickCommandTarget ?? this);
ShowTrayPopup(cursorPosition); ShowTrayPopup(cursorPosition);
}; };
singleClickTimer.Change(WinApi.GetDoubleClickTime(), Timeout.Infinite); singleClickTimer.Change(doubleClickWaitTime, Timeout.Infinite);
isLeftClickCommandInvoked = true; isLeftClickCommandInvoked = true;
} }
else else
@@ -437,7 +453,7 @@ namespace Hardcodet.Wpf.TaskbarNotification
LeftClickCommand.ExecuteIfEnabled(LeftClickCommandParameter, LeftClickCommandTarget ?? this); LeftClickCommand.ExecuteIfEnabled(LeftClickCommandParameter, LeftClickCommandTarget ?? this);
ShowContextMenu(cursorPosition); ShowContextMenu(cursorPosition);
}; };
singleClickTimer.Change(WinApi.GetDoubleClickTime(), Timeout.Infinite); singleClickTimer.Change(doubleClickWaitTime, Timeout.Infinite);
isLeftClickCommandInvoked = true; isLeftClickCommandInvoked = true;
} }
else else
@@ -456,7 +472,7 @@ namespace Hardcodet.Wpf.TaskbarNotification
{ {
LeftClickCommand.ExecuteIfEnabled(LeftClickCommandParameter, LeftClickCommandTarget ?? this); LeftClickCommand.ExecuteIfEnabled(LeftClickCommandParameter, LeftClickCommandTarget ?? this);
}; };
singleClickTimer.Change(WinApi.GetDoubleClickTime(), Timeout.Infinite); singleClickTimer.Change(doubleClickWaitTime, Timeout.Infinite);
} }
} }
@@ -820,7 +836,6 @@ namespace Hardcodet.Wpf.TaskbarNotification
} }
} }
/// <summary> /// <summary>
/// Displays a balloon tip with the specified title, /// Displays a balloon tip with the specified title,
/// text, and a custom icon in the taskbar for the specified time period. /// text, and a custom icon in the taskbar for the specified time period.
@@ -828,15 +843,21 @@ namespace Hardcodet.Wpf.TaskbarNotification
/// <param name="title">The title to display on the balloon tip.</param> /// <param name="title">The title to display on the balloon tip.</param>
/// <param name="message">The text to display on the balloon tip.</param> /// <param name="message">The text to display on the balloon tip.</param>
/// <param name="customIcon">A custom icon.</param> /// <param name="customIcon">A custom icon.</param>
/// <param name="largeIcon">True to allow large icons (Windows Vista and later).</param>
/// <exception cref="ArgumentNullException">If <paramref name="customIcon"/> /// <exception cref="ArgumentNullException">If <paramref name="customIcon"/>
/// is a null reference.</exception> /// is a null reference.</exception>
public void ShowBalloonTip(string title, string message, Icon customIcon) public void ShowBalloonTip(string title, string message, Icon customIcon, bool largeIcon = false)
{ {
if (customIcon == null) throw new ArgumentNullException("customIcon"); if (customIcon == null) throw new ArgumentNullException("customIcon");
lock (this) lock (this)
{ {
ShowBalloonTip(title, message, BalloonFlags.User, customIcon.Handle); var flags = BalloonFlags.User;
if (largeIcon)
flags |= BalloonFlags.LargeIcon;
ShowBalloonTip(title, message, flags, customIcon.Handle);
} }
} }
@@ -998,34 +1019,7 @@ namespace Hardcodet.Wpf.TaskbarNotification
#endregion #endregion
/// <summary>
/// Recalculates OS coordinates in order to support WPFs coordinate
/// system if OS scaling (DPIs) is not 100%.
/// </summary>
/// <param name="point"></param>
/// <returns></returns>
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 #region Dispose / Exit