@ -1,4 +1,4 @@
using System ;
using System ;
using Avalonia.Controls ;
using Avalonia.Controls ;
using Avalonia.Controls.ApplicationLifetimes ;
using Avalonia.Controls.ApplicationLifetimes ;
using Avalonia.Controls.Platform ;
using Avalonia.Controls.Platform ;
@ -6,24 +6,29 @@ using Avalonia.Dialogs;
using Avalonia.Input ;
using Avalonia.Input ;
using Avalonia.Native.Interop ;
using Avalonia.Native.Interop ;
using Avalonia.Native.Interop.Impl ;
using Avalonia.Native.Interop.Impl ;
using Avalonia.Reactive ;
using Avalonia.Threading ;
using Avalonia.Threading ;
namespace Avalonia.Native
namespace Avalonia.Native
{
{
internal class AvaloniaNativeMenuExporter : ITopLevelNativeMenuExporter
internal class AvaloniaNativeMenuExporter : ITopLevelNativeMenuExporter
{
{
internal enum MenuTarget { Application , Window , TrayIcon , Dock }
private readonly IAvaloniaNativeFactory _f actory ;
private readonly IAvaloniaNativeFactory _f actory ;
private readonly MenuTarget _ target ;
private bool _ resetQueued = true ;
private bool _ resetQueued = true ;
private bool _ exported ;
private bool _ exported ;
private readonly IAvnWindow ? _ nativeWindow ;
private readonly IAvnWindow ? _ nativeWindow ;
private NativeMenu ? _ menu ;
private NativeMenu ? _ menu ;
private _ _ MicroComIAvnMenuProxy ? _ nativeMenu ;
private _ _ MicroComIAvnMenuProxy ? _ nativeMenu ;
private readonly IAvnTrayIcon ? _ trayIcon ;
private readonly IAvnTrayIcon ? _ trayIcon ;
private readonly IAvnApplicationCommands _ applicationCommands ;
private readonly IAvnApplicationCommands ? _ applicationCommands ;
public AvaloniaNativeMenuExporter ( IAvnWindow nativeWindow , IAvaloniaNativeFactory factory )
public AvaloniaNativeMenuExporter ( IAvnWindow nativeWindow , IAvaloniaNativeFactory factory )
{
{
_f actory = factory ;
_f actory = factory ;
_ target = MenuTarget . Window ;
_ nativeWindow = nativeWindow ;
_ nativeWindow = nativeWindow ;
_ applicationCommands = _f actory . CreateApplicationCommands ( ) ;
_ applicationCommands = _f actory . CreateApplicationCommands ( ) ;
@ -33,6 +38,7 @@ namespace Avalonia.Native
public AvaloniaNativeMenuExporter ( IAvaloniaNativeFactory factory )
public AvaloniaNativeMenuExporter ( IAvaloniaNativeFactory factory )
{
{
_f actory = factory ;
_f actory = factory ;
_ target = MenuTarget . Application ;
_ applicationCommands = _f actory . CreateApplicationCommands ( ) ;
_ applicationCommands = _f actory . CreateApplicationCommands ( ) ;
DoLayoutReset ( ) ;
DoLayoutReset ( ) ;
@ -41,20 +47,65 @@ namespace Avalonia.Native
public AvaloniaNativeMenuExporter ( IAvnTrayIcon trayIcon , IAvaloniaNativeFactory factory )
public AvaloniaNativeMenuExporter ( IAvnTrayIcon trayIcon , IAvaloniaNativeFactory factory )
{
{
_f actory = factory ;
_f actory = factory ;
_ target = MenuTarget . TrayIcon ;
_ trayIcon = trayIcon ;
_ trayIcon = trayIcon ;
_ applicationCommands = _f actory . CreateApplicationCommands ( ) ;
_ applicationCommands = _f actory . CreateApplicationCommands ( ) ;
DoLayoutReset ( ) ;
DoLayoutReset ( ) ;
}
}
internal AvaloniaNativeMenuExporter ( IAvaloniaNativeFactory factory , MenuTarget target )
{
_f actory = factory ;
_ target = target ;
_ resetQueued = false ;
var macOpts = AvaloniaLocator . Current . GetService < MacOSPlatformOptions > ( ) ? ? new MacOSPlatformOptions ( ) ;
if ( macOpts . DisableNativeMenus )
{
return ;
}
NativeDock . MenuProperty . Changed . Subscribe ( args = >
{
if ( args . Sender is Application )
{
SetNativeMenu ( args . NewValue . GetValueOrDefault ( ) ) ;
}
} ) ;
var app = Application . Current ;
if ( app is not null )
{
var dockMenu = NativeDock . GetMenu ( app ) ;
if ( dockMenu is not null )
{
SetNativeMenu ( dockMenu ) ;
}
}
}
public bool IsNativeMenuExported = > _ exported ;
public bool IsNativeMenuExported = > _ exported ;
public event EventHandler OnIsNativeMenuExportedChanged { add { } remove { } }
public event EventHandler OnIsNativeMenuExportedChanged { add { } remove { } }
public void SetNativeMenu ( NativeMenu ? menu )
public void SetNativeMenu ( NativeMenu ? menu )
{
{
_ menu = menu ? ? new NativeMenu ( ) ;
if ( _ target = = MenuTarget . Dock )
DoLayoutReset ( true ) ;
{
_ menu = menu ;
if ( _ menu is not null )
{
DoLayoutReset ( true ) ;
}
}
else
{
_ menu = menu ? ? new NativeMenu ( ) ;
DoLayoutReset ( true ) ;
}
}
}
internal void UpdateIfNeeded ( )
internal void UpdateIfNeeded ( )
@ -70,7 +121,7 @@ namespace Avalonia.Native
var result = new NativeMenu ( ) ;
var result = new NativeMenu ( ) ;
var aboutItem = new NativeMenuItem ( "About Avalonia" ) ;
var aboutItem = new NativeMenuItem ( "About Avalonia" ) ;
aboutItem . Click + = async ( _ , _ ) = >
aboutItem . Click + = async ( _ , _ ) = >
{
{
var dialog = new AboutAvaloniaDialog ( ) ;
var dialog = new AboutAvaloniaDialog ( ) ;
@ -78,14 +129,14 @@ namespace Avalonia.Native
if ( Application . Current is
if ( Application . Current is
{ ApplicationLifetime : IClassicDesktopStyleApplicationLifetime { MainWindow : { IsVisible : true } mainWindow } } )
{ ApplicationLifetime : IClassicDesktopStyleApplicationLifetime { MainWindow : { IsVisible : true } mainWindow } } )
{
{
await dialog . ShowDialog ( mainWindow ) ;
await dialog . ShowDialog ( mainWindow ) ;
}
}
else
else
{
{
dialog . Show ( ) ;
dialog . Show ( ) ;
}
}
} ;
} ;
result . Add ( aboutItem ) ;
result . Add ( aboutItem ) ;
return result ;
return result ;
@ -109,7 +160,7 @@ namespace Avalonia.Native
hideItem . Click + = ( _ , _ ) = >
hideItem . Click + = ( _ , _ ) = >
{
{
_ applicationCommands . HideApp ( ) ;
_ applicationCommands ? . HideApp ( ) ;
} ;
} ;
appMenu . Add ( hideItem ) ;
appMenu . Add ( hideItem ) ;
@ -120,14 +171,14 @@ namespace Avalonia.Native
} ;
} ;
hideOthersItem . Click + = ( _ , _ ) = >
hideOthersItem . Click + = ( _ , _ ) = >
{
{
_ applicationCommands . HideOthers ( ) ;
_ applicationCommands ? . HideOthers ( ) ;
} ;
} ;
appMenu . Add ( hideOthersItem ) ;
appMenu . Add ( hideOthersItem ) ;
var showAllItem = new NativeMenuItem ( "Show All" ) ;
var showAllItem = new NativeMenuItem ( "Show All" ) ;
showAllItem . Click + = ( _ , _ ) = >
showAllItem . Click + = ( _ , _ ) = >
{
{
_ applicationCommands . ShowAll ( ) ;
_ applicationCommands ? . ShowAll ( ) ;
} ;
} ;
appMenu . Add ( showAllItem ) ;
appMenu . Add ( showAllItem ) ;
@ -165,9 +216,9 @@ namespace Avalonia.Native
{
{
_ resetQueued = false ;
_ resetQueued = false ;
if ( _ nativeWindow is null )
switch ( _ target )
{
{
if ( _ trayIcon is null )
case MenuTarget . Application :
{
{
var app = Application . Current ;
var app = Application . Current ;
var appMenu = app is null ? null : NativeMenu . GetMenu ( app ) ;
var appMenu = app is null ? null : NativeMenu . GetMenu ( app ) ;
@ -181,17 +232,34 @@ namespace Avalonia.Native
}
}
SetMenu ( appMenu ) ;
SetMenu ( appMenu ) ;
break ;
}
}
else if ( _ menu ! = null )
case MenuTarget . Window :
{
{
SetMenu ( _ trayIcon , _ menu ) ;
if ( _ menu ! = null )
{
SetMenu ( _ nativeWindow , _ menu ) ;
}
break ;
}
}
}
else
case MenuTarget . TrayIcon :
{
{
if ( _ menu ! = null )
if ( _ menu ! = null )
{
SetMenu ( _ trayIcon , _ menu ) ;
}
break ;
}
case MenuTarget . Dock :
{
{
SetMenu ( _ nativeWindow , _ menu ) ;
if ( _ menu ! = null )
{
SetDockMenu ( _ menu ) ;
}
break ;
}
}
}
}
@ -253,7 +321,7 @@ namespace Avalonia.Native
}
}
}
}
private void SetMenu ( IAvnWindow avnWindow , NativeMenu menu )
private void SetMenu ( IAvnWindow ? avnWindow , NativeMenu menu )
{
{
var setMenu = false ;
var setMenu = false ;
@ -270,11 +338,11 @@ namespace Avalonia.Native
if ( setMenu )
if ( setMenu )
{
{
avnWindow . SetMainMenu ( _ nativeMenu ) ;
avnWindow ? . SetMainMenu ( _ nativeMenu ) ;
}
}
}
}
private void SetMenu ( IAvnTrayIcon trayIcon , NativeMenu menu )
private void SetMenu ( IAvnTrayIcon ? trayIcon , NativeMenu menu )
{
{
var setMenu = false ;
var setMenu = false ;
@ -291,7 +359,28 @@ namespace Avalonia.Native
if ( setMenu )
if ( setMenu )
{
{
trayIcon . SetMenu ( _ nativeMenu ) ;
trayIcon ? . SetMenu ( _ nativeMenu ) ;
}
}
private void SetDockMenu ( NativeMenu menu )
{
var setMenu = false ;
if ( _ nativeMenu is null )
{
_ nativeMenu = _ _ MicroComIAvnMenuProxy . Create ( _f actory ) ;
_ nativeMenu . Initialize ( this , menu , "" ) ;
setMenu = true ;
}
_ nativeMenu . Update ( _f actory , menu ) ;
if ( setMenu )
{
_f actory . SetDockMenu ( _ nativeMenu ) ;
}
}
}
}
}
}