From fb14118771eeb34f51146e23def0a1f94a49fbad Mon Sep 17 00:00:00 2001 From: attila Date: Thu, 4 Jan 2024 17:44:00 +0100 Subject: [PATCH] MacOS: Disable window controls for windows created by JUCE when a Component is modal The change does not affect plugin windows, which are created by the host. --- .../components/juce_ModalComponentManager.cpp | 5 +++ .../detail/juce_ComponentHelpers.h | 25 +++++++++++++++ .../native/juce_NSViewComponentPeer_mac.mm | 31 ++++++++++++++++++- 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp b/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp index e8ecfec5fc..857567192c 100644 --- a/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp +++ b/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp @@ -106,7 +106,10 @@ JUCE_IMPLEMENT_SINGLETON (ModalComponentManager) void ModalComponentManager::startModal (Component* component, bool autoDelete) { if (component != nullptr) + { stack.add (new ModalItem (component, autoDelete)); + detail::ComponentHelpers::ModalComponentManagerChangeNotifier::getInstance().modalComponentManagerChanged(); + } } void ModalComponentManager::attachCallback (Component* component, Callback* callback) @@ -210,6 +213,8 @@ void ModalComponentManager::handleAsyncUpdate() item->callbacks.getUnchecked (j)->modalStateFinished (item->returnValue); compToDelete.deleteAndZero(); + + detail::ComponentHelpers::ModalComponentManagerChangeNotifier::getInstance().modalComponentManagerChanged(); } } } diff --git a/modules/juce_gui_basics/detail/juce_ComponentHelpers.h b/modules/juce_gui_basics/detail/juce_ComponentHelpers.h index b815cfb8f8..aa3067b4a8 100644 --- a/modules/juce_gui_basics/detail/juce_ComponentHelpers.h +++ b/modules/juce_gui_basics/detail/juce_ComponentHelpers.h @@ -250,6 +250,31 @@ struct ComponentHelpers if (modalWouldBlockComponent (*c, &modal)) (c->*function) (ms, SH::screenPosToLocalPos (*c, ms.getScreenPosition()), Time::getCurrentTime()); } + + class ModalComponentManagerChangeNotifier + { + public: + static auto& getInstance() + { + static ModalComponentManagerChangeNotifier instance; + return instance; + } + + ErasedScopeGuard addListener (std::function l) + { + return listeners.addListener (std::move (l)); + } + + void modalComponentManagerChanged() + { + listeners.call(); + } + + private: + ModalComponentManagerChangeNotifier() = default; + + detail::CallbackListenerList<> listeners; + }; }; } // namespace juce::detail diff --git a/modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm b/modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm index c35b78ac28..da1a462bcf 100644 --- a/modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm +++ b/modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm @@ -1712,7 +1712,7 @@ public: NSWindow* window = nil; NSView* view = nil; WeakReference safeComponent; - bool isSharedWindow = false; + const bool isSharedWindow = false; #if USE_COREGRAPHICS_RENDERING bool usingCoreGraphics = true; #else @@ -1998,10 +1998,39 @@ private: #endif } + void modalComponentManagerChanged() + { + if (isSharedWindow) + return; + + auto style = [window styleMask]; + + if (ModalComponentManager::getInstance()->getNumModalComponents() > 0) + { + style &= ~NSWindowStyleMaskMiniaturizable; + style &= ~NSWindowStyleMaskClosable; + } + else + { + const auto flags = getStyleFlags(); + + if ((flags & windowHasMinimiseButton) != 0) style |= NSWindowStyleMaskMiniaturizable; + if ((flags & windowHasCloseButton) != 0) style |= NSWindowStyleMaskClosable; + } + + [window setStyleMask: style]; + } + //============================================================================== std::vector scopedObservers; std::vector windowObservers; + ErasedScopeGuard modalChangeListenerScope = + detail::ComponentHelpers::ModalComponentManagerChangeNotifier::getInstance().addListener ([this] + { + modalComponentManagerChanged(); + }); + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NSViewComponentPeer) };