From abf4242280b71160ec7845f42a051b87b0534927 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 10 Sep 2021 12:08:54 +0100 Subject: [PATCH] support trayicon clicked on osx. --- .../Platform/ITrayIconImpl.cs | 8 +++ src/Avalonia.Controls/TrayIcon.cs | 60 ++++++++++++------- .../Remote/TrayIconStub.cs | 4 +- src/Avalonia.Native/TrayIconImpl.cs | 6 +- src/Windows/Avalonia.Win32/TrayIconImpl.cs | 36 ++++++----- 5 files changed, 71 insertions(+), 43 deletions(-) diff --git a/src/Avalonia.Controls/Platform/ITrayIconImpl.cs b/src/Avalonia.Controls/Platform/ITrayIconImpl.cs index 013aff13ee..12a32ec64b 100644 --- a/src/Avalonia.Controls/Platform/ITrayIconImpl.cs +++ b/src/Avalonia.Controls/Platform/ITrayIconImpl.cs @@ -23,6 +23,14 @@ namespace Avalonia.Platform /// void SetIsVisible (bool visible); + /// + /// Gets the MenuExporter to allow native menus to be exported to the TrayIcon. + /// INativeMenuExporter? MenuExporter { get; } + + /// + /// Gets or Sets the Action that is called when the TrayIcon is clicked. + /// + Action? OnClicked { get; set; } } } diff --git a/src/Avalonia.Controls/TrayIcon.cs b/src/Avalonia.Controls/TrayIcon.cs index cfff568a4a..4d86f9ddc1 100644 --- a/src/Avalonia.Controls/TrayIcon.cs +++ b/src/Avalonia.Controls/TrayIcon.cs @@ -22,6 +22,15 @@ namespace Avalonia.Controls _impl = impl; _impl.SetIsVisible(IsVisible); + + _impl.OnClicked = () => Clicked?.Invoke(this, EventArgs.Empty); + + Clicked += TrayIcon_Clicked; + } + + private void TrayIcon_Clicked(object sender, EventArgs e) + { + } public TrayIcon () : this(PlatformManager.CreateTrayIcon()) @@ -52,28 +61,12 @@ namespace Avalonia.Controls } } - private static void Lifetime_Exit(object sender, ControlledApplicationLifetimeExitEventArgs e) - { - var trayIcons = GetTrayIcons(Application.Current); - - foreach(var icon in trayIcons) - { - icon.Dispose(); - } - } - - private static void Icons_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) - { - - } - - private static void RemoveIcons (IEnumerable icons) - { - foreach(var icon in icons) - { - icon.Dispose(); - } - } + /// + /// Raised when the TrayIcon is clicked. + /// Note, this is only supported on Win32. + /// Linux and OSX this event is not raised. + /// + public event EventHandler? Clicked; /// /// Defines the attached property. @@ -132,6 +125,29 @@ namespace Avalonia.Controls public INativeMenuExporter? NativeMenuExporter => _impl.MenuExporter; + private static void Lifetime_Exit(object sender, ControlledApplicationLifetimeExitEventArgs e) + { + var trayIcons = GetTrayIcons(Application.Current); + + foreach (var icon in trayIcons) + { + icon.Dispose(); + } + } + + private static void Icons_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + + } + + private static void RemoveIcons(IEnumerable icons) + { + foreach (var icon in icons) + { + icon.Dispose(); + } + } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); diff --git a/src/Avalonia.DesignerSupport/Remote/TrayIconStub.cs b/src/Avalonia.DesignerSupport/Remote/TrayIconStub.cs index 6fd70f203c..88ca076f8a 100644 --- a/src/Avalonia.DesignerSupport/Remote/TrayIconStub.cs +++ b/src/Avalonia.DesignerSupport/Remote/TrayIconStub.cs @@ -11,7 +11,9 @@ namespace Avalonia.DesignerSupport.Remote public Action DoubleClicked { get; set; } public Action RightClicked { get; set; } - public INativeMenuExporter MenuExporter => throw new NotImplementedException(); + public INativeMenuExporter MenuExporter => null; + + public Action OnClicked { get; set; } public void Dispose() { diff --git a/src/Avalonia.Native/TrayIconImpl.cs b/src/Avalonia.Native/TrayIconImpl.cs index b5cb0d8c08..7e2ade901c 100644 --- a/src/Avalonia.Native/TrayIconImpl.cs +++ b/src/Avalonia.Native/TrayIconImpl.cs @@ -4,6 +4,8 @@ using Avalonia.Controls.Platform; using Avalonia.Native.Interop; using Avalonia.Platform; +#nullable enable + namespace Avalonia.Native { class TrayIconEvents : CallbackBase, IAvnTrayIconEvents @@ -34,7 +36,9 @@ namespace Avalonia.Native MenuExporter = new AvaloniaNativeMenuExporter(_native, factory); } - + + public Action? OnClicked { get; set; } + public void Dispose() { diff --git a/src/Windows/Avalonia.Win32/TrayIconImpl.cs b/src/Windows/Avalonia.Win32/TrayIconImpl.cs index c1286f8436..ba208a4b74 100644 --- a/src/Windows/Avalonia.Win32/TrayIconImpl.cs +++ b/src/Windows/Avalonia.Win32/TrayIconImpl.cs @@ -23,10 +23,20 @@ namespace Avalonia.Win32 private IconImpl? _icon; private string? _tooltipText; private readonly Win32NativeToManagedMenuExporter _exporter; - private static Dictionary s_trayIcons = new Dictionary(); private bool _disposedValue; + public TrayIconImpl() + { + _exporter = new Win32NativeToManagedMenuExporter(); + + _uniqueId = ++_nextUniqueId; + + s_trayIcons.Add(_uniqueId, this); + } + + public Action? OnClicked { get; set; } + public INativeMenuExporter MenuExporter => _exporter; internal static void ProcWnd(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) @@ -37,15 +47,6 @@ namespace Avalonia.Win32 } } - public TrayIconImpl() - { - _exporter = new Win32NativeToManagedMenuExporter(); - - _uniqueId = ++_nextUniqueId; - - s_trayIcons.Add(_uniqueId, this); - } - public void SetIcon(IWindowIconImpl? icon) { _icon = icon as IconImpl; @@ -63,7 +64,6 @@ namespace Avalonia.Win32 UpdateIcon(!_iconAdded); } - private void UpdateIcon(bool remove = false) { var iconData = new NOTIFYICONDATA() @@ -105,9 +105,7 @@ namespace Avalonia.Win32 switch (lParam.ToInt32()) { case (int)WindowsMessage.WM_LBUTTONUP: - break; - - case (int)WindowsMessage.WM_LBUTTONDBLCLK: + OnClicked?.Invoke(); break; case (int)WindowsMessage.WM_RBUTTONUP: @@ -264,11 +262,11 @@ namespace Avalonia.Win32 } } - ~TrayIconImpl() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: false); - } + ~TrayIconImpl() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: false); + } public void Dispose() {