|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2022 - Raw Material Software Limited
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- By using JUCE, you agree to the terms of both the JUCE 7 End-User License
- Agreement and JUCE Privacy Policy.
-
- End User License Agreement: www.juce.com/juce-7-licence
- Privacy Policy: www.juce.com/juce-privacy-policy
-
- Or: You may also use this code under the terms of the GPL v3 (see
- www.gnu.org/licenses).
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce
- {
-
- /*
- Instances of this type can show and dismiss a message box.
-
- This is an interface rather than a concrete type so that platforms can pick an implementation at
- runtime if necessary.
- */
- struct ScopedMessageBoxInterface
- {
- virtual ~ScopedMessageBoxInterface() = default;
-
- /* Shows the message box.
-
- When the message box exits normally, it should send the result to the passed-in function.
- The passed-in function is safe to call from any thread at any time.
- */
- virtual void runAsync (std::function<void (int)>) = 0;
-
- /* Shows the message box and blocks. */
- virtual int runSync() = 0;
-
- /* Forcefully closes the message box.
-
- This will be called when the message box handle has fallen out of scope.
- If the message box has already been closed by the user, this shouldn't do anything.
- */
- virtual void close() = 0;
-
- /* Implemented differently for each platform. */
- static std::unique_ptr<ScopedMessageBoxInterface> create (const MessageBoxOptions& options);
- };
-
- //==============================================================================
- class ScopedMessageBox::Pimpl : private AsyncUpdater
- {
- public:
- static ScopedMessageBox show (std::unique_ptr<ScopedMessageBoxInterface>&& native, std::function<void (int)> callback)
- {
- return ScopedMessageBox (runAsync (std::move (native), rawToUniquePtr (ModalCallbackFunction::create (std::move (callback)))));
- }
-
- static int showUnmanaged (std::unique_ptr<ScopedMessageBoxInterface>&& native,
- ModalComponentManager::Callback* cb)
- {
- #if JUCE_MODAL_LOOPS_PERMITTED
- if (cb == nullptr)
- return runSync (std::move (native));
- #endif
-
- runAsync (std::move (native), rawToUniquePtr (cb));
-
- return 0;
- }
-
- ~Pimpl() override
- {
- cancelPendingUpdate();
- }
-
- void close()
- {
- cancelPendingUpdate();
- nativeImplementation->close();
- self.reset();
- }
-
- private:
- static std::shared_ptr<Pimpl> runAsync (std::unique_ptr<ScopedMessageBoxInterface>&& p,
- std::unique_ptr<ModalComponentManager::Callback>&& c)
- {
- std::shared_ptr<Pimpl> result (new Pimpl (std::move (p), std::move (c)));
- result->self = result;
- result->triggerAsyncUpdate();
- return result;
- }
-
- static int runSync (std::unique_ptr<ScopedMessageBoxInterface>&& p)
- {
- auto local = std::move (p);
- return local != nullptr ? local->runSync() : 0;
- }
-
- explicit Pimpl (std::unique_ptr<ScopedMessageBoxInterface>&& p)
- : Pimpl (std::move (p), nullptr) {}
-
- Pimpl (std::unique_ptr<ScopedMessageBoxInterface>&& p,
- std::unique_ptr<ModalComponentManager::Callback>&& c)
- : callback (std::move (c)), nativeImplementation (std::move (p)) {}
-
- void handleAsyncUpdate() override
- {
- nativeImplementation->runAsync ([weakRecipient = std::weak_ptr<Pimpl> (self)] (int result)
- {
- const auto notifyRecipient = [result, weakRecipient]
- {
- if (const auto locked = weakRecipient.lock())
- {
- if (auto* cb = locked->callback.get())
- cb->modalStateFinished (result);
-
- locked->self.reset();
- }
- };
-
- if (MessageManager::getInstance()->isThisTheMessageThread())
- notifyRecipient();
- else
- MessageManager::callAsync (notifyRecipient);
- });
- }
-
- std::unique_ptr<ModalComponentManager::Callback> callback;
- std::unique_ptr<ScopedMessageBoxInterface> nativeImplementation;
-
- /* The 'old' native message box API doesn't have a concept of message box owners.
- Instead, message boxes have to clean up after themselves, once they're done displaying.
- To allow this mode of usage, the implementation keeps an owning reference to itself,
- which is cleared once the message box is closed or asked to quit. To display a native
- message box without a scoped lifetime, just create a Pimpl instance without using
- the ScopedMessageBox wrapper, and the Pimpl will destroy itself after it is dismissed.
- */
- std::shared_ptr<Pimpl> self;
- };
-
- //==============================================================================
- ScopedMessageBox::ScopedMessageBox() = default;
-
- ScopedMessageBox::ScopedMessageBox (std::shared_ptr<Pimpl> p)
- : pimpl (std::move (p)) {}
-
- ScopedMessageBox::~ScopedMessageBox() noexcept
- {
- close();
- }
-
- ScopedMessageBox::ScopedMessageBox (ScopedMessageBox&& other) noexcept
- : pimpl (std::exchange (other.pimpl, nullptr)) {}
-
- ScopedMessageBox& ScopedMessageBox::operator= (ScopedMessageBox&& other) noexcept
- {
- ScopedMessageBox temp (std::move (other));
- std::swap (temp.pimpl, pimpl);
- return *this;
- }
-
- void ScopedMessageBox::close()
- {
- if (pimpl != nullptr)
- pimpl->close();
-
- pimpl.reset();
- }
-
- } // namespace juce
|