diff --git a/native/Avalonia.Native/src/OSX/common.h b/native/Avalonia.Native/src/OSX/common.h index 0f7215f37c..c082003ccf 100644 --- a/native/Avalonia.Native/src/OSX/common.h +++ b/native/Avalonia.Native/src/OSX/common.h @@ -23,7 +23,7 @@ extern IAvnCursorFactory* CreateCursorFactory(); extern IAvnGlDisplay* GetGlDisplay(); extern IAvnMenu* CreateAppMenu(IAvnMenuEvents* events); extern IAvnMenuItem* CreateAppMenuItem(); -extern IAvnMenuItem* CreateAppMenuItemSeperator(); +extern IAvnMenuItem* CreateAppMenuItemSeparator(); extern IAvnNativeControlHost* CreateNativeControlHost(NSView* parent); extern void SetAppMenu (NSString* appName, IAvnMenu* appMenu); extern IAvnMenu* GetAppMenu (); diff --git a/native/Avalonia.Native/src/OSX/main.mm b/native/Avalonia.Native/src/OSX/main.mm index 11742e3b5c..aaaf381b26 100644 --- a/native/Avalonia.Native/src/OSX/main.mm +++ b/native/Avalonia.Native/src/OSX/main.mm @@ -253,9 +253,9 @@ public: return S_OK; } - virtual HRESULT CreateMenuItemSeperator (IAvnMenuItem** ppv) override + virtual HRESULT CreateMenuItemSeparator (IAvnMenuItem** ppv) override { - *ppv = ::CreateAppMenuItemSeperator(); + *ppv = ::CreateAppMenuItemSeparator(); return S_OK; } diff --git a/native/Avalonia.Native/src/OSX/menu.h b/native/Avalonia.Native/src/OSX/menu.h index 564fdc132b..186fcf255b 100644 --- a/native/Avalonia.Native/src/OSX/menu.h +++ b/native/Avalonia.Native/src/OSX/menu.h @@ -31,13 +31,13 @@ private: NSMenuItem* _native; // here we hold a pointer to an AvnMenuItem IAvnActionCallback* _callback; IAvnPredicateCallback* _predicate; - bool _isSeperator; + bool _isSeparator; bool _isCheckable; public: FORWARD_IUNKNOWN() - AvnAppMenuItem(bool isSeperator); + AvnAppMenuItem(bool isSeparator); NSMenuItem* GetNative(); @@ -60,7 +60,6 @@ public: void RaiseOnClicked(); }; - class AvnAppMenu : public ComSingleObject { private: @@ -71,10 +70,12 @@ public: FORWARD_IUNKNOWN() AvnAppMenu(IAvnMenuEvents* events); - + AvnMenu* GetNative(); void RaiseNeedsUpdate (); + void RaiseOpening(); + void RaiseClosed(); virtual HRESULT InsertItem (int index, IAvnMenuItem* item) override; diff --git a/native/Avalonia.Native/src/OSX/menu.mm b/native/Avalonia.Native/src/OSX/menu.mm index ea5cca9ce8..b9a95e7b3c 100644 --- a/native/Avalonia.Native/src/OSX/menu.mm +++ b/native/Avalonia.Native/src/OSX/menu.mm @@ -71,12 +71,12 @@ } @end -AvnAppMenuItem::AvnAppMenuItem(bool isSeperator) +AvnAppMenuItem::AvnAppMenuItem(bool isSeparator) { _isCheckable = false; - _isSeperator = isSeperator; + _isSeparator = isSeparator; - if(isSeperator) + if(isSeparator) { _native = [NSMenuItem separatorItem]; } @@ -298,6 +298,23 @@ void AvnAppMenu::RaiseNeedsUpdate() } } +void AvnAppMenu::RaiseOpening() +{ + if(_baseEvents != nullptr) + { + _baseEvents->Opening(); + } +} + +void AvnAppMenu::RaiseClosed() +{ + if(_baseEvents != nullptr) + { + _baseEvents->Closed(); + } +} + + HRESULT AvnAppMenu::InsertItem(int index, IAvnMenuItem *item) { @autoreleasepool @@ -382,6 +399,15 @@ HRESULT AvnAppMenu::Clear() _parent->RaiseNeedsUpdate(); } +- (void)menuWillOpen:(NSMenu *)menu +{ + _parent->RaiseOpening(); +} + +- (void)menuDidClose:(NSMenu *)menu +{ + _parent->RaiseClosed(); +} @end @@ -401,7 +427,7 @@ extern IAvnMenuItem* CreateAppMenuItem() } } -extern IAvnMenuItem* CreateAppMenuItemSeperator() +extern IAvnMenuItem* CreateAppMenuItemSeparator() { @autoreleasepool { diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index 4d63c486c4..b46655c7df 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -2231,9 +2231,12 @@ protected: { @autoreleasepool { - [Window setContentSize:NSSize{x, y}]; + if (Window != nullptr) + { + [Window setContentSize:NSSize{x, y}]; - [Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(lastPositionSet))]; + [Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(lastPositionSet))]; + } return S_OK; } diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index 8e331edab4..d627a2bf19 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -89,10 +89,6 @@ partial class Build : NukeBuild Process.Start(new ProcessStartInfo(command, args) {UseShellExecute = false}).WaitForExit(); } ExecWait("dotnet version:", "dotnet", "--version"); - if (Parameters.IsRunningOnUnix) - ExecWait("Mono version:", "mono", "--version"); - - } IReadOnlyCollection MsBuildCommon( diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index 6a70bb082f..a107ee2163 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -18,11 +18,11 @@ - + - + diff --git a/src/Avalonia.Controls/ApiCompatBaseline.txt b/src/Avalonia.Controls/ApiCompatBaseline.txt index aa8db78087..0284463f1c 100644 --- a/src/Avalonia.Controls/ApiCompatBaseline.txt +++ b/src/Avalonia.Controls/ApiCompatBaseline.txt @@ -1,7 +1,9 @@ Compat issues with assembly Avalonia.Controls: +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.INativeMenuExporterEventsImplBridge.RaiseClosed()' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.INativeMenuExporterEventsImplBridge.RaiseOpening()' is present in the implementation but not in the contract. MembersMustExist : Member 'public void Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.SetCursor(Avalonia.Platform.IPlatformHandle)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.AvaloniaProperty Avalonia.AvaloniaProperty Avalonia.Controls.Notifications.NotificationCard.CloseOnClickProperty' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.ICursorImpl)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.IPlatformHandle)' is present in the contract but not in the implementation. MembersMustExist : Member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.IPlatformHandle)' does not exist in the implementation but it does exist in the contract. -Total Issues: 5 +Total Issues: 7 diff --git a/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs b/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs index 672d5c1a13..f492e6ca0f 100644 --- a/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs +++ b/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs @@ -3,5 +3,7 @@ namespace Avalonia.Controls public interface INativeMenuExporterEventsImplBridge { void RaiseNeedsUpdate (); + void RaiseOpening(); + void RaiseClosed(); } } diff --git a/src/Avalonia.Controls/NativeMenu.cs b/src/Avalonia.Controls/NativeMenu.cs index 38a9f03d29..58ee99722f 100644 --- a/src/Avalonia.Controls/NativeMenu.cs +++ b/src/Avalonia.Controls/NativeMenu.cs @@ -12,13 +12,34 @@ namespace Avalonia.Controls private readonly AvaloniaList _items = new AvaloniaList { ResetBehavior = ResetBehavior.Remove }; private NativeMenuItem _parent; + [Content] public IList Items => _items; /// - /// Raised when the user clicks the menu and before its opened. Use this event to update the menu dynamically. + /// Raised when the menu requests an update. + /// + /// + /// Use this event to add, remove or modify menu items before a menu is + /// shown or a hotkey is pressed. + /// + public event EventHandler NeedsUpdate; + + /// + /// Raised before the menu is opened. /// + /// + /// Do not update the menu in this event; use . + /// public event EventHandler Opening; + + /// + /// Raised after the menu is closed. + /// + /// + /// Do not update the menu in this event; use . + /// + public event EventHandler Closed; public NativeMenu() { @@ -27,10 +48,20 @@ namespace Avalonia.Controls } void INativeMenuExporterEventsImplBridge.RaiseNeedsUpdate() + { + NeedsUpdate?.Invoke(this, EventArgs.Empty); + } + + void INativeMenuExporterEventsImplBridge.RaiseOpening() { Opening?.Invoke(this, EventArgs.Empty); } + void INativeMenuExporterEventsImplBridge.RaiseClosed() + { + Closed?.Invoke(this, EventArgs.Empty); + } + private void Validator(NativeMenuItemBase obj) { if (obj.Parent != null) diff --git a/src/Avalonia.Controls/NativeMenuItemSeparator.cs b/src/Avalonia.Controls/NativeMenuItemSeparator.cs new file mode 100644 index 0000000000..d3d3721c89 --- /dev/null +++ b/src/Avalonia.Controls/NativeMenuItemSeparator.cs @@ -0,0 +1,16 @@ +using System; + +namespace Avalonia.Controls +{ + + [Obsolete("This class exists to maintain backwards compatiblity with existing code. Use NativeMenuItemSeparator instead")] + public class NativeMenuItemSeperator : NativeMenuItemSeparator + { + } + + public class NativeMenuItemSeparator : NativeMenuItemBase + { + [Obsolete("This is a temporary hack to make our MenuItem recognize this as a separator, don't use", true)] + public string Header => "-"; + } +} diff --git a/src/Avalonia.Controls/NativeMenuItemSeperator.cs b/src/Avalonia.Controls/NativeMenuItemSeperator.cs deleted file mode 100644 index e743483dab..0000000000 --- a/src/Avalonia.Controls/NativeMenuItemSeperator.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Avalonia.Controls -{ - public class NativeMenuItemSeperator : NativeMenuItemBase - { - [Obsolete("This is a temporary hack to make our MenuItem recognize this as a separator, don't use", true)] - public string Header => "-"; - } -} diff --git a/src/Avalonia.FreeDesktop/DBusMenuExporter.cs b/src/Avalonia.FreeDesktop/DBusMenuExporter.cs index 2cf533195e..9e635e01f1 100644 --- a/src/Avalonia.FreeDesktop/DBusMenuExporter.cs +++ b/src/Avalonia.FreeDesktop/DBusMenuExporter.cs @@ -192,7 +192,7 @@ namespace Avalonia.FreeDesktop { var (it, menu) = i; - if (it is NativeMenuItemSeperator) + if (it is NativeMenuItemSeparator) { if (name == "type") return "separator"; diff --git a/src/Avalonia.Native/IAvnMenu.cs b/src/Avalonia.Native/IAvnMenu.cs index dd9464284f..f76e9450fc 100644 --- a/src/Avalonia.Native/IAvnMenu.cs +++ b/src/Avalonia.Native/IAvnMenu.cs @@ -20,11 +20,23 @@ namespace Avalonia.Native.Interop { _parent?.RaiseNeedsUpdate(); } + + public void Opening() + { + _parent?.RaiseOpening(); + } + + public void Closed() + { + _parent?.RaiseClosed(); + } } partial interface IAvnMenu { void RaiseNeedsUpdate(); + void RaiseOpening(); + void RaiseClosed(); void Deinitialise(); } } @@ -45,6 +57,16 @@ namespace Avalonia.Native.Interop.Impl _exporter.UpdateIfNeeded(); } + public void RaiseOpening() + { + (ManagedMenu as INativeMenuExporterEventsImplBridge).RaiseOpening(); + } + + public void RaiseClosed() + { + (ManagedMenu as INativeMenuExporterEventsImplBridge).RaiseClosed(); + } + internal NativeMenu ManagedMenu { get; private set; } public static __MicroComIAvnMenuProxy Create(IAvaloniaNativeFactory factory) @@ -103,8 +125,8 @@ namespace Avalonia.Native.Interop.Impl private __MicroComIAvnMenuItemProxy CreateNew(IAvaloniaNativeFactory factory, NativeMenuItemBase item) { - var nativeItem = (__MicroComIAvnMenuItemProxy)(item is NativeMenuItemSeperator ? - factory.CreateMenuItemSeperator() : + var nativeItem = (__MicroComIAvnMenuItemProxy)(item is NativeMenuItemSeparator ? + factory.CreateMenuItemSeparator() : factory.CreateMenuItem()); nativeItem.ManagedMenuItem = item; diff --git a/src/Avalonia.Native/avn.idl b/src/Avalonia.Native/avn.idl index 2693f5f139..9cada1120a 100644 --- a/src/Avalonia.Native/avn.idl +++ b/src/Avalonia.Native/avn.idl @@ -417,7 +417,7 @@ interface IAvaloniaNativeFactory : IUnknown HRESULT SetAppMenu(IAvnMenu* menu); HRESULT CreateMenu(IAvnMenuEvents* cb, IAvnMenu** ppv); HRESULT CreateMenuItem(IAvnMenuItem** ppv); - HRESULT CreateMenuItemSeperator(IAvnMenuItem** ppv); + HRESULT CreateMenuItemSeparator(IAvnMenuItem** ppv); } [uuid(233e094f-9b9f-44a3-9a6e-6948bbdd9fb1)] @@ -685,10 +685,9 @@ interface IAvnMenuItem : IUnknown [uuid(0af7df53-7632-42f4-a650-0992c361b477)] interface IAvnMenuEvents : IUnknown { - /** - * NeedsUpdate - */ void NeedsUpdate(); + void Opening(); + void Closed(); } [uuid(5142bb41-66ab-49e7-bb37-cd079c000f27)]