diff --git a/.ncrunch/Avalonia.Native.v3.ncrunchproject b/.ncrunch/Avalonia.Native.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/Avalonia.Native.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h
index 0e3edaa2dc..4b814a9cfb 100644
--- a/native/Avalonia.Native/inc/avalonia-native.h
+++ b/native/Avalonia.Native/inc/avalonia-native.h
@@ -213,7 +213,7 @@ AVNCOM(IAvnPopup, 03) : virtual IAvnWindowBase
AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase
{
- virtual HRESULT ShowDialog (IUnknown**ppv) = 0;
+ virtual HRESULT ShowDialog (IAvnWindow* parent) = 0;
virtual HRESULT SetCanResize(bool value) = 0;
virtual HRESULT SetHasDecorations(bool value) = 0;
virtual HRESULT SetTitle (void* utf8Title) = 0;
diff --git a/native/Avalonia.Native/src/OSX/common.h b/native/Avalonia.Native/src/OSX/common.h
index 1647569269..f748dd59ad 100644
--- a/native/Avalonia.Native/src/OSX/common.h
+++ b/native/Avalonia.Native/src/OSX/common.h
@@ -31,4 +31,13 @@ extern NSSize ToNSSize (AvnSize s);
#define NSDebugLog(...) (void)0
#endif
+template inline T* objc_cast(id from) {
+ if(from == nil)
+ return nil;
+ if ([from isKindOfClass:[T class]]) {
+ return static_cast(from);
+ }
+ return nil;
+}
+
#endif
diff --git a/native/Avalonia.Native/src/OSX/main.mm b/native/Avalonia.Native/src/OSX/main.mm
index 4d6dcfed85..5043246c53 100644
--- a/native/Avalonia.Native/src/OSX/main.mm
+++ b/native/Avalonia.Native/src/OSX/main.mm
@@ -32,27 +32,23 @@ public:
- (void) do;
@end
@implementation ThreadingInitializer
-
-pthread_mutex_t mutex;
-pthread_cond_t cond;
-
+{
+ int _fds[2];
+}
- (void) runOnce
{
- pthread_mutex_lock(&mutex);
- pthread_cond_signal(&cond);
- pthread_mutex_unlock(&mutex);
+ char buf[]={0};
+ write(_fds[1], buf, 1);
}
- (void) do
{
- pthread_mutex_init(&mutex, NULL);
- pthread_cond_init(&cond, NULL);
+ pipe(_fds);
[[[NSThread alloc] initWithTarget:self selector:@selector(runOnce) object:nil] start];
- pthread_mutex_lock(&mutex);
- pthread_cond_wait(&cond, &mutex);
- pthread_mutex_unlock(&mutex);
- pthread_cond_destroy(&cond);
- pthread_mutex_destroy(&mutex);
+ char buf[1];
+ read(_fds[0], buf, 1);
+ close(_fds[0]);
+ close(_fds[1]);
}
diff --git a/native/Avalonia.Native/src/OSX/window.h b/native/Avalonia.Native/src/OSX/window.h
index 34592993c3..e2221217f3 100644
--- a/native/Avalonia.Native/src/OSX/window.h
+++ b/native/Avalonia.Native/src/OSX/window.h
@@ -18,6 +18,8 @@ class WindowBaseImpl;
-(AvnWindow* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent;
-(void) setCanBecomeKeyAndMain;
-(void) pollModalSession: (NSModalSession _Nonnull) session;
+-(void) restoreParentWindow;
+-(bool) shouldTryToHandleEvents;
@end
struct INSWindowHolder
diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm
index 16b21efcd5..ae00bde780 100644
--- a/native/Avalonia.Native/src/OSX/window.mm
+++ b/native/Avalonia.Native/src/OSX/window.mm
@@ -109,6 +109,7 @@ public:
if(Window != nullptr)
{
[Window orderOut:Window];
+ [Window restoreParentWindow];
}
return S_OK;
@@ -392,30 +393,6 @@ protected:
}
};
-class ModalDisposable : public ComUnknownObject
-{
- NSModalSession _session;
- AvnWindow* _window;
-
- void Dispose ()
- {
- [_window orderOut:_window];
- [NSApp endModalSession:_session];
- }
-
-public:
- ModalDisposable(AvnWindow* window, NSModalSession session)
- {
- _session = session;
- _window = window;
- }
-
- virtual ~ModalDisposable()
- {
- Dispose();
- }
-};
-
class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, public IWindowStateChanged
{
private:
@@ -444,32 +421,27 @@ private:
{
@autoreleasepool
{
+ if([Window parentWindow] != nil)
+ [[Window parentWindow] removeChildWindow:Window];
WindowBaseImpl::Show();
return SetWindowState(_lastWindowState);
}
}
- virtual HRESULT ShowDialog (IUnknown**ppv) override
+ virtual HRESULT ShowDialog (IAvnWindow* parent) override
{
@autoreleasepool
{
- if(ppv == nullptr)
- {
+ if(parent == nullptr)
return E_POINTER;
- }
-
- auto session = [NSApp beginModalSessionForWindow:Window];
- auto disposable = new ModalDisposable(Window, session);
- *ppv = disposable;
-
- SetPosition(lastPositionSet);
- UpdateStyle();
-
- [Window setTitle:_lastTitle];
- [Window setTitleVisibility:NSWindowTitleVisible];
+
+ auto cparent = dynamic_cast(parent);
+ if(cparent == nullptr)
+ return E_INVALIDARG;
- [Window pollModalSession:session];
+ [cparent->Window addChildWindow:Window ordered:NSWindowAbove];
+ WindowBaseImpl::Show();
return S_OK;
}
@@ -843,8 +815,19 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
[super viewDidChangeBackingProperties];
}
+- (bool) ignoreUserInput
+{
+ auto parentWindow = objc_cast([self window]);
+ if(parentWindow == nil || ![parentWindow shouldTryToHandleEvents])
+ return TRUE;
+ return FALSE;
+}
+
- (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type
{
+ if([self ignoreUserInput])
+ return;
+
[self becomeFirstResponder];
auto localPoint = [self convertPoint:[event locationInWindow] toView:self];
auto avnPoint = [self toAvnPoint:localPoint];
@@ -952,7 +935,9 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
}
- (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type
-{
+{
+ if([self ignoreUserInput])
+ return;
auto key = s_KeyMap[[event keyCode]];
auto timestamp = [event timestamp] * 1000;
@@ -1125,13 +1110,15 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
{
ComPtr parent = _parent;
_parent = NULL;
+ [self restoreParentWindow];
parent->BaseEvents->Closed();
[parent->View onClosed];
- [self setContentView: nil];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self setContentView: nil];
+ });
}
}
-
-(BOOL)canBecomeKeyWindow
{
return _canBecomeKeyAndMain;
@@ -1142,12 +1129,62 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
return _canBecomeKeyAndMain;
}
+-(bool) activateAppropriateChild: (bool)activating
+{
+ for(NSWindow* uch in [self childWindows])
+ {
+ auto ch = objc_cast(uch);
+ if(ch == nil)
+ continue;
+ [ch activateAppropriateChild:false];
+ return FALSE;
+ }
+
+ if(!activating)
+ [self makeKeyAndOrderFront:self];
+ return TRUE;
+}
+
+-(bool)shouldTryToHandleEvents
+{
+ for(NSWindow* uch in [self childWindows])
+ {
+ auto ch = objc_cast(uch);
+ if(ch == nil)
+ continue;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+-(void)makeKeyWindow
+{
+ if([self activateAppropriateChild: true])
+ {
+ [super makeKeyWindow];
+ }
+}
+
-(void)becomeKeyWindow
{
- _parent->BaseEvents->Activated();
- [super becomeKeyWindow];
+ if([self activateAppropriateChild: true])
+ {
+ _parent->BaseEvents->Activated();
+ [super becomeKeyWindow];
+ }
+}
+
+-(void) restoreParentWindow;
+{
+ auto parent = objc_cast([self parentWindow]);
+ if(parent != nil)
+ {
+ [parent removeChildWindow:self];
+ [parent activateAppropriateChild: false];
+ }
}
+
- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame
{
return true;
diff --git a/samples/ControlCatalog.Desktop/Program.cs b/samples/ControlCatalog.Desktop/Program.cs
index a2048005a4..329b2ab5a3 100644
--- a/samples/ControlCatalog.Desktop/Program.cs
+++ b/samples/ControlCatalog.Desktop/Program.cs
@@ -22,7 +22,7 @@ namespace ControlCatalog
/// This method is needed for IDE previewer infrastructure
///
public static AppBuilder BuildAvaloniaApp()
- => AppBuilder.Configure().LogToDebug().UsePlatformDetect();
+ => AppBuilder.Configure().LogToDebug().UsePlatformDetect().UseReactiveUI();
private static void ConfigureAssetAssembly(AppBuilder builder)
{
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index ec3bf799b4..7c2ae441d0 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -1,33 +1,41 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ Background="{DynamicResource ThemeBackgroundBrush}"
+ Foreground="{DynamicResource ThemeForegroundBrush}"
+ FontSize="{DynamicResource FontSizeNormal}">
+
+
+ Light
+ Dark
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/MainView.xaml.cs b/samples/ControlCatalog/MainView.xaml.cs
index 0be5d25a09..a498b17bdd 100644
--- a/samples/ControlCatalog/MainView.xaml.cs
+++ b/samples/ControlCatalog/MainView.xaml.cs
@@ -2,6 +2,7 @@ using System.Collections;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
+using Avalonia.Markup.Xaml.Styling;
using Avalonia.Platform;
using ControlCatalog.Pages;
@@ -27,6 +28,22 @@ namespace ControlCatalog
});
}
+ var light = AvaloniaXamlLoader.Parse(@"");
+ var dark = AvaloniaXamlLoader.Parse(@"");
+ var themes = this.Find("Themes");
+ themes.SelectionChanged += (sender, e) =>
+ {
+ switch (themes.SelectedIndex)
+ {
+ case 0:
+ Styles[0] = light;
+ break;
+ case 1:
+ Styles[0] = dark;
+ break;
+ }
+ };
+ Styles.Add(light);
}
private void InitializeComponent()
diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml b/samples/ControlCatalog/Pages/DialogsPage.xaml
index 710d791f3a..353edce51c 100644
--- a/samples/ControlCatalog/Pages/DialogsPage.xaml
+++ b/samples/ControlCatalog/Pages/DialogsPage.xaml
@@ -3,10 +3,7 @@
-
-
- Modal to window
-
+
diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
index 8b3e810f0a..e380c677c9 100644
--- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
@@ -31,12 +31,18 @@ namespace ControlCatalog.Pages
}.ShowAsync(GetWindow());
};
this.FindControl