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/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