diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index b70e0bf77f..54645e461e 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -68,7 +68,7 @@ jobs:
inputs:
script: |
brew update
- brew install castxml
+ brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/8a004a91a7fcd3f6620d5b01b6541ff0a640ffba/Formula/castxml.rb
- task: CmdLine@2
displayName: 'Install Nuke'
diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props
index 08a9aa3ceb..4f69f39e02 100644
--- a/build/SkiaSharp.props
+++ b/build/SkiaSharp.props
@@ -1,6 +1,6 @@
-
-
+
+
diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h
index 3475eff654..b10db08adc 100644
--- a/native/Avalonia.Native/inc/avalonia-native.h
+++ b/native/Avalonia.Native/inc/avalonia-native.h
@@ -1,5 +1,6 @@
#include "com.h"
#include "key.h"
+#include "stddef.h"
#define AVNCOM(name, id) COMINTERFACE(name, 2e2cda0a, 9ae5, 4f1b, 8e, 20, 08, 1a, 04, 27, 9f, id)
@@ -19,8 +20,9 @@ struct IAvnGlContext;
struct IAvnGlDisplay;
struct IAvnGlSurfaceRenderTarget;
struct IAvnGlSurfaceRenderingSession;
-struct IAvnAppMenu;
-struct IAvnAppMenuItem;
+struct IAvnMenu;
+struct IAvnMenuItem;
+struct IAvnMenuEvents;
enum SystemDecorations {
SystemDecorationsNone = 0,
@@ -175,6 +177,13 @@ enum AvnWindowEdge
WindowEdgeSouthEast
};
+enum AvnMenuItemToggleType
+{
+ None,
+ CheckMark,
+ Radio
+};
+
AVNCOM(IAvaloniaNativeFactory, 01) : IUnknown
{
public:
@@ -188,11 +197,10 @@ public:
virtual HRESULT CreateClipboard(IAvnClipboard** ppv) = 0;
virtual HRESULT CreateCursorFactory(IAvnCursorFactory** ppv) = 0;
virtual HRESULT ObtainGlDisplay(IAvnGlDisplay** ppv) = 0;
- virtual HRESULT ObtainAppMenu(IAvnAppMenu** retOut) = 0;
- virtual HRESULT SetAppMenu(IAvnAppMenu* menu) = 0;
- virtual HRESULT CreateMenu (IAvnAppMenu** ppv) = 0;
- virtual HRESULT CreateMenuItem (IAvnAppMenuItem** ppv) = 0;
- virtual HRESULT CreateMenuItemSeperator (IAvnAppMenuItem** ppv) = 0;
+ virtual HRESULT SetAppMenu(IAvnMenu* menu) = 0;
+ virtual HRESULT CreateMenu (IAvnMenuEvents* cb, IAvnMenu** ppv) = 0;
+ virtual HRESULT CreateMenuItem (IAvnMenuItem** ppv) = 0;
+ virtual HRESULT CreateMenuItemSeperator (IAvnMenuItem** ppv) = 0;
};
AVNCOM(IAvnString, 17) : IUnknown
@@ -222,8 +230,7 @@ AVNCOM(IAvnWindowBase, 02) : IUnknown
virtual HRESULT SetTopMost (bool value) = 0;
virtual HRESULT SetCursor(IAvnCursor* cursor) = 0;
virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget** ret) = 0;
- virtual HRESULT SetMainMenu(IAvnAppMenu* menu) = 0;
- virtual HRESULT ObtainMainMenu(IAvnAppMenu** retOut) = 0;
+ virtual HRESULT SetMainMenu(IAvnMenu* menu) = 0;
virtual HRESULT ObtainNSWindowHandle(void** retOut) = 0;
virtual HRESULT ObtainNSWindowHandleRetained(void** retOut) = 0;
virtual HRESULT ObtainNSViewHandle(void** retOut) = 0;
@@ -388,10 +395,10 @@ AVNCOM(IAvnGlSurfaceRenderingSession, 16) : IUnknown
virtual HRESULT GetScaling(double* ret) = 0;
};
-AVNCOM(IAvnAppMenu, 17) : IUnknown
+AVNCOM(IAvnMenu, 17) : IUnknown
{
- virtual HRESULT AddItem (IAvnAppMenuItem* item) = 0;
- virtual HRESULT RemoveItem (IAvnAppMenuItem* item) = 0;
+ virtual HRESULT InsertItem (int index, IAvnMenuItem* item) = 0;
+ virtual HRESULT RemoveItem (IAvnMenuItem* item) = 0;
virtual HRESULT SetTitle (void* utf8String) = 0;
virtual HRESULT Clear () = 0;
};
@@ -401,12 +408,23 @@ AVNCOM(IAvnPredicateCallback, 18) : IUnknown
virtual bool Evaluate() = 0;
};
-AVNCOM(IAvnAppMenuItem, 19) : IUnknown
+AVNCOM(IAvnMenuItem, 19) : IUnknown
{
- virtual HRESULT SetSubMenu (IAvnAppMenu* menu) = 0;
+ virtual HRESULT SetSubMenu (IAvnMenu* menu) = 0;
virtual HRESULT SetTitle (void* utf8String) = 0;
virtual HRESULT SetGesture (void* utf8String, AvnInputModifiers modifiers) = 0;
virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) = 0;
+ virtual HRESULT SetIsChecked (bool isChecked) = 0;
+ virtual HRESULT SetToggleType (AvnMenuItemToggleType toggleType) = 0;
+ virtual HRESULT SetIcon (void* data, size_t length) = 0;
+};
+
+AVNCOM(IAvnMenuEvents, 1A) : IUnknown
+{
+ /**
+ * NeedsUpdate
+ */
+ virtual void NeedsUpdate () = 0;
};
extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative();
diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme
index 1a665d3ea5..5d20a135b9 100644
--- a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme
+++ b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/xcshareddata/xcschemes/Avalonia.Native.OSX.xcscheme
@@ -29,8 +29,6 @@
shouldUseLaunchSchemeArgsEnv = "YES">
-
-
-
-
@end
-extern NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationActivationPolicyRegular;
+NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationActivationPolicyRegular;
+
@implementation AvnAppDelegate
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
@@ -14,6 +15,10 @@ extern NSApplicationActivationPolicy AvnDesiredActivationPolicy = NSApplicationA
}
[[NSApplication sharedApplication] setActivationPolicy: AvnDesiredActivationPolicy];
+
+ [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"];
+
+ [[NSApplication sharedApplication] setHelpMenu: [[NSMenu new] initWithTitle:@""]];
}
}
diff --git a/native/Avalonia.Native/src/OSX/common.h b/native/Avalonia.Native/src/OSX/common.h
index 85403abfe7..7a433bfd9f 100644
--- a/native/Avalonia.Native/src/OSX/common.h
+++ b/native/Avalonia.Native/src/OSX/common.h
@@ -15,11 +15,11 @@ extern IAvnScreens* CreateScreens();
extern IAvnClipboard* CreateClipboard();
extern IAvnCursorFactory* CreateCursorFactory();
extern IAvnGlDisplay* GetGlDisplay();
-extern IAvnAppMenu* CreateAppMenu();
-extern IAvnAppMenuItem* CreateAppMenuItem();
-extern IAvnAppMenuItem* CreateAppMenuItemSeperator();
-extern void SetAppMenu (NSString* appName, IAvnAppMenu* appMenu);
-extern IAvnAppMenu* GetAppMenu ();
+extern IAvnMenu* CreateAppMenu(IAvnMenuEvents* events);
+extern IAvnMenuItem* CreateAppMenuItem();
+extern IAvnMenuItem* CreateAppMenuItemSeperator();
+extern void SetAppMenu (NSString* appName, IAvnMenu* appMenu);
+extern IAvnMenu* GetAppMenu ();
extern NSMenuItem* GetAppMenuItem ();
extern void InitializeAvnApp();
diff --git a/native/Avalonia.Native/src/OSX/main.mm b/native/Avalonia.Native/src/OSX/main.mm
index a2134de6c1..a63353bc0a 100644
--- a/native/Avalonia.Native/src/OSX/main.mm
+++ b/native/Avalonia.Native/src/OSX/main.mm
@@ -92,12 +92,11 @@ void SetProcessName(NSString* appTitle) {
PrivateLSASN asn = ls_get_current_application_asn_func();
// Constant used by WebKit; what exactly it means is unknown.
const int magic_session_constant = -2;
- OSErr err =
+
ls_set_application_information_item_func(magic_session_constant, asn,
ls_display_name_key,
process_name,
NULL /* optional out param */);
- //LOG_IF(ERROR, err) << "Call to set process name failed, err " << err;
}
class MacOptions : public ComSingleObject
@@ -228,41 +227,29 @@ public:
return S_OK;
}
- virtual HRESULT CreateMenu (IAvnAppMenu** ppv) override
+ virtual HRESULT CreateMenu (IAvnMenuEvents* cb, IAvnMenu** ppv) override
{
- *ppv = ::CreateAppMenu();
+ *ppv = ::CreateAppMenu(cb);
return S_OK;
}
- virtual HRESULT CreateMenuItem (IAvnAppMenuItem** ppv) override
+ virtual HRESULT CreateMenuItem (IAvnMenuItem** ppv) override
{
*ppv = ::CreateAppMenuItem();
return S_OK;
}
- virtual HRESULT CreateMenuItemSeperator (IAvnAppMenuItem** ppv) override
+ virtual HRESULT CreateMenuItemSeperator (IAvnMenuItem** ppv) override
{
*ppv = ::CreateAppMenuItemSeperator();
return S_OK;
}
- virtual HRESULT SetAppMenu (IAvnAppMenu* appMenu) override
+ virtual HRESULT SetAppMenu (IAvnMenu* appMenu) override
{
::SetAppMenu(s_appTitle, appMenu);
return S_OK;
}
-
- virtual HRESULT ObtainAppMenu(IAvnAppMenu** retOut) override
- {
- if(retOut == nullptr)
- {
- return E_POINTER;
- }
-
- *retOut = ::GetAppMenu();
-
- return S_OK;
- }
};
extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative()
diff --git a/native/Avalonia.Native/src/OSX/menu.h b/native/Avalonia.Native/src/OSX/menu.h
index befbe6a7e0..bfbc6801f8 100644
--- a/native/Avalonia.Native/src/OSX/menu.h
+++ b/native/Avalonia.Native/src/OSX/menu.h
@@ -14,8 +14,10 @@
class AvnAppMenuItem;
class AvnAppMenu;
-@interface AvnMenu : NSMenu // for some reason it doesnt detect nsmenu here but compiler doesnt complain
-- (void)setMenu:(NSMenu*) menu;
+@interface AvnMenu : NSMenu
+- (id) initWithDelegate: (NSObject*) del;
+- (void) setHasGlobalMenuItem: (bool) value;
+- (bool) hasGlobalMenuItem;
@end
@interface AvnMenuItem : NSMenuItem
@@ -23,13 +25,14 @@ class AvnAppMenu;
- (void)didSelectItem:(id)sender;
@end
-class AvnAppMenuItem : public ComSingleObject
+class AvnAppMenuItem : public ComSingleObject
{
private:
NSMenuItem* _native; // here we hold a pointer to an AvnMenuItem
IAvnActionCallback* _callback;
IAvnPredicateCallback* _predicate;
bool _isSeperator;
+ bool _isCheckable;
public:
FORWARD_IUNKNOWN()
@@ -38,7 +41,7 @@ public:
NSMenuItem* GetNative();
- virtual HRESULT SetSubMenu (IAvnAppMenu* menu) override;
+ virtual HRESULT SetSubMenu (IAvnMenu* menu) override;
virtual HRESULT SetTitle (void* utf8String) override;
@@ -46,29 +49,36 @@ public:
virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) override;
+ virtual HRESULT SetIsChecked (bool isChecked) override;
+
+ virtual HRESULT SetToggleType (AvnMenuItemToggleType toggleType) override;
+
+ virtual HRESULT SetIcon (void* data, size_t length) override;
+
bool EvaluateItemEnabled();
void RaiseOnClicked();
};
-class AvnAppMenu : public ComSingleObject
+class AvnAppMenu : public ComSingleObject
{
private:
AvnMenu* _native;
+ ComPtr _baseEvents;
public:
FORWARD_IUNKNOWN()
- AvnAppMenu();
-
- AvnAppMenu(AvnMenu* native);
-
+ AvnAppMenu(IAvnMenuEvents* events);
+
AvnMenu* GetNative();
- virtual HRESULT AddItem (IAvnAppMenuItem* item) override;
+ void RaiseNeedsUpdate ();
+
+ virtual HRESULT InsertItem (int index, IAvnMenuItem* item) override;
- virtual HRESULT RemoveItem (IAvnAppMenuItem* item) override;
+ virtual HRESULT RemoveItem (IAvnMenuItem* item) override;
virtual HRESULT SetTitle (void* utf8String) override;
@@ -76,5 +86,9 @@ public:
};
+@interface AvnMenuDelegate : NSObject
+- (id) initWithParent: (AvnAppMenu*) parent;
+@end
+
#endif
diff --git a/native/Avalonia.Native/src/OSX/menu.mm b/native/Avalonia.Native/src/OSX/menu.mm
index 1d2f075ccb..dc1245cd23 100644
--- a/native/Avalonia.Native/src/OSX/menu.mm
+++ b/native/Avalonia.Native/src/OSX/menu.mm
@@ -4,6 +4,30 @@
#include "window.h"
@implementation AvnMenu
+{
+ bool _isReparented;
+ NSObject* _wtf;
+}
+
+- (id) initWithDelegate: (NSObject*)del
+{
+ self = [super init];
+ self.delegate = del;
+ _wtf = del;
+ _isReparented = false;
+ return self;
+}
+
+- (bool)hasGlobalMenuItem
+{
+ return _isReparented;
+}
+
+- (void)setHasGlobalMenuItem:(bool)value
+{
+ _isReparented = value;
+}
+
@end
@implementation AvnMenuItem
@@ -46,6 +70,7 @@
AvnAppMenuItem::AvnAppMenuItem(bool isSeperator)
{
+ _isCheckable = false;
_isSeperator = isSeperator;
if(isSeperator)
@@ -65,49 +90,134 @@ NSMenuItem* AvnAppMenuItem::GetNative()
return _native;
}
-HRESULT AvnAppMenuItem::SetSubMenu (IAvnAppMenu* menu)
+HRESULT AvnAppMenuItem::SetSubMenu (IAvnMenu* menu)
{
- auto nsMenu = dynamic_cast(menu)->GetNative();
-
- [_native setSubmenu: nsMenu];
-
- return S_OK;
+ @autoreleasepool
+ {
+ if(menu != nullptr)
+ {
+ auto nsMenu = dynamic_cast(menu)->GetNative();
+
+ [_native setSubmenu: nsMenu];
+ }
+ else
+ {
+ [_native setSubmenu: nullptr];
+ }
+
+ return S_OK;
+ }
}
HRESULT AvnAppMenuItem::SetTitle (void* utf8String)
{
- if (utf8String != nullptr)
+ @autoreleasepool
{
- [_native setTitle:[NSString stringWithUTF8String:(const char*)utf8String]];
+ if (utf8String != nullptr)
+ {
+ [_native setTitle:[NSString stringWithUTF8String:(const char*)utf8String]];
+ }
+
+ return S_OK;
}
-
- return S_OK;
}
HRESULT AvnAppMenuItem::SetGesture (void* key, AvnInputModifiers modifiers)
{
- NSEventModifierFlags flags = 0;
-
- if (modifiers & Control)
- flags |= NSEventModifierFlagControl;
- if (modifiers & Shift)
- flags |= NSEventModifierFlagShift;
- if (modifiers & Alt)
- flags |= NSEventModifierFlagOption;
- if (modifiers & Windows)
- flags |= NSEventModifierFlagCommand;
-
- [_native setKeyEquivalent:[NSString stringWithUTF8String:(const char*)key]];
- [_native setKeyEquivalentModifierMask:flags];
-
- return S_OK;
+ @autoreleasepool
+ {
+ NSEventModifierFlags flags = 0;
+
+ if (modifiers & Control)
+ flags |= NSEventModifierFlagControl;
+ if (modifiers & Shift)
+ flags |= NSEventModifierFlagShift;
+ if (modifiers & Alt)
+ flags |= NSEventModifierFlagOption;
+ if (modifiers & Windows)
+ flags |= NSEventModifierFlagCommand;
+
+ [_native setKeyEquivalent:[NSString stringWithUTF8String:(const char*)key]];
+ [_native setKeyEquivalentModifierMask:flags];
+
+ return S_OK;
+ }
}
HRESULT AvnAppMenuItem::SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback)
{
- _predicate = predicate;
- _callback = callback;
- return S_OK;
+ @autoreleasepool
+ {
+ _predicate = predicate;
+ _callback = callback;
+ return S_OK;
+ }
+}
+
+HRESULT AvnAppMenuItem::SetIsChecked (bool isChecked)
+{
+ @autoreleasepool
+ {
+ [_native setState:(isChecked && _isCheckable ? NSOnState : NSOffState)];
+ return S_OK;
+ }
+}
+
+HRESULT AvnAppMenuItem::SetToggleType(AvnMenuItemToggleType toggleType)
+{
+ @autoreleasepool
+ {
+ switch(toggleType)
+ {
+ case AvnMenuItemToggleType::None:
+ [_native setOnStateImage: [NSImage imageNamed:@"NSMenuCheckmark"]];
+
+ _isCheckable = false;
+ break;
+
+ case AvnMenuItemToggleType::CheckMark:
+ [_native setOnStateImage: [NSImage imageNamed:@"NSMenuCheckmark"]];
+
+ _isCheckable = true;
+ break;
+
+ case AvnMenuItemToggleType::Radio:
+ [_native setOnStateImage: [NSImage imageNamed:@"NSMenuItemBullet"]];
+
+ _isCheckable = true;
+ break;
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT AvnAppMenuItem::SetIcon(void *data, size_t length)
+{
+ @autoreleasepool
+ {
+ if(data != nullptr)
+ {
+ NSData *imageData = [NSData dataWithBytes:data length:length];
+ NSImage *image = [[NSImage alloc] initWithData:imageData];
+
+ NSSize originalSize = [image size];
+
+ NSSize size;
+ size.height = [[NSFont menuFontOfSize:0] pointSize] * 1.333333;
+
+ auto scaleFactor = size.height / originalSize.height;
+ size.width = originalSize.width * scaleFactor;
+
+ [image setSize: size];
+ [_native setImage:image];
+ }
+ else
+ {
+ [_native setImage:nullptr];
+ }
+ return S_OK;
+ }
}
bool AvnAppMenuItem::EvaluateItemEnabled()
@@ -130,71 +240,123 @@ void AvnAppMenuItem::RaiseOnClicked()
}
}
-AvnAppMenu::AvnAppMenu()
+AvnAppMenu::AvnAppMenu(IAvnMenuEvents* events)
{
- _native = [AvnMenu new];
+ _baseEvents = events;
+ id del = [[AvnMenuDelegate alloc] initWithParent: this];
+ _native = [[AvnMenu alloc] initWithDelegate: del];
}
-AvnAppMenu::AvnAppMenu(AvnMenu* native)
-{
- _native = native;
-}
AvnMenu* AvnAppMenu::GetNative()
{
return _native;
}
-HRESULT AvnAppMenu::AddItem (IAvnAppMenuItem* item)
+void AvnAppMenu::RaiseNeedsUpdate()
{
- auto avnMenuItem = dynamic_cast(item);
-
- if(avnMenuItem != nullptr)
+ if(_baseEvents != nullptr)
{
- [_native addItem: avnMenuItem->GetNative()];
+ _baseEvents->NeedsUpdate();
}
-
- return S_OK;
}
-HRESULT AvnAppMenu::RemoveItem (IAvnAppMenuItem* item)
+HRESULT AvnAppMenu::InsertItem(int index, IAvnMenuItem *item)
{
- auto avnMenuItem = dynamic_cast(item);
-
- if(avnMenuItem != nullptr)
+ @autoreleasepool
{
- [_native removeItem:avnMenuItem->GetNative()];
+ if([_native hasGlobalMenuItem])
+ {
+ index++;
+ }
+
+ auto avnMenuItem = dynamic_cast(item);
+
+ if(avnMenuItem != nullptr)
+ {
+ [_native insertItem: avnMenuItem->GetNative() atIndex:index];
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT AvnAppMenu::RemoveItem (IAvnMenuItem* item)
+{
+ @autoreleasepool
+ {
+ auto avnMenuItem = dynamic_cast(item);
+
+ if(avnMenuItem != nullptr)
+ {
+ [_native removeItem:avnMenuItem->GetNative()];
+ }
+
+ return S_OK;
}
-
- return S_OK;
}
HRESULT AvnAppMenu::SetTitle (void* utf8String)
{
- if (utf8String != nullptr)
+ @autoreleasepool
{
- [_native setTitle:[NSString stringWithUTF8String:(const char*)utf8String]];
+ if (utf8String != nullptr)
+ {
+ [_native setTitle:[NSString stringWithUTF8String:(const char*)utf8String]];
+ }
+
+ return S_OK;
}
-
- return S_OK;
}
HRESULT AvnAppMenu::Clear()
{
- [_native removeAllItems];
- return S_OK;
+ @autoreleasepool
+ {
+ [_native removeAllItems];
+ return S_OK;
+ }
+}
+
+@implementation AvnMenuDelegate
+{
+ ComPtr _parent;
}
+- (id) initWithParent:(AvnAppMenu *)parent
+{
+ self = [super init];
+ _parent = parent;
+ return self;
+}
+- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel
+{
+ if(shouldCancel)
+ return NO;
+ return YES;
+}
+
+- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu
+{
+ return [menu numberOfItems];
+}
+
+- (void)menuNeedsUpdate:(NSMenu *)menu
+{
+ _parent->RaiseNeedsUpdate();
+}
+
+
+@end
-extern IAvnAppMenu* CreateAppMenu()
+extern IAvnMenu* CreateAppMenu(IAvnMenuEvents* cb)
{
@autoreleasepool
{
- id menuBar = [NSMenu new];
- return new AvnAppMenu(menuBar);
+ return new AvnAppMenu(cb);
}
}
-extern IAvnAppMenuItem* CreateAppMenuItem()
+extern IAvnMenuItem* CreateAppMenuItem()
{
@autoreleasepool
{
@@ -202,7 +364,7 @@ extern IAvnAppMenuItem* CreateAppMenuItem()
}
}
-extern IAvnAppMenuItem* CreateAppMenuItemSeperator()
+extern IAvnMenuItem* CreateAppMenuItemSeperator()
{
@autoreleasepool
{
@@ -210,10 +372,10 @@ extern IAvnAppMenuItem* CreateAppMenuItemSeperator()
}
}
-static IAvnAppMenu* s_appMenu = nullptr;
+static IAvnMenu* s_appMenu = nullptr;
static NSMenuItem* s_appMenuItem = nullptr;
-extern void SetAppMenu (NSString* appName, IAvnAppMenu* menu)
+extern void SetAppMenu (NSString* appName, IAvnMenu* menu)
{
s_appMenu = menu;
@@ -294,7 +456,7 @@ extern void SetAppMenu (NSString* appName, IAvnAppMenu* menu)
}
}
-extern IAvnAppMenu* GetAppMenu ()
+extern IAvnMenu* GetAppMenu ()
{
return s_appMenu;
}
diff --git a/native/Avalonia.Native/src/OSX/platformthreading.mm b/native/Avalonia.Native/src/OSX/platformthreading.mm
index 2d72226faf..f93436d157 100644
--- a/native/Avalonia.Native/src/OSX/platformthreading.mm
+++ b/native/Avalonia.Native/src/OSX/platformthreading.mm
@@ -54,9 +54,11 @@ private:
{
public:
FORWARD_IUNKNOWN()
+
bool Running = false;
bool Cancelled = false;
- virtual void Cancel()
+
+ virtual void Cancel() override
{
Cancelled = true;
if(Running)
diff --git a/native/Avalonia.Native/src/OSX/window.h b/native/Avalonia.Native/src/OSX/window.h
index 5c85a2f423..8092db3663 100644
--- a/native/Avalonia.Native/src/OSX/window.h
+++ b/native/Avalonia.Native/src/OSX/window.h
@@ -19,7 +19,11 @@ class WindowBaseImpl;
-(void) pollModalSession: (NSModalSession _Nonnull) session;
-(void) restoreParentWindow;
-(bool) shouldTryToHandleEvents;
--(void) applyMenu:(NSMenu *)menu;
+-(bool) isModal;
+-(void) setModal: (bool) isModal;
+-(void) showAppMenuOnly;
+-(void) showWindowMenuWithAppMenu;
+-(void) applyMenu:(NSMenu* _Nullable)menu;
-(double) getScaling;
@end
diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm
index 6298118c10..68899df9f0 100644
--- a/native/Avalonia.Native/src/OSX/window.mm
+++ b/native/Avalonia.Native/src/OSX/window.mm
@@ -27,7 +27,7 @@ public:
NSObject* renderTarget;
AvnPoint lastPositionSet;
NSString* _lastTitle;
- IAvnAppMenu* _mainMenu;
+ IAvnMenu* _mainMenu;
bool _shown;
WindowBaseImpl(IAvnWindowBaseEvents* events, IAvnGlContext* gl)
@@ -234,7 +234,7 @@ public:
}
}
- virtual HRESULT SetMainMenu(IAvnAppMenu* menu) override
+ virtual HRESULT SetMainMenu(IAvnMenu* menu) override
{
_mainMenu = menu;
@@ -244,18 +244,11 @@ public:
[Window applyMenu:nsmenu];
- return S_OK;
- }
-
- virtual HRESULT ObtainMainMenu(IAvnAppMenu** ret) override
- {
- if(ret == nullptr)
+ if ([Window isKeyWindow])
{
- return E_POINTER;
+ [Window showWindowMenuWithAppMenu];
}
- *ret = _mainMenu;
-
return S_OK;
}
@@ -432,6 +425,7 @@ private:
WindowEvents = events;
[Window setCanBecomeKeyAndMain];
[Window disableCursorRects];
+ [Window setTabbingMode:NSWindowTabbingModeDisallowed];
}
virtual HRESULT Show () override
@@ -440,6 +434,9 @@ private:
{
if([Window parentWindow] != nil)
[[Window parentWindow] removeChildWindow:Window];
+
+ [Window setModal:FALSE];
+
WindowBaseImpl::Show();
return SetWindowState(_lastWindowState);
@@ -457,6 +454,8 @@ private:
if(cparent == nullptr)
return E_INVALIDARG;
+ [Window setModal:TRUE];
+
[cparent->Window addChildWindow:Window ordered:NSWindowAbove];
WindowBaseImpl::Show();
@@ -1151,8 +1150,8 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
ComPtr _parent;
bool _canBecomeKeyAndMain;
bool _closed;
- NSMenu* _menu;
- bool _isAppMenuApplied;
+ bool _isModal;
+ AvnMenu* _menu;
double _lastScaling;
}
@@ -1189,32 +1188,64 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
}
}
--(void) applyMenu:(NSMenu *)menu
+-(void) showWindowMenuWithAppMenu
{
- if(menu == nullptr)
+ if(_menu != nullptr)
{
- menu = [NSMenu new];
+ auto appMenuItem = ::GetAppMenuItem();
+
+ if(appMenuItem != nullptr)
+ {
+ auto appMenu = [appMenuItem menu];
+
+ [appMenu removeItem:appMenuItem];
+
+ [_menu insertItem:appMenuItem atIndex:0];
+
+ [_menu setHasGlobalMenuItem:true];
+ }
+
+ [NSApp setMenu:_menu];
}
+}
+
+-(void) showAppMenuOnly
+{
+ auto appMenuItem = ::GetAppMenuItem();
- _menu = menu;
-
- if ([self isKeyWindow])
+ if(appMenuItem != nullptr)
{
- auto appMenu = ::GetAppMenuItem();
+ auto appMenu = ::GetAppMenu();
+
+ auto nativeAppMenu = dynamic_cast(appMenu);
- if(appMenu != nullptr)
+ [[appMenuItem menu] removeItem:appMenuItem];
+
+ if(_menu != nullptr)
{
- [[appMenu menu] removeItem:appMenu];
-
- [_menu insertItem:appMenu atIndex:0];
-
- _isAppMenuApplied = true;
+ [_menu setHasGlobalMenuItem:false];
}
- [NSApp setMenu:menu];
+ [nativeAppMenu->GetNative() addItem:appMenuItem];
+
+ [NSApp setMenu:nativeAppMenu->GetNative()];
+ }
+ else
+ {
+ [NSApp setMenu:nullptr];
}
}
+-(void) applyMenu:(AvnMenu *)menu
+{
+ if(menu == nullptr)
+ {
+ menu = [AvnMenu new];
+ }
+
+ _menu = menu;
+}
+
-(void) setCanBecomeKeyAndMain
{
_canBecomeKeyAndMain = true;
@@ -1298,11 +1329,25 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
auto ch = objc_cast(uch);
if(ch == nil)
continue;
+
+ if(![ch isModal])
+ continue;
+
return FALSE;
}
return TRUE;
}
+-(bool) isModal
+{
+ return _isModal;
+}
+
+-(void) setModal: (bool) isModal
+{
+ _isModal = isModal;
+}
+
-(void)makeKeyWindow
{
if([self activateAppropriateChild: true])
@@ -1315,23 +1360,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
{
if([self activateAppropriateChild: true])
{
- if(_menu == nullptr)
- {
- _menu = [NSMenu new];
- }
-
- auto appMenu = ::GetAppMenuItem();
-
- if(appMenu != nullptr)
- {
- [[appMenu menu] removeItem:appMenu];
-
- [_menu insertItem:appMenu atIndex:0];
-
- _isAppMenuApplied = true;
- }
-
- [NSApp setMenu:_menu];
+ [self showWindowMenuWithAppMenu];
_parent->BaseEvents->Activated();
[super becomeKeyWindow];
@@ -1383,26 +1412,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
if(_parent)
_parent->BaseEvents->Deactivated();
- auto appMenuItem = ::GetAppMenuItem();
-
- if(appMenuItem != nullptr)
- {
- auto appMenu = ::GetAppMenu();
-
- auto nativeAppMenu = dynamic_cast(appMenu);
-
- [[appMenuItem menu] removeItem:appMenuItem];
-
- [nativeAppMenu->GetNative() addItem:appMenuItem];
-
- [NSApp setMenu:nativeAppMenu->GetNative()];
- }
- else
- {
- [NSApp setMenu:nullptr];
- }
-
- // remove window menu items from appmenu?
+ [self showAppMenuOnly];
[super resignKeyWindow];
}
diff --git a/packages/Avalonia/Avalonia.csproj b/packages/Avalonia/Avalonia.csproj
index 9f7593b702..2c5a09bee7 100644
--- a/packages/Avalonia/Avalonia.csproj
+++ b/packages/Avalonia/Avalonia.csproj
@@ -1,6 +1,6 @@
- netstandard2.0;net461;netcoreapp3.1
+ netstandard2.0;net461;netcoreapp2.0
Avalonia
@@ -20,8 +20,8 @@
Platform=$(Platform)" />
- <_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/netcoreapp3.1/Avalonia.Designer.HostApp.dll">
- tools/netcoreapp3.1/designer
+ <_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/netcoreapp2.0/Avalonia.Designer.HostApp.dll">
+ tools/netcoreapp2.0/designer
false
None
diff --git a/packages/Avalonia/Avalonia.props b/packages/Avalonia/Avalonia.props
index 99d53c1e03..6f21971d3d 100644
--- a/packages/Avalonia/Avalonia.props
+++ b/packages/Avalonia/Avalonia.props
@@ -1,6 +1,6 @@
- $(MSBuildThisFileDirectory)\..\tools\netcoreapp3.1\designer\Avalonia.Designer.HostApp.dll
+ $(MSBuildThisFileDirectory)\..\tools\netcoreapp2.0\designer\Avalonia.Designer.HostApp.dll
$(MSBuildThisFileDirectory)\..\tools\net461\designer\Avalonia.Designer.HostApp.exe
$(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Avalonia.Build.Tasks.dll
false
diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml
index d25de9c1f5..bea751ad4c 100644
--- a/samples/ControlCatalog/MainWindow.xaml
+++ b/samples/ControlCatalog/MainWindow.xaml
@@ -14,9 +14,9 @@
-
+
-
+
@@ -36,6 +36,24 @@
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/MainWindow.xaml.cs b/samples/ControlCatalog/MainWindow.xaml.cs
index b40fdb4a17..d97325ef8d 100644
--- a/samples/ControlCatalog/MainWindow.xaml.cs
+++ b/samples/ControlCatalog/MainWindow.xaml.cs
@@ -29,6 +29,7 @@ namespace ControlCatalog
DataContext = new MainWindowViewModel(_notificationArea);
_recentMenu = ((NativeMenu.GetMenu(this).Items[0] as NativeMenuItem).Menu.Items[2] as NativeMenuItem).Menu;
+
var mainMenu = this.FindControl