diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 2200421..f76bdb5 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -21,5 +21,6 @@ jobs: /target:libs\H_NotifyIcon_Uno_WinUI /target:libs\H_NotifyIcon_WinUI /target:libs\H_NotifyIcon_Wpf + /target:libs\H_NotifyIcon_Maui secrets: nuget-key: ${{ secrets.NUGET_KEY }} diff --git a/H.NotifyIcon.sln b/H.NotifyIcon.sln index 194200d..e171c55 100644 --- a/H.NotifyIcon.sln +++ b/H.NotifyIcon.sln @@ -61,6 +61,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "H.GeneratedIcons.System.Dra EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "H.GeneratedIcons.SkiaSharp", "src\libs\H.GeneratedIcons.SkiaSharp\H.GeneratedIcons.SkiaSharp.csproj", "{EECF393D-0F55-4BFE-AEA8-7FD90383C05D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "H.NotifyIcon.Maui", "src\libs\H.NotifyIcon.Maui\H.NotifyIcon.Maui.csproj", "{84E993AA-5343-4502-9612-B9A416AF243F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "H.NotifyIcon.Apps.Maui", "src\apps\H.NotifyIcon.Apps.Maui\H.NotifyIcon.Apps.Maui.csproj", "{6C5EA367-5663-420E-B10C-8E5543EBF8DD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -329,6 +333,38 @@ Global {EECF393D-0F55-4BFE-AEA8-7FD90383C05D}.Release|x64.Build.0 = Release|Any CPU {EECF393D-0F55-4BFE-AEA8-7FD90383C05D}.Release|x86.ActiveCfg = Release|Any CPU {EECF393D-0F55-4BFE-AEA8-7FD90383C05D}.Release|x86.Build.0 = Release|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Debug|arm64.ActiveCfg = Debug|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Debug|arm64.Build.0 = Debug|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Debug|x64.ActiveCfg = Debug|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Debug|x64.Build.0 = Debug|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Debug|x86.ActiveCfg = Debug|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Debug|x86.Build.0 = Debug|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Release|Any CPU.Build.0 = Release|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Release|arm64.ActiveCfg = Release|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Release|arm64.Build.0 = Release|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Release|x64.ActiveCfg = Release|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Release|x64.Build.0 = Release|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Release|x86.ActiveCfg = Release|Any CPU + {84E993AA-5343-4502-9612-B9A416AF243F}.Release|x86.Build.0 = Release|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Debug|arm64.ActiveCfg = Debug|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Debug|arm64.Build.0 = Debug|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Debug|x64.ActiveCfg = Debug|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Debug|x64.Build.0 = Debug|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Debug|x86.ActiveCfg = Debug|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Debug|x86.Build.0 = Debug|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Release|Any CPU.Build.0 = Release|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Release|arm64.ActiveCfg = Release|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Release|arm64.Build.0 = Release|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Release|x64.ActiveCfg = Release|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Release|x64.Build.0 = Release|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Release|x86.ActiveCfg = Release|Any CPU + {6C5EA367-5663-420E-B10C-8E5543EBF8DD}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -350,6 +386,8 @@ Global {A04E983D-5631-4C68-B34A-796970E060C0} = {52FA15AF-CAE7-4822-9975-F5E812EDEF33} {A4A97F4E-71C1-42FA-84DC-7D4A41079A13} = {FCF55611-6E25-4F1E-8E88-705896171E71} {EECF393D-0F55-4BFE-AEA8-7FD90383C05D} = {FCF55611-6E25-4F1E-8E88-705896171E71} + {84E993AA-5343-4502-9612-B9A416AF243F} = {FCF55611-6E25-4F1E-8E88-705896171E71} + {6C5EA367-5663-420E-B10C-8E5543EBF8DD} = {52FA15AF-CAE7-4822-9975-F5E812EDEF33} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C139BD97-A4F7-411B-99B1-824CE1ABA403} diff --git a/src/apps/H.NotifyIcon.Apps.Maui/H.NotifyIcon.Apps.Maui.csproj b/src/apps/H.NotifyIcon.Apps.Maui/H.NotifyIcon.Apps.Maui.csproj index bdc8484..70b5fee 100644 --- a/src/apps/H.NotifyIcon.Apps.Maui/H.NotifyIcon.Apps.Maui.csproj +++ b/src/apps/H.NotifyIcon.Apps.Maui/H.NotifyIcon.Apps.Maui.csproj @@ -10,6 +10,7 @@ true true enable + $(NoWarn);MT0182 H.NotifyIcon.Apps.Maui @@ -30,6 +31,13 @@ 6.5 + + + + + + + @@ -54,6 +62,7 @@ + diff --git a/src/apps/H.NotifyIcon.Apps.Maui/MainPage.xaml b/src/apps/H.NotifyIcon.Apps.Maui/MainPage.xaml index 4f9c270..d90f043 100644 --- a/src/apps/H.NotifyIcon.Apps.Maui/MainPage.xaml +++ b/src/apps/H.NotifyIcon.Apps.Maui/MainPage.xaml @@ -1,13 +1,19 @@  - - - + + + + + + diff --git a/src/apps/H.NotifyIcon.Apps.Maui/MainPage.xaml.cs b/src/apps/H.NotifyIcon.Apps.Maui/MainPage.xaml.cs index d3b1867..66bcdc7 100644 --- a/src/apps/H.NotifyIcon.Apps.Maui/MainPage.xaml.cs +++ b/src/apps/H.NotifyIcon.Apps.Maui/MainPage.xaml.cs @@ -1,7 +1,4 @@ -using SkiaSharp; -using SkiaSharp.Views.Maui; - -namespace H.NotifyIcon.Apps.Maui; +namespace H.NotifyIcon.Apps.Maui; public partial class MainPage { @@ -9,41 +6,41 @@ public MainPage() { InitializeComponent(); - CanvasView.PaintSurface += CanvasViewOnPaintSurface; + //CanvasView.PaintSurface += CanvasViewOnPaintSurface; } - - private static void CanvasViewOnPaintSurface(object? sender, SKPaintSurfaceEventArgs args) - { - SKImageInfo info = args.Info; - SKSurface surface = args.Surface; - SKCanvas canvas = surface.Canvas; - - canvas.Clear(); - - using var backgroundBrush = new SKPaint(); - backgroundBrush.Style = SKPaintStyle.Stroke; - backgroundBrush.Color = SKColors.Black; - backgroundBrush.StrokeWidth = 24; - backgroundBrush.StrokeCap = SKStrokeCap.Round; - - using var foregroundBrush = new SKPaint(); - foregroundBrush.Style = SKPaintStyle.Stroke; - foregroundBrush.Color = SKColors.White; - foregroundBrush.StrokeWidth = 1; - foregroundBrush.StrokeCap = SKStrokeCap.Round; - foregroundBrush.TextSize = 48; - - canvas.DrawBitmap(SkiaSharpIconGenerator.Generate( - backgroundBrush: backgroundBrush, - foregroundBrush: foregroundBrush, - text: "H", - font: new SKFont(SKTypeface.Default, size: 48F), - pen: new SKPaint - { - Style = SKPaintStyle.Stroke, - StrokeWidth = 5, - Color = SKColors.Aqua, - }), info.Rect); - } + // + // private static void CanvasViewOnPaintSurface(object? sender, SKPaintSurfaceEventArgs args) + // { + // SKImageInfo info = args.Info; + // SKSurface surface = args.Surface; + // SKCanvas canvas = surface.Canvas; + // + // canvas.Clear(); + // + // using var backgroundBrush = new SKPaint(); + // backgroundBrush.Style = SKPaintStyle.Stroke; + // backgroundBrush.Color = SKColors.Black; + // backgroundBrush.StrokeWidth = 24; + // backgroundBrush.StrokeCap = SKStrokeCap.Round; + // + // using var foregroundBrush = new SKPaint(); + // foregroundBrush.Style = SKPaintStyle.Stroke; + // foregroundBrush.Color = SKColors.White; + // foregroundBrush.StrokeWidth = 1; + // foregroundBrush.StrokeCap = SKStrokeCap.Round; + // foregroundBrush.TextSize = 48; + // + // canvas.DrawBitmap(SkiaSharpIconGenerator.Generate( + // backgroundBrush: backgroundBrush, + // foregroundBrush: foregroundBrush, + // text: "H", + // font: new SKFont(SKTypeface.Default, size: 48F), + // pen: new SKPaint + // { + // Style = SKPaintStyle.Stroke, + // StrokeWidth = 5, + // Color = SKColors.Aqua, + // }), info.Rect); + // } } diff --git a/src/apps/H.NotifyIcon.Apps.Maui/MauiProgram.cs b/src/apps/H.NotifyIcon.Apps.Maui/MauiProgram.cs index c106787..f752e11 100644 --- a/src/apps/H.NotifyIcon.Apps.Maui/MauiProgram.cs +++ b/src/apps/H.NotifyIcon.Apps.Maui/MauiProgram.cs @@ -11,6 +11,7 @@ public static MauiApp CreateMauiApp() builder .UseMauiApp() .UseSkiaSharp() + .UseNotifyIcon() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); diff --git a/src/apps/H.NotifyIcon.Apps.Maui/Platforms/MacCatalyst/Program.cs b/src/apps/H.NotifyIcon.Apps.Maui/Platforms/MacCatalyst/Program.cs index affb33b..25f0831 100644 --- a/src/apps/H.NotifyIcon.Apps.Maui/Platforms/MacCatalyst/Program.cs +++ b/src/apps/H.NotifyIcon.Apps.Maui/Platforms/MacCatalyst/Program.cs @@ -1,15 +1,11 @@ -using ObjCRuntime; +using H.NotifyIcon.Apps.Maui; using UIKit; -namespace H.NotifyIcon.Apps.Maui; - -public class Program +#if DEBUG +if (System.Diagnostics.Debugger.IsAttached) { - // This is the main entry point of the application. - static void Main(string[] args) - { - // if you want to use a different Application Delegate class from "AppDelegate" - // you can specify it here. - UIApplication.Main(args, null, typeof(AppDelegate)); - } + Thread.Sleep(TimeSpan.FromSeconds(5)); } +#endif + +UIApplication.Main(args, null, typeof(AppDelegate)); diff --git a/src/apps/H.NotifyIcon.Apps.Maui/Platforms/iOS/Program.cs b/src/apps/H.NotifyIcon.Apps.Maui/Platforms/iOS/Program.cs index affb33b..25f0831 100644 --- a/src/apps/H.NotifyIcon.Apps.Maui/Platforms/iOS/Program.cs +++ b/src/apps/H.NotifyIcon.Apps.Maui/Platforms/iOS/Program.cs @@ -1,15 +1,11 @@ -using ObjCRuntime; +using H.NotifyIcon.Apps.Maui; using UIKit; -namespace H.NotifyIcon.Apps.Maui; - -public class Program +#if DEBUG +if (System.Diagnostics.Debugger.IsAttached) { - // This is the main entry point of the application. - static void Main(string[] args) - { - // if you want to use a different Application Delegate class from "AppDelegate" - // you can specify it here. - UIApplication.Main(args, null, typeof(AppDelegate)); - } + Thread.Sleep(TimeSpan.FromSeconds(5)); } +#endif + +UIApplication.Main(args, null, typeof(AppDelegate)); diff --git a/src/apps/H.NotifyIcon.Apps.Maui/Resources/Images/red.ico b/src/apps/H.NotifyIcon.Apps.Maui/Resources/Images/red.ico new file mode 100644 index 0000000..8a8bbaf Binary files /dev/null and b/src/apps/H.NotifyIcon.Apps.Maui/Resources/Images/red.ico differ diff --git a/src/libs/Directory.Build.targets b/src/libs/Directory.Build.targets index 85a9414..3df63b6 100644 --- a/src/libs/Directory.Build.targets +++ b/src/libs/Directory.Build.targets @@ -30,5 +30,9 @@ + + + + diff --git a/src/libs/H.NotifyIcon.Maui/H.NotifyIcon.Maui.csproj b/src/libs/H.NotifyIcon.Maui/H.NotifyIcon.Maui.csproj new file mode 100644 index 0000000..6d4949b --- /dev/null +++ b/src/libs/H.NotifyIcon.Maui/H.NotifyIcon.Maui.csproj @@ -0,0 +1,48 @@ + + + + net7.0;net7.0-windows10.0.19041.0 + true + $(DefineConstants);HAS_PLATFORM_CODE;HAS_MAUI + $(NoWarn);CA1031;CS8002;CS0108;CA1501 + true + + + + This is an implementation of a NotifyIcon (aka system tray icon or taskbar icon) for the MAUI platform. +It does not just rely on the Windows Forms NotifyIcon component, +but is a purely independent control which leverages several features of the WinUI framework in order to display rich tooltips, +popups, context menus, and balloon messages. It can be used directly in code or embedded in any XAML file. + + notifyicon;maui;tray + + + + + <_Parameter1>https://notifyicon.com/ + <_Parameter2>tb + + + <_Parameter1>https://notifyicon.com/ + <_Parameter2>H.NotifyIcon + + + + + + all + compile; build; native; contentfiles; analyzers; buildtransitive + + + all + compile; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + \ No newline at end of file diff --git a/src/libs/H.NotifyIcon.Maui/MauiAppBuilderExtensions.cs b/src/libs/H.NotifyIcon.Maui/MauiAppBuilderExtensions.cs new file mode 100644 index 0000000..925a06a --- /dev/null +++ b/src/libs/H.NotifyIcon.Maui/MauiAppBuilderExtensions.cs @@ -0,0 +1,18 @@ +namespace H.NotifyIcon; + +/// +/// +/// +[CLSCompliant(false)] +public static class MauiAppBuilderExtensions +{ + /// + /// + /// + /// + /// + public static MauiAppBuilder UseNotifyIcon(this MauiAppBuilder builder) + { + return builder; + } +} diff --git a/src/libs/H.NotifyIcon.Shared/GlobalUsings.cs b/src/libs/H.NotifyIcon.Shared/GlobalUsings.cs index ccf9d2f..d2648eb 100644 --- a/src/libs/H.NotifyIcon.Shared/GlobalUsings.cs +++ b/src/libs/H.NotifyIcon.Shared/GlobalUsings.cs @@ -4,6 +4,7 @@ global using DependencyPropertyGenerator; global using EventGenerator; global using H.NotifyIcon.Core; +global using System.Runtime.Versioning; #if HAS_AVALONIA global using Avalonia; global using Avalonia.Data; @@ -42,7 +43,7 @@ #if HAS_UNO global using WindowActivationState = Windows.UI.Core.CoreWindowActivationState; #endif -#else +#elif HAS_UNO global using Windows.UI.Core; global using Windows.System; global using Windows.UI; @@ -57,6 +58,18 @@ global using Windows.Storage; global using Windows.Foundation; global using FontStyles = Windows.UI.Text.FontStyle; +#else +global using System.Windows.Input; +global using Microsoft.Maui; +global using Microsoft.Maui.Controls; +global using Microsoft.Maui.Media; +global using Microsoft.Maui.Graphics; +global using Microsoft.Maui.Primitives; +global using FontStyle = Microsoft.Maui.Controls.FontAttributes; +global using FontStyles = Microsoft.Maui.Controls.FontAttributes; +global using FontWeights = Microsoft.Maui.FontWeight; +global using FontFamily = System.String; +global using FrameworkElement = Microsoft.Maui.Controls.TemplatedView; #endif #if HAS_SYSTEM_DRAWING global using Icon = System.Drawing.Icon; diff --git a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.IconSource.cs b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.IconSource.cs index 9d015a2..049c9cc 100644 --- a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.IconSource.cs +++ b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.IconSource.cs @@ -4,6 +4,7 @@ Description = "Resolves an image source and updates the Icon property accordingly.", Category = CategoryName)] public partial class TaskbarIcon { + [SupportedOSPlatform("windows5.0")] async partial void OnIconSourceChanged(ImageSource? oldValue, ImageSource? newValue) { if (newValue == null) diff --git a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.KeyboardEvents.cs b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.KeyboardEvents.cs index 16a3c5f..50d03ae 100644 --- a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.KeyboardEvents.cs +++ b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.KeyboardEvents.cs @@ -10,6 +10,7 @@ public partial class TaskbarIcon { #region Event handlers +#if !HAS_MAUI /// /// Processes keyboard events, which are bubbled /// through the class' routed events, trigger @@ -45,6 +46,7 @@ private void OnKeyboardEvent(object? sender, MessageWindow.KeyboardEventReceived $"Missing handler for keyboard event flag: {args.KeyboardEvent}"); } } - +#endif + #endregion } diff --git a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.MouseEvents.cs b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.MouseEvents.cs index cd3038c..62fa0be 100644 --- a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.MouseEvents.cs +++ b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.MouseEvents.cs @@ -41,12 +41,14 @@ public partial class TaskbarIcon /// /// The time we should wait for a double click. /// + [SupportedOSPlatform("windows5.0")] private int DoubleClickWaitTime => NoLeftClickDelay ? 0 : CursorUtilities.GetDoubleClickTime(); #endregion #region Event handlers +#if !HAS_MAUI /// /// Processes mouse events, which are bubbled /// through the class' routed events, trigger @@ -198,7 +200,8 @@ private void OnMouseEvent(object? sender, MessageWindow.MouseEventReceivedEventA SingleClickTimer.Change(DoubleClickWaitTime, Timeout.Infinite); } } - +#endif + /// /// Performs a delayed action if the user requested an action /// based on a single click of the left mouse.
@@ -223,6 +226,8 @@ private void DoSingleClickAction(object? state) this.GetDispatcher().Invoke(action); #elif HAS_UNO && (!HAS_WINUI && !HAS_UNO_WINUI) _ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action()); +#elif HAS_MAUI + MainThread.BeginInvokeOnMainThread(action); #else DispatcherQueue.TryEnqueue(() => action()); #endif diff --git a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.Notifications.cs b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.Notifications.cs index c79fe6e..06cfc3a 100644 --- a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.Notifications.cs +++ b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.Notifications.cs @@ -56,6 +56,7 @@ public partial class TaskbarIcon #if !HAS_WPF [CLSCompliant(false)] #endif + [SupportedOSPlatform("windows5.1.2600")] public void ShowNotification( string title, string message, @@ -88,6 +89,7 @@ public void ShowNotification( /// but I haven't been able to get it to work. ///
/// + [SupportedOSPlatform("windows5.1.2600")] public void ClearNotifications() { EnsureNotDisposed(); @@ -99,6 +101,7 @@ public void ClearNotifications() #region Event handlers +#if !HAS_MAUI /// /// Bubbles events if a balloon ToolTip was displayed /// or removed. @@ -117,6 +120,7 @@ private void OnBalloonToolTipChanged(object? sender, MessageWindow.BalloonToolTi _ = OnTrayBalloonTipClosed(); } } +#endif #endregion } diff --git a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.Popups.cs b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.Popups.cs index cc2fe2a..293265a 100644 --- a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.Popups.cs +++ b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.Popups.cs @@ -1,5 +1,6 @@ namespace H.NotifyIcon; +#if !HAS_MAUI [DependencyProperty("PopupActivation", DefaultValue = PopupActivationMode.LeftClick, Description = "Defines what mouse events display the TaskbarIconPopup.", Category = CategoryName, ClsCompliant = false)] [DependencyProperty("TrayPopup", @@ -236,3 +237,4 @@ private void PlacePopup(System.Drawing.Point cursorPosition) #endregion } +#endif diff --git a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.Properties.cs b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.Properties.cs index 905b047..1380b51 100644 --- a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.Properties.cs +++ b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.Properties.cs @@ -22,11 +22,13 @@ public partial class TaskbarIcon #region Id #if !MACOS + [SupportedOSPlatform("windows5.1.2600")] partial void OnIdChanged(Guid newValue) { TrayIcon.UpdateId(newValue); } + [SupportedOSPlatform("windows5.1.2600")] partial void OnCustomNameChanged(string? newValue) { TrayIcon.UpdateName(newValue ?? string.Empty); @@ -37,6 +39,7 @@ partial void OnCustomNameChanged(string? newValue) #region Icon/IconSource + [SupportedOSPlatform("windows5.1.2600")] partial void OnIconChanged(Icon? oldValue, Icon? newValue) { oldValue?.Dispose(); @@ -48,6 +51,7 @@ partial void OnIconChanged(Icon? oldValue, Icon? newValue) /// /// [CLSCompliant(false)] + [SupportedOSPlatform("windows5.1.2600")] public void UpdateIcon(Icon? value) { #if !MACOS @@ -57,8 +61,11 @@ public void UpdateIcon(Icon? value) #endregion +#if !HAS_MAUI + #region Visibility + [SupportedOSPlatform("windows5.1.2600")] partial void OnVisibilityChanged(Visibility newValue) { var state = newValue == Visibility.Visible @@ -114,4 +121,6 @@ partial void OnDataContextChanged(object? newValue) } #endregion + +#endif } diff --git a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.ToolTips.cs b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.ToolTips.cs index 67c0b90..ce52677 100644 --- a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.ToolTips.cs +++ b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.ToolTips.cs @@ -1,5 +1,6 @@ namespace H.NotifyIcon; +#if !HAS_MAUI [DependencyProperty("ToolTipText", DefaultValue = "", Description = "A tooltip text that is being displayed if no custom ToolTip was set or if custom tooltips are not supported.", Category = CategoryName)] [DependencyProperty("TrayToolTip", @@ -278,3 +279,4 @@ private void OnToolTipChange(object? sender, MessageWindow.ChangeToolTipStateReq #endregion } +#endif diff --git a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.cs b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.cs index 9667385..7d74808 100644 --- a/src/libs/H.NotifyIcon.Shared/TaskbarIcon.cs +++ b/src/libs/H.NotifyIcon.Shared/TaskbarIcon.cs @@ -13,16 +13,14 @@ namespace H.NotifyIcon; #else [OverrideMetadata("ContextFlyout")] #endif -#if HAS_WINUI || HAS_UNO +#if HAS_WINUI || HAS_UNO || HAS_MAUI [CLSCompliant(false)] #endif -#if NET5_0_OR_GREATER #if MACOS || MACCATALYST [Advice("Starting with macos10.10 Soft-deprecation, forwards message to button, but will be gone in the future.")] -[System.Runtime.Versioning.UnsupportedOSPlatform("macos10.10")] -[System.Runtime.Versioning.UnsupportedOSPlatform("maccatalyst")] -[System.Runtime.Versioning.SupportedOSPlatform("macos")] -#endif +[UnsupportedOSPlatform("macos10.10")] +[UnsupportedOSPlatform("maccatalyst")] +[SupportedOSPlatform("macos")] #endif public partial class TaskbarIcon : FrameworkElement, IDisposable { @@ -36,6 +34,7 @@ public partial class TaskbarIcon : FrameworkElement, IDisposable /// /// Indicates whether the taskbar icon has been created or not. /// + [SupportedOSPlatform("windows5.1.2600")] public bool IsCreated => TrayIcon.IsCreated; #endregion @@ -46,9 +45,10 @@ public partial class TaskbarIcon : FrameworkElement, IDisposable /// Initializes the taskbar icon and registers a message listener /// in order to receive events from the taskbar area. ///
+ [SupportedOSPlatform("windows5.1.2600")] public TaskbarIcon() { -#if !HAS_WPF +#if !HAS_WPF && !HAS_MAUI RegisterPropertyChangedCallbacks(); #endif @@ -64,7 +64,7 @@ public TaskbarIcon() Debugger.Break(); } }; -#if !MACOS +#if !MACOS && !HAS_MAUI // https://github.com/HavenDV/H.NotifyIcon/issues/34 //Unloaded += (_, _) => Dispose(); TrayIcon.MessageWindow.DpiChanged += static (_, _) => DpiUtilities.UpdateDpiFactors(); @@ -101,6 +101,7 @@ public TaskbarIcon() /// Recreates the taskbar icon if the whole taskbar was /// recreated (e.g. because Explorer was shut down). ///
+ [SupportedOSPlatform("windows5.1.2600")] private void OnTaskbarCreated(object? sender, EventArgs args) { try @@ -122,6 +123,7 @@ private void OnTaskbarCreated(object? sender, EventArgs args) /// Use it to force create icon if it placed in resources.
/// This also turns on Efficiency Mode by default, meaning you run the app in a hidden state. /// + [SupportedOSPlatform("windows5.1.2600")] public void ForceCreate(bool enablesEfficiencyMode = true) { TrayIcon.Create(); @@ -160,7 +162,11 @@ private void EnsureNotDisposed() { if (IsDisposed) { - throw new ObjectDisposedException(Name ?? GetType().FullName); +#if HAS_MAUI + throw new ObjectDisposedException(GetType().FullName); +#else + throw new ObjectDisposedException(Name ?? nameof(TaskbarIcon)); +#endif } } @@ -168,6 +174,7 @@ private void EnsureNotDisposed() /// /// Disposes the class if the application exits. /// + [SupportedOSPlatform("windows5.1.2600")] private void OnExit(object sender, EventArgs e) { Dispose(); @@ -182,6 +189,7 @@ private void OnExit(object sender, EventArgs e) /// Important: Do not provide destructor in types derived from this class. /// /// + [SupportedOSPlatform("windows5.1.2600")] ~TaskbarIcon() { Dispose(false); @@ -194,6 +202,7 @@ private void OnExit(object sender, EventArgs e) /// This method is not virtual by design. Derived classes /// should override . /// + [SupportedOSPlatform("windows5.1.2600")] #if HAS_UNO public new void Dispose() #else @@ -226,6 +235,7 @@ public void Dispose() /// be disposed. /// Check the property to determine whether /// the method has already been called. + [SupportedOSPlatform("windows5.1.2600")] protected virtual void Dispose(bool disposing) { if (IsDisposed || !disposing) @@ -251,7 +261,7 @@ protected virtual void Dispose(bool disposing) balloonCloseTimer.Dispose(); #endif -#if !HAS_WPF && !HAS_UNO +#if !HAS_WPF && !HAS_UNO && !HAS_MAUI ContextMenuWindow?.Close(); ContextMenuWindow = null; ContextMenuWindowHandle = null; diff --git a/src/libs/H.NotifyIcon.Shared/Utilities/ImageExtensions.Maui.cs b/src/libs/H.NotifyIcon.Shared/Utilities/ImageExtensions.Maui.cs new file mode 100644 index 0000000..5564958 --- /dev/null +++ b/src/libs/H.NotifyIcon.Shared/Utilities/ImageExtensions.Maui.cs @@ -0,0 +1,32 @@ +namespace H.NotifyIcon; + +internal static partial class ImageExtensions +{ + public static Stream ToStream(this ImageSource imageSource) + { + switch (imageSource) + { + case FileImageSource bitmapImage: + { + return File.OpenRead(bitmapImage.File); + } + + default: + throw new NotImplementedException($"ImageSource type: {imageSource.GetType()} is not supported"); + } + } + + public static Task ToStreamAsync(this ImageSource imageSource, CancellationToken cancellationToken = default) + { + switch(imageSource) + { + case FileImageSource bitmapImage: + { + return Task.FromResult(File.OpenRead(bitmapImage.File)); + } + + default: + return Task.FromException(new NotImplementedException($"ImageSource type: {imageSource.GetType()} is not supported")); + } + } +} diff --git a/src/libs/H.NotifyIcon.Shared/Utilities/System.Drawing/StreamExtensions.cs b/src/libs/H.NotifyIcon.Shared/Utilities/System.Drawing/StreamExtensions.cs index de64b7c..e9fca1f 100644 --- a/src/libs/H.NotifyIcon.Shared/Utilities/System.Drawing/StreamExtensions.cs +++ b/src/libs/H.NotifyIcon.Shared/Utilities/System.Drawing/StreamExtensions.cs @@ -4,7 +4,7 @@ namespace H.NotifyIcon; internal static class StreamExtensions { - [SupportedOSPlatform("windows")] + [SupportedOSPlatform("windows5.0")] internal static Icon ToSmallIcon(this Stream stream) { var iconSize = IconUtilities.GetRequiredCustomIconSize(largeIcon: false).ScaleWithDpi(); diff --git a/src/libs/H.NotifyIcon.Shared/WindowExtensions.cs b/src/libs/H.NotifyIcon.Shared/WindowExtensions.cs index 2cc5e02..93567b0 100644 --- a/src/libs/H.NotifyIcon.Shared/WindowExtensions.cs +++ b/src/libs/H.NotifyIcon.Shared/WindowExtensions.cs @@ -20,7 +20,7 @@ public static void Hide( #if HAS_WPF window.Hide(); -#elif !HAS_UNO +#elif !HAS_UNO && !HAS_MAUI WindowUtilities.HideWindow(WindowNative.GetWindowHandle(window)); #endif @@ -49,7 +49,7 @@ public static void Show( #if HAS_WPF window.Show(); -#elif !HAS_UNO +#elif !HAS_UNO && !HAS_MAUI WindowUtilities.ShowWindow(WindowNative.GetWindowHandle(window)); #endif