|
|
|
@ -6,93 +6,12 @@ using System.Runtime.InteropServices; |
|
|
|
using Avalonia.Controls; |
|
|
|
using Avalonia.Controls.Primitives.PopupPositioning; |
|
|
|
using Avalonia.Platform; |
|
|
|
using Avalonia.Threading; |
|
|
|
using Avalonia.Win32.Interop; |
|
|
|
using static Avalonia.Win32.Interop.UnmanagedMethods; |
|
|
|
|
|
|
|
namespace Avalonia.Win32 |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
/// Custom Win32 window messages for the NotifyIcon
|
|
|
|
/// </summary>
|
|
|
|
public enum CustomWindowsMessage : uint |
|
|
|
{ |
|
|
|
WM_TRAYICON = WindowsMessage.WM_APP + 1024, |
|
|
|
WM_TRAYMOUSE = WindowsMessage.WM_USER + 1024 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
public class TrayIconManagedPopupPositionerPopupImplHelper : IManagedPopupPositionerPopup |
|
|
|
{ |
|
|
|
public delegate void MoveResizeDelegate(PixelPoint position, Size size, double scaling); |
|
|
|
private readonly MoveResizeDelegate _moveResize; |
|
|
|
private Window _hiddenWindow; |
|
|
|
|
|
|
|
public TrayIconManagedPopupPositionerPopupImplHelper(MoveResizeDelegate moveResize) |
|
|
|
{ |
|
|
|
_moveResize = moveResize; |
|
|
|
_hiddenWindow = new Window(); |
|
|
|
} |
|
|
|
|
|
|
|
public IReadOnlyList<ManagedPopupPositionerScreenInfo> Screens => |
|
|
|
_hiddenWindow.Screens.All.Select(s => new ManagedPopupPositionerScreenInfo( |
|
|
|
s.Bounds.ToRect(1), s.Bounds.ToRect(1))).ToList(); |
|
|
|
|
|
|
|
public Rect ParentClientAreaScreenGeometry |
|
|
|
{ |
|
|
|
get |
|
|
|
{ |
|
|
|
var point = _hiddenWindow.Screens.Primary.Bounds.TopLeft; |
|
|
|
var size = _hiddenWindow.Screens.Primary.Bounds.Size; |
|
|
|
return new Rect(point.X, point.Y, size.Width * _hiddenWindow.Screens.Primary.PixelDensity, size.Height * _hiddenWindow.Screens.Primary.PixelDensity); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void MoveAndResize(Point devicePoint, Size virtualSize) |
|
|
|
{ |
|
|
|
_moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _hiddenWindow.Screens.Primary.PixelDensity); |
|
|
|
} |
|
|
|
|
|
|
|
public virtual double Scaling => _hiddenWindow.Screens.Primary.PixelDensity; |
|
|
|
} |
|
|
|
|
|
|
|
public class TrayPopupRoot : Window |
|
|
|
{ |
|
|
|
private ManagedPopupPositioner _positioner; |
|
|
|
|
|
|
|
public TrayPopupRoot() |
|
|
|
{ |
|
|
|
_positioner = new ManagedPopupPositioner(new TrayIconManagedPopupPositionerPopupImplHelper(MoveResize)); |
|
|
|
Topmost = true; |
|
|
|
|
|
|
|
LostFocus += TrayPopupRoot_LostFocus; |
|
|
|
} |
|
|
|
|
|
|
|
private void MoveResize(PixelPoint position, Size size, double scaling) |
|
|
|
{ |
|
|
|
PlatformImpl.Move(position); |
|
|
|
PlatformImpl.Resize(size, PlatformResizeReason.Layout); |
|
|
|
} |
|
|
|
|
|
|
|
private void TrayPopupRoot_LostFocus(object sender, Interactivity.RoutedEventArgs e) |
|
|
|
{ |
|
|
|
Close(); |
|
|
|
} |
|
|
|
|
|
|
|
protected override void ArrangeCore(Rect finalRect) |
|
|
|
{ |
|
|
|
base.ArrangeCore(finalRect); |
|
|
|
|
|
|
|
_positioner.Update(new PopupPositionerParameters |
|
|
|
{ |
|
|
|
Anchor = PopupAnchor.TopLeft, |
|
|
|
Gravity = PopupGravity.BottomRight, |
|
|
|
AnchorRectangle = new Rect(Position.ToPoint(1) / Screens.Primary.PixelDensity, new Size(1, 1)), |
|
|
|
Size = finalRect.Size, |
|
|
|
ConstraintAdjustment = PopupPositionerConstraintAdjustment.FlipX | PopupPositionerConstraintAdjustment.FlipY, |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public class TrayIconImpl : ITrayIconImpl |
|
|
|
{ |
|
|
|
private readonly int _uniqueId = 0; |
|
|
|
@ -163,7 +82,14 @@ namespace Avalonia.Win32 |
|
|
|
{ |
|
|
|
throw new NotImplementedException(); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Custom Win32 window messages for the NotifyIcon
|
|
|
|
/// </summary>
|
|
|
|
public enum CustomWindowsMessage : uint |
|
|
|
{ |
|
|
|
WM_TRAYICON = WindowsMessage.WM_APP + 1024, |
|
|
|
WM_TRAYMOUSE = WindowsMessage.WM_USER + 1024 |
|
|
|
} |
|
|
|
private void UpdateIcon(bool remove = false) |
|
|
|
{ |
|
|
|
var iconData = new NOTIFYICONDATA() |
|
|
|
@ -210,8 +136,6 @@ namespace Avalonia.Win32 |
|
|
|
// Click?.Invoke(this, new EventArgs());
|
|
|
|
//}
|
|
|
|
//_doubleClick = false;
|
|
|
|
|
|
|
|
Debug.WriteLine($"Clicked {lParam:X}"); |
|
|
|
break; |
|
|
|
|
|
|
|
case (int)WindowsMessage.WM_LBUTTONDBLCLK: |
|
|
|
@ -226,9 +150,13 @@ namespace Avalonia.Win32 |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return DefWindowProc(hWnd, msg, wParam, lParam); |
|
|
|
return IntPtr.Zero; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
return DefWindowProc(hWnd, msg, wParam, lParam); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static void OnRightClicked() |
|
|
|
@ -258,5 +186,85 @@ namespace Avalonia.Win32 |
|
|
|
|
|
|
|
_trayMenu.Show(); |
|
|
|
} |
|
|
|
|
|
|
|
class TrayPopupRoot : Window |
|
|
|
{ |
|
|
|
private ManagedPopupPositioner _positioner; |
|
|
|
|
|
|
|
public TrayPopupRoot() |
|
|
|
{ |
|
|
|
_positioner = new ManagedPopupPositioner(new TrayIconManagedPopupPositionerPopupImplHelper(MoveResize)); |
|
|
|
Topmost = true; |
|
|
|
|
|
|
|
Deactivated += TrayPopupRoot_Deactivated; |
|
|
|
} |
|
|
|
|
|
|
|
private void TrayPopupRoot_Deactivated(object sender, EventArgs e) |
|
|
|
{ |
|
|
|
Dispatcher.UIThread.Post(() => |
|
|
|
{ |
|
|
|
Close(); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
private void MoveResize(PixelPoint position, Size size, double scaling) |
|
|
|
{ |
|
|
|
PlatformImpl.Move(position); |
|
|
|
PlatformImpl.Resize(size, PlatformResizeReason.Layout); |
|
|
|
} |
|
|
|
|
|
|
|
private void TrayPopupRoot_LostFocus(object sender, Interactivity.RoutedEventArgs e) |
|
|
|
{ |
|
|
|
Close(); |
|
|
|
} |
|
|
|
|
|
|
|
protected override void ArrangeCore(Rect finalRect) |
|
|
|
{ |
|
|
|
base.ArrangeCore(finalRect); |
|
|
|
|
|
|
|
_positioner.Update(new PopupPositionerParameters |
|
|
|
{ |
|
|
|
Anchor = PopupAnchor.TopLeft, |
|
|
|
Gravity = PopupGravity.BottomRight, |
|
|
|
AnchorRectangle = new Rect(Position.ToPoint(1) / Screens.Primary.PixelDensity, new Size(1, 1)), |
|
|
|
Size = finalRect.Size, |
|
|
|
ConstraintAdjustment = PopupPositionerConstraintAdjustment.FlipX | PopupPositionerConstraintAdjustment.FlipY, |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
class TrayIconManagedPopupPositionerPopupImplHelper : IManagedPopupPositionerPopup |
|
|
|
{ |
|
|
|
public delegate void MoveResizeDelegate(PixelPoint position, Size size, double scaling); |
|
|
|
private readonly MoveResizeDelegate _moveResize; |
|
|
|
private Window _hiddenWindow; |
|
|
|
|
|
|
|
public TrayIconManagedPopupPositionerPopupImplHelper(MoveResizeDelegate moveResize) |
|
|
|
{ |
|
|
|
_moveResize = moveResize; |
|
|
|
_hiddenWindow = new Window(); |
|
|
|
} |
|
|
|
|
|
|
|
public IReadOnlyList<ManagedPopupPositionerScreenInfo> Screens => |
|
|
|
_hiddenWindow.Screens.All.Select(s => new ManagedPopupPositionerScreenInfo( |
|
|
|
s.Bounds.ToRect(1), s.Bounds.ToRect(1))).ToList(); |
|
|
|
|
|
|
|
public Rect ParentClientAreaScreenGeometry |
|
|
|
{ |
|
|
|
get |
|
|
|
{ |
|
|
|
var point = _hiddenWindow.Screens.Primary.Bounds.TopLeft; |
|
|
|
var size = _hiddenWindow.Screens.Primary.Bounds.Size; |
|
|
|
return new Rect(point.X, point.Y, size.Width * _hiddenWindow.Screens.Primary.PixelDensity, size.Height * _hiddenWindow.Screens.Primary.PixelDensity); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void MoveAndResize(Point devicePoint, Size virtualSize) |
|
|
|
{ |
|
|
|
_moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _hiddenWindow.Screens.Primary.PixelDensity); |
|
|
|
} |
|
|
|
|
|
|
|
public virtual double Scaling => _hiddenWindow.Screens.Primary.PixelDensity; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|