Merged in wezeku/notifyicon-wpf (pull request #2)

Added "NoLeftClickDelay" property for left clicks without delay.
This commit is contained in:
Philipp Sumi
2016-01-01 17:40:13 +01:00
5 changed files with 113 additions and 56 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.Drawing;
using System.Runtime.InteropServices;
using System.Windows;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
@@ -18,6 +19,7 @@ namespace Hardcodet.Wpf.TaskbarNotification.Interop
/// <returns>Tray coordinates.</returns>
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});
}
/// <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")]
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)
{

View File

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

View File

@@ -828,6 +828,33 @@ namespace Hardcodet.Wpf.TaskbarNotification
#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
#region TrayLeftMouseDown

View File

@@ -67,6 +67,14 @@ namespace Hardcodet.Wpf.TaskbarNotification
/// </summary>
private readonly Timer singleClickTimer;
/// <summary>
/// The time we should wait for a double click.
/// </summary>
private int doubleClickWaitTime
{
get { return NoLeftClickDelay ? 0 : WinApi.GetDoubleClickTime(); }
}
/// <summary>
/// A timer that is used to close open balloon tooltips.
/// </summary>
@@ -145,6 +153,14 @@ namespace Hardcodet.Wpf.TaskbarNotification
#endregion
#region Custom Balloons
public delegate Point GetCustomPopupPosition();
public GetCustomPopupPosition CustomPopupPosition;
public Point GetPopupTrayPosition()
{
return TrayInfo.GetTrayLocation();
}
/// <summary>
/// Shows a custom control as a tooltip in the tray location.
@@ -217,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;
@@ -394,7 +410,7 @@ namespace Hardcodet.Wpf.TaskbarNotification
WinApi.GetCursorPos(ref cursorPosition);
}
cursorPosition = GetDeviceCoordinates(cursorPosition);
cursorPosition = TrayInfo.GetDeviceCoordinates(cursorPosition);
bool isLeftClickCommandInvoked = false;
@@ -409,7 +425,7 @@ namespace Hardcodet.Wpf.TaskbarNotification
LeftClickCommand.ExecuteIfEnabled(LeftClickCommandParameter, LeftClickCommandTarget ?? this);
ShowTrayPopup(cursorPosition);
};
singleClickTimer.Change(WinApi.GetDoubleClickTime(), Timeout.Infinite);
singleClickTimer.Change(doubleClickWaitTime, Timeout.Infinite);
isLeftClickCommandInvoked = true;
}
else
@@ -431,7 +447,7 @@ namespace Hardcodet.Wpf.TaskbarNotification
LeftClickCommand.ExecuteIfEnabled(LeftClickCommandParameter, LeftClickCommandTarget ?? this);
ShowContextMenu(cursorPosition);
};
singleClickTimer.Change(WinApi.GetDoubleClickTime(), Timeout.Infinite);
singleClickTimer.Change(doubleClickWaitTime, Timeout.Infinite);
isLeftClickCommandInvoked = true;
}
else
@@ -450,7 +466,7 @@ namespace Hardcodet.Wpf.TaskbarNotification
{
LeftClickCommand.ExecuteIfEnabled(LeftClickCommandParameter, LeftClickCommandTarget ?? this);
};
singleClickTimer.Change(WinApi.GetDoubleClickTime(), Timeout.Infinite);
singleClickTimer.Change(doubleClickWaitTime, Timeout.Infinite);
}
}
@@ -954,34 +970,7 @@ namespace Hardcodet.Wpf.TaskbarNotification
#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