diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm index 53982ad4e7..d673523983 100644 --- a/native/Avalonia.Native/src/OSX/AvnWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm @@ -32,6 +32,7 @@ bool _isEnabled; bool _canBecomeKeyWindow; bool _isExtended; + bool _isTransitioningToFullScreen; AvnMenu* _menu; } @@ -174,6 +175,7 @@ [self setBackgroundColor: [NSColor clearColor]]; _isExtended = false; + _isTransitioningToFullScreen = false; if(self.isDialog) { @@ -348,6 +350,7 @@ - (void)windowWillEnterFullScreen:(NSNotification *_Nonnull)notification { + _isTransitioningToFullScreen = true; auto parent = dynamic_cast(_parent.operator->()); if(parent != nullptr) @@ -358,6 +361,7 @@ - (void)windowDidEnterFullScreen:(NSNotification *_Nonnull)notification { + _isTransitioningToFullScreen = false; auto parent = dynamic_cast(_parent.operator->()); if(parent != nullptr) @@ -440,7 +444,10 @@ _parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, static_cast([event timestamp] * 1000), AvnInputModifiersNone, point, delta); } - _parent->BringToFront(); + if(!_isTransitioningToFullScreen) + { + _parent->BringToFront(); + } } break; diff --git a/native/Avalonia.Native/src/OSX/PopupImpl.mm b/native/Avalonia.Native/src/OSX/PopupImpl.mm index 7ed780359d..b29b44b6cc 100644 --- a/native/Avalonia.Native/src/OSX/PopupImpl.mm +++ b/native/Avalonia.Native/src/OSX/PopupImpl.mm @@ -25,17 +25,13 @@ private: PopupImpl(IAvnWindowEvents* events, IAvnGlContext* gl) : WindowBaseImpl(events, gl) { WindowEvents = events; + [Window setLevel:NSPopUpMenuWindowLevel]; } protected: virtual NSWindowStyleMask GetStyle() override { return NSWindowStyleMaskBorderless; } - - virtual void OnInitialiseNSWindow () override - { - [Window setLevel:NSPopUpMenuWindowLevel]; - } public: virtual bool ShouldTakeFocusOnShow() override diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h index 040ba39b6d..787827c9b4 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h @@ -106,8 +106,6 @@ protected: virtual NSWindowStyleMask GetStyle(); void UpdateStyle(); - - virtual void OnInitialiseNSWindow (); private: void CreateNSWindow (bool isDialog); diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index 067383349f..289694a9b8 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -89,8 +89,6 @@ HRESULT WindowBaseImpl::Show(bool activate, bool isDialog) { START_COM_CALL; @autoreleasepool { - InitialiseNSWindow(); - if(hasPosition) { SetPosition(lastPositionSet); @@ -568,11 +566,6 @@ void WindowBaseImpl::CreateNSWindow(bool isDialog) { } } -void WindowBaseImpl::OnInitialiseNSWindow() -{ - -} - void WindowBaseImpl::InitialiseNSWindow() { if(Window != nullptr) { [Window setContentView:StandardContainer]; @@ -595,8 +588,6 @@ void WindowBaseImpl::InitialiseNSWindow() { [GetWindowProtocol() showWindowMenuWithAppMenu]; } } - - OnInitialiseNSWindow(); } } diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.h b/native/Avalonia.Native/src/OSX/WindowImpl.h index 76d5cbf6ea..b4b1d4e70b 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowImpl.h @@ -13,6 +13,7 @@ class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, public IWindowStateChanged { private: + bool _isEnabled; bool _canResize; bool _fullScreenActive; SystemDecorations _decorations; @@ -92,8 +93,6 @@ BEGIN_INTERFACE_MAP() virtual bool IsDialog() override; - virtual void OnInitialiseNSWindow() override; - virtual void BringToFront () override; bool CanBecomeKeyWindow (); @@ -102,6 +101,7 @@ protected: virtual NSWindowStyleMask GetStyle() override; private: + void OnInitialiseNSWindow(); NSString *_lastTitle; }; diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index 9d4d0b8e21..782c8b80dc 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -9,6 +9,7 @@ #include "WindowProtocol.h" WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBaseImpl(events, gl) { + _isEnabled = true; _children = std::list(); _isClientAreaExtended = false; _extendClientHints = AvnDefaultChrome; @@ -22,6 +23,8 @@ WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBase _lastTitle = @""; _parent = nullptr; WindowEvents = events; + + OnInitialiseNSWindow(); } void WindowImpl::HideOrShowTrafficLights() { @@ -30,15 +33,16 @@ void WindowImpl::HideOrShowTrafficLights() { } bool wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome); - bool hasTrafficLights = _isClientAreaExtended ? !wantsChrome : _decorations != SystemDecorationsFull; + bool hasTrafficLights = _isClientAreaExtended ? wantsChrome : _decorations == SystemDecorationsFull; - [[Window standardWindowButton:NSWindowCloseButton] setHidden:hasTrafficLights]; - [[Window standardWindowButton:NSWindowMiniaturizeButton] setHidden:hasTrafficLights]; - [[Window standardWindowButton:NSWindowZoomButton] setHidden:hasTrafficLights]; + [[Window standardWindowButton:NSWindowCloseButton] setHidden:!hasTrafficLights]; + [[Window standardWindowButton:NSWindowMiniaturizeButton] setHidden:!hasTrafficLights]; + [[Window standardWindowButton:NSWindowZoomButton] setHidden:!hasTrafficLights]; } void WindowImpl::OnInitialiseNSWindow(){ [GetWindowProtocol() setCanBecomeKeyWindow:true]; + [Window disableCursorRects]; [Window setTabbingMode:NSWindowTabbingModeDisallowed]; [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; @@ -75,7 +79,9 @@ HRESULT WindowImpl::SetEnabled(bool enable) { START_COM_CALL; @autoreleasepool { + _isEnabled = enable; [GetWindowProtocol() setEnabled:enable]; + UpdateStyle(); return S_OK; } } @@ -87,11 +93,8 @@ HRESULT WindowImpl::SetParent(IAvnWindow *parent) { if(_parent != nullptr) { _parent->_children.remove(this); - auto parent = _parent; - dispatch_async(dispatch_get_main_queue(), ^{ - parent->BringToFront(); - }); + _parent->BringToFront(); } auto cparent = dynamic_cast(parent); @@ -118,20 +121,23 @@ HRESULT WindowImpl::SetParent(IAvnWindow *parent) { void WindowImpl::BringToFront() { - if(IsDialog()) + if(Window != nullptr) { - Activate(); - } - else - { - [Window orderFront:nullptr]; - } - - [Window invalidateShadow]; - - for(auto iterator = _children.begin(); iterator != _children.end(); iterator++) - { - (*iterator)->BringToFront(); + if(IsDialog()) + { + Activate(); + } + else + { + [Window orderFront:nullptr]; + } + + [Window invalidateShadow]; + + for(auto iterator = _children.begin(); iterator != _children.end(); iterator++) + { + (*iterator)->BringToFront(); + } } } @@ -560,6 +566,11 @@ bool WindowImpl::IsDialog() { NSWindowStyleMask WindowImpl::GetStyle() { unsigned long s = NSWindowStyleMaskBorderless; + + if(_actualWindowState == FullScreen) + { + s |= NSWindowStyleMaskFullScreen; + } switch (_decorations) { case SystemDecorationsNone: @@ -573,7 +584,7 @@ NSWindowStyleMask WindowImpl::GetStyle() { case SystemDecorationsFull: s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable; - if (_canResize) { + if (_canResize && _isEnabled) { s = s | NSWindowStyleMaskResizable; } break; diff --git a/samples/ControlCatalog/MainWindow.xaml.cs b/samples/ControlCatalog/MainWindow.xaml.cs index dd62698cc7..3bad18c815 100644 --- a/samples/ControlCatalog/MainWindow.xaml.cs +++ b/samples/ControlCatalog/MainWindow.xaml.cs @@ -32,8 +32,6 @@ namespace ControlCatalog DataContext = new MainWindowViewModel(_notificationArea); _recentMenu = ((NativeMenu.GetMenu(this).Items[0] as NativeMenuItem).Menu.Items[2] as NativeMenuItem).Menu; - - ExtendClientAreaChromeHints = Avalonia.Platform.ExtendClientAreaChromeHints.OSXThickTitleBar; } public static string MenuQuitHeader => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "Quit Avalonia" : "E_xit"; diff --git a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs index bdabfbd6c8..0c1eed7534 100644 --- a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs +++ b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs @@ -221,7 +221,7 @@ namespace Avalonia.Controls.Primitives ((ISetLogicalParent)Popup).SetParent(null); } - if (Popup.PlacementTarget != placementTarget) + if (Popup.Parent == null || Popup.PlacementTarget != placementTarget) { Popup.PlacementTarget = Target = placementTarget; ((ISetLogicalParent)Popup).SetParent(placementTarget); diff --git a/tests/Avalonia.Controls.UnitTests/FlyoutTests.cs b/tests/Avalonia.Controls.UnitTests/FlyoutTests.cs index 8b77074960..776b4508c2 100644 --- a/tests/Avalonia.Controls.UnitTests/FlyoutTests.cs +++ b/tests/Avalonia.Controls.UnitTests/FlyoutTests.cs @@ -451,6 +451,28 @@ namespace Avalonia.Controls.UnitTests Assert.Null(popup.Parent); } } + + [Fact] + public void Should_Reset_Popup_Parent_On_Target_Attach_Following_Detach() + { + using (CreateServicesWithFocus()) + { + var userControl = new UserControl(); + var window = PreparedWindow(userControl); + window.Show(); + + var flyout = new TestFlyout(); + flyout.ShowAt(userControl); + + var popup = Assert.IsType(flyout.Popup); + Assert.NotNull(popup.Parent); + + flyout.Hide(); + + flyout.ShowAt(userControl); + Assert.NotNull(popup.Parent); + } + } [Fact] public void ContextFlyout_Can_Be_Set_In_Styles()