Skip to content

Commit

Permalink
Merge pull request #8547 from AvaloniaUI/tray-icon-fixes
Browse files Browse the repository at this point in the history
Tray icon fixes
  • Loading branch information
danwalmsley committed Jul 20, 2022
1 parent dc871e7 commit 0b525bf
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 24 deletions.
1 change: 1 addition & 0 deletions samples/ControlCatalog/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
<NativeMenuItemSeparator />
<NativeMenuItem Header="Option 3" ToggleType="CheckBox" IsChecked="True" Command="{Binding ToggleCommand}" />
<NativeMenuItem Icon="/Assets/test_icon.ico" Header="Restore Defaults" Command="{Binding ToggleCommand}" />
<NativeMenuItem Header="Disabled option" IsEnabled="False" />
</NativeMenu>
</NativeMenuItem>
<NativeMenuItem Header="Exit" Command="{Binding ExitCommand}" />
Expand Down
8 changes: 6 additions & 2 deletions src/Avalonia.Controls/TrayIcon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ static TrayIcon()
args.NewValue.Value.CollectionChanged += Icons_CollectionChanged;
}
}
else
{
throw new InvalidOperationException("TrayIcon.Icons must be set on the Application.");
}
});

var app = Application.Current ?? throw new InvalidOperationException("Application not yet initialized.");
Expand Down Expand Up @@ -125,9 +129,9 @@ public static readonly StyledProperty<NativeMenu?> MenuProperty
public static readonly StyledProperty<bool> IsVisibleProperty =
Visual.IsVisibleProperty.AddOwner<TrayIcon>();

public static void SetIcons(AvaloniaObject o, TrayIcons trayIcons) => o.SetValue(IconsProperty, trayIcons);
public static void SetIcons(Application o, TrayIcons trayIcons) => o.SetValue(IconsProperty, trayIcons);

public static TrayIcons GetIcons(AvaloniaObject o) => o.GetValue(IconsProperty);
public static TrayIcons GetIcons(Application o) => o.GetValue(IconsProperty);

/// <summary>
/// Gets or sets the <see cref="Command"/> property of a TrayIcon.
Expand Down
1 change: 1 addition & 0 deletions src/Avalonia.Themes.Default/NativeMenuBar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<Menu.Styles>
<Style Selector="MenuItem">
<Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
<Setter Property="InputGesture" Value="{Binding Gesture}"/>
<Setter Property="Items" Value="{Binding Menu.Items}"/>
<Setter Property="Command" Value="{Binding Command}"/>
Expand Down
1 change: 1 addition & 0 deletions src/Avalonia.Themes.Fluent/Controls/NativeMenuBar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<Menu.Styles>
<Style x:CompileBindings="False" Selector="MenuItem">
<Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
<Setter Property="InputGesture" Value="{Binding Gesture}"/>
<Setter Property="Items" Value="{Binding Menu.Items}"/>
<Setter Property="Command" Value="{Binding Command}"/>
Expand Down
20 changes: 3 additions & 17 deletions src/Windows/Avalonia.Win32/IconImpl.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,24 @@
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using Avalonia.Platform;

namespace Avalonia.Win32
{
class IconImpl : IWindowIconImpl
{
private Bitmap bitmap;
private Icon icon;

public IconImpl(Bitmap bitmap)
{
this.bitmap = bitmap;
}
private readonly Icon icon;

public IconImpl(Icon icon)
{
this.icon = icon;
}

public IntPtr HIcon => icon?.Handle ?? bitmap.GetHicon();
public IntPtr HIcon => icon.Handle;

public void Save(Stream outputStream)
{
if (icon != null)
{
icon.Save(outputStream);
}
else
{
bitmap.Save(outputStream, ImageFormat.Png);
}
icon.Save(outputStream);
}
}
}
4 changes: 3 additions & 1 deletion src/Windows/Avalonia.Win32/TrayIconImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace Avalonia.Win32
{
public class TrayIconImpl : ITrayIconImpl
{
private static readonly IntPtr s_emptyIcon = new System.Drawing.Bitmap(32, 32).GetHicon();

private readonly int _uniqueId;
private static int s_nextUniqueId;
private bool _iconAdded;
Expand Down Expand Up @@ -84,7 +86,7 @@ private void UpdateIcon(bool remove = false)
uID = _uniqueId,
uFlags = NIF.TIP | NIF.MESSAGE,
uCallbackMessage = (int)CustomWindowsMessage.WM_TRAYMOUSE,
hIcon = _icon?.HIcon ?? new IconImpl(new System.Drawing.Bitmap(32, 32)).HIcon,
hIcon = _icon?.HIcon ?? s_emptyIcon,
szTip = _tooltipText ?? ""
};

Expand Down
16 changes: 14 additions & 2 deletions src/Windows/Avalonia.Win32/Win32NativeToManagedMenuExporter.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using System.Collections.Generic;
using System.Reactive.Linq;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Media.Imaging;
using Avalonia.Utilities;

#nullable enable

Expand All @@ -28,15 +31,24 @@ private AvaloniaList<MenuItem> Populate(NativeMenu nativeMenu)
}
else if (menuItem is NativeMenuItem item)
{
var newItem = new MenuItem { Header = item.Header, Icon = item.Icon, Command = item.Command, CommandParameter = item.CommandParameter };
var newItem = new MenuItem
{
[!MenuItem.HeaderProperty] = item.GetObservable(NativeMenuItem.HeaderProperty).ToBinding(),
[!MenuItem.IconProperty] = item.GetObservable(NativeMenuItem.IconProperty)
.Select(i => i is {} bitmap ? new Image { Source = bitmap } : null).ToBinding(),
[!MenuItem.IsEnabledProperty] = item.GetObservable(NativeMenuItem.IsEnabledProperty).ToBinding(),
[!MenuItem.CommandProperty] = item.GetObservable(NativeMenuItem.CommandProperty).ToBinding(),
[!MenuItem.CommandParameterProperty] = item.GetObservable(NativeMenuItem.CommandParameterProperty).ToBinding(),
[!MenuItem.InputGestureProperty] = item.GetObservable(NativeMenuItem.GestureProperty).ToBinding()
};

if (item.Menu != null)
{
newItem.Items = Populate(item.Menu);
}
else if (item.HasClickHandlers && item is INativeMenuItemExporterEventsImplBridge bridge)
{
newItem.Click += (_, __) => bridge.RaiseClicked();
newItem.Click += (_, _) => bridge.RaiseClicked();
}

result.Add(newItem);
Expand Down
8 changes: 6 additions & 2 deletions src/Windows/Avalonia.Win32/Win32Platform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -346,19 +346,23 @@ public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
using (var memoryStream = new MemoryStream())
{
bitmap.Save(memoryStream);
return new IconImpl(new System.Drawing.Bitmap(memoryStream));
return CreateIconImpl(memoryStream);
}
}

private static IconImpl CreateIconImpl(Stream stream)
{
try
{
// new Icon() will work only if stream is an "ico" file.
return new IconImpl(new System.Drawing.Icon(stream));
}
catch (ArgumentException)
{
return new IconImpl(new System.Drawing.Bitmap(stream));
// Fallback to Bitmap creation and converting into a windows icon.
using var icon = new System.Drawing.Bitmap(stream);
var hIcon = icon.GetHicon();
return new IconImpl(System.Drawing.Icon.FromHandle(hIcon));
}
}

Expand Down

0 comments on commit 0b525bf

Please sign in to comment.