upgrade to JUCE 5.4.3. Remove (probably) unused JUCE modules. Remove VST2 target (it's been end-of-life'd by Steinberg and by JUCE)
This commit is contained in:
		@ -35,7 +35,7 @@ public:
 | 
			
		||||
 | 
			
		||||
    void messageCallback() override
 | 
			
		||||
    {
 | 
			
		||||
        if (const ActionBroadcaster* const b = broadcaster)
 | 
			
		||||
        if (auto b = broadcaster.get())
 | 
			
		||||
            if (b->actionListeners.contains (listener))
 | 
			
		||||
                listener->actionListenerCallback (message);
 | 
			
		||||
    }
 | 
			
		||||
@ -52,13 +52,13 @@ private:
 | 
			
		||||
ActionBroadcaster::ActionBroadcaster()
 | 
			
		||||
{
 | 
			
		||||
    // are you trying to create this object before or after juce has been intialised??
 | 
			
		||||
    jassert (MessageManager::getInstanceWithoutCreating() != nullptr);
 | 
			
		||||
    JUCE_ASSERT_MESSAGE_MANAGER_EXISTS
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ActionBroadcaster::~ActionBroadcaster()
 | 
			
		||||
{
 | 
			
		||||
    // all event-based objects must be deleted BEFORE juce is shut down!
 | 
			
		||||
    jassert (MessageManager::getInstanceWithoutCreating() != nullptr);
 | 
			
		||||
    JUCE_ASSERT_MESSAGE_MANAGER_EXISTS
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ActionBroadcaster::addActionListener (ActionListener* const listener)
 | 
			
		||||
 | 
			
		||||
@ -35,7 +35,7 @@ class JUCE_API  ActionListener
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    virtual ~ActionListener()  {}
 | 
			
		||||
    virtual ~ActionListener() = default;
 | 
			
		||||
 | 
			
		||||
    /** Overridden by your subclass to receive the callback.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,7 @@ public:
 | 
			
		||||
//==============================================================================
 | 
			
		||||
AsyncUpdater::AsyncUpdater()
 | 
			
		||||
{
 | 
			
		||||
    activeMessage = new AsyncUpdaterMessage (*this);
 | 
			
		||||
    activeMessage = *new AsyncUpdaterMessage (*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AsyncUpdater::~AsyncUpdater()
 | 
			
		||||
@ -63,7 +63,7 @@ void AsyncUpdater::triggerAsyncUpdate()
 | 
			
		||||
{
 | 
			
		||||
    // If you're calling this before (or after) the MessageManager is
 | 
			
		||||
    // running, then you're not going to get any callbacks!
 | 
			
		||||
    jassert (MessageManager::getInstanceWithoutCreating() != nullptr);
 | 
			
		||||
    JUCE_ASSERT_MESSAGE_MANAGER_EXISTS
 | 
			
		||||
 | 
			
		||||
    if (activeMessage->shouldDeliver.compareAndSetBool (1, 0))
 | 
			
		||||
        if (! activeMessage->post())
 | 
			
		||||
@ -79,7 +79,7 @@ void AsyncUpdater::cancelPendingUpdate() noexcept
 | 
			
		||||
void AsyncUpdater::handleUpdateNowIfNeeded()
 | 
			
		||||
{
 | 
			
		||||
    // This can only be called by the event thread.
 | 
			
		||||
    jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
 | 
			
		||||
    JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
 | 
			
		||||
 | 
			
		||||
    if (activeMessage->shouldDeliver.exchange (0) != 0)
 | 
			
		||||
        handleAsyncUpdate();
 | 
			
		||||
 | 
			
		||||
@ -36,7 +36,7 @@ void ChangeBroadcaster::addChangeListener (ChangeListener* const listener)
 | 
			
		||||
{
 | 
			
		||||
    // Listeners can only be safely added when the event thread is locked
 | 
			
		||||
    // You can  use a MessageManagerLock if you need to call this from another thread.
 | 
			
		||||
    jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
 | 
			
		||||
    JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
 | 
			
		||||
 | 
			
		||||
    changeListeners.add (listener);
 | 
			
		||||
}
 | 
			
		||||
@ -45,7 +45,7 @@ void ChangeBroadcaster::removeChangeListener (ChangeListener* const listener)
 | 
			
		||||
{
 | 
			
		||||
    // Listeners can only be safely removed when the event thread is locked
 | 
			
		||||
    // You can  use a MessageManagerLock if you need to call this from another thread.
 | 
			
		||||
    jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
 | 
			
		||||
    JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
 | 
			
		||||
 | 
			
		||||
    changeListeners.remove (listener);
 | 
			
		||||
}
 | 
			
		||||
@ -54,7 +54,7 @@ void ChangeBroadcaster::removeAllChangeListeners()
 | 
			
		||||
{
 | 
			
		||||
    // Listeners can only be safely removed when the event thread is locked
 | 
			
		||||
    // You can  use a MessageManagerLock if you need to call this from another thread.
 | 
			
		||||
    jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
 | 
			
		||||
    JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
 | 
			
		||||
 | 
			
		||||
    changeListeners.clear();
 | 
			
		||||
}
 | 
			
		||||
@ -68,7 +68,7 @@ void ChangeBroadcaster::sendChangeMessage()
 | 
			
		||||
void ChangeBroadcaster::sendSynchronousChangeMessage()
 | 
			
		||||
{
 | 
			
		||||
    // This can only be called by the event thread.
 | 
			
		||||
    jassert (MessageManager::getInstance()->isThisTheMessageThread());
 | 
			
		||||
    JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
 | 
			
		||||
 | 
			
		||||
    broadcastCallback.cancelPendingUpdate();
 | 
			
		||||
    callListeners();
 | 
			
		||||
 | 
			
		||||
@ -45,7 +45,7 @@ class JUCE_API  ChangeListener
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    virtual ~ChangeListener()  {}
 | 
			
		||||
    virtual ~ChangeListener() = default;
 | 
			
		||||
 | 
			
		||||
    /** Your subclass should implement this method to receive the callback.
 | 
			
		||||
        @param source the ChangeBroadcaster that triggered the callback.
 | 
			
		||||
 | 
			
		||||
@ -94,7 +94,7 @@ struct ChildProcessMaster::Connection  : public InterprocessConnection,
 | 
			
		||||
            startThread (4);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Connection()
 | 
			
		||||
    ~Connection() override
 | 
			
		||||
    {
 | 
			
		||||
        stopThread (10000);
 | 
			
		||||
    }
 | 
			
		||||
@ -192,7 +192,7 @@ struct ChildProcessSlave::Connection  : public InterprocessConnection,
 | 
			
		||||
        startThread (4);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Connection()
 | 
			
		||||
    ~Connection() override
 | 
			
		||||
    {
 | 
			
		||||
        stopThread (10000);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -104,8 +104,6 @@ public:
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    struct Connection;
 | 
			
		||||
    friend struct Connection;
 | 
			
		||||
    friend struct ContainerDeletePolicy<Connection>;
 | 
			
		||||
    std::unique_ptr<Connection> connection;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcessSlave)
 | 
			
		||||
@ -194,8 +192,6 @@ private:
 | 
			
		||||
    std::unique_ptr<ChildProcess> childProcess;
 | 
			
		||||
 | 
			
		||||
    struct Connection;
 | 
			
		||||
    friend struct Connection;
 | 
			
		||||
    friend struct ContainerDeletePolicy<Connection>;
 | 
			
		||||
    std::unique_ptr<Connection> connection;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcessMaster)
 | 
			
		||||
 | 
			
		||||
@ -59,6 +59,7 @@ bool InterprocessConnection::connectToSocket (const String& hostName,
 | 
			
		||||
 | 
			
		||||
    if (socket->connect (hostName, portNumber, timeOutMillisecs))
 | 
			
		||||
    {
 | 
			
		||||
        threadIsRunning = true;
 | 
			
		||||
        connectionMadeInt();
 | 
			
		||||
        thread->startThread();
 | 
			
		||||
        return true;
 | 
			
		||||
@ -130,7 +131,7 @@ bool InterprocessConnection::isConnected() const
 | 
			
		||||
 | 
			
		||||
    return ((socket != nullptr && socket->isConnected())
 | 
			
		||||
              || (pipe != nullptr && pipe->isOpen()))
 | 
			
		||||
            && thread->isThreadRunning();
 | 
			
		||||
            && threadIsRunning;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String InterprocessConnection::getConnectedHostName() const
 | 
			
		||||
@ -179,6 +180,8 @@ void InterprocessConnection::initialiseWithSocket (StreamingSocket* newSocket)
 | 
			
		||||
{
 | 
			
		||||
    jassert (socket == nullptr && pipe == nullptr);
 | 
			
		||||
    socket.reset (newSocket);
 | 
			
		||||
 | 
			
		||||
    threadIsRunning = true;
 | 
			
		||||
    connectionMadeInt();
 | 
			
		||||
    thread->startThread();
 | 
			
		||||
}
 | 
			
		||||
@ -187,6 +190,8 @@ void InterprocessConnection::initialiseWithPipe (NamedPipe* newPipe)
 | 
			
		||||
{
 | 
			
		||||
    jassert (socket == nullptr && pipe == nullptr);
 | 
			
		||||
    pipe.reset (newPipe);
 | 
			
		||||
 | 
			
		||||
    threadIsRunning = true;
 | 
			
		||||
    connectionMadeInt();
 | 
			
		||||
    thread->startThread();
 | 
			
		||||
}
 | 
			
		||||
@ -366,6 +371,8 @@ void InterprocessConnection::runThread()
 | 
			
		||||
        if (thread->threadShouldExit() || ! readNextMessage())
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    threadIsRunning = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 | 
			
		||||
@ -197,9 +197,9 @@ private:
 | 
			
		||||
    int readData (void*, int);
 | 
			
		||||
 | 
			
		||||
    struct ConnectionThread;
 | 
			
		||||
    friend struct ConnectionThread;
 | 
			
		||||
    friend struct ContainerDeletePolicy<ConnectionThread>;
 | 
			
		||||
    std::unique_ptr<ConnectionThread> thread;
 | 
			
		||||
    std::atomic<bool> threadIsRunning { false };
 | 
			
		||||
 | 
			
		||||
    void runThread();
 | 
			
		||||
    int writeData (void*, int);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -45,7 +45,7 @@ public:
 | 
			
		||||
    InterprocessConnectionServer();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~InterprocessConnectionServer();
 | 
			
		||||
    ~InterprocessConnectionServer() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Starts an internal thread which listens on the given port number.
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,190 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2017 - ROLI Ltd.
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   The code included in this file is provided under the terms of the ISC license
 | 
			
		||||
   http://www.isc.org/downloads/software-support-policy/isc-license. Permission
 | 
			
		||||
   To use, copy, modify, and/or distribute this software for any purpose with or
 | 
			
		||||
   without fee is hereby granted provided that the above copyright notice and
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
NetworkServiceDiscovery::Advertiser::Advertiser (const String& serviceTypeUID,
 | 
			
		||||
                                                 const String& serviceDescription,
 | 
			
		||||
                                                 int broadcastPortToUse, int connectionPort,
 | 
			
		||||
                                                 RelativeTime minTimeBetweenBroadcasts)
 | 
			
		||||
    : Thread ("Discovery_broadcast"),
 | 
			
		||||
      message (serviceTypeUID), broadcastPort (broadcastPortToUse),
 | 
			
		||||
      minInterval (minTimeBetweenBroadcasts)
 | 
			
		||||
{
 | 
			
		||||
    message.setAttribute ("id", Uuid().toString());
 | 
			
		||||
    message.setAttribute ("name", serviceDescription);
 | 
			
		||||
    message.setAttribute ("address", String());
 | 
			
		||||
    message.setAttribute ("port", connectionPort);
 | 
			
		||||
 | 
			
		||||
    startThread (2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NetworkServiceDiscovery::Advertiser::~Advertiser()
 | 
			
		||||
{
 | 
			
		||||
    stopThread (2000);
 | 
			
		||||
    socket.shutdown();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NetworkServiceDiscovery::Advertiser::run()
 | 
			
		||||
{
 | 
			
		||||
    if (! socket.bindToPort (0))
 | 
			
		||||
    {
 | 
			
		||||
        jassertfalse;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (! threadShouldExit())
 | 
			
		||||
    {
 | 
			
		||||
        sendBroadcast();
 | 
			
		||||
        wait ((int) minInterval.inMilliseconds());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NetworkServiceDiscovery::Advertiser::sendBroadcast()
 | 
			
		||||
{
 | 
			
		||||
    auto localAddress = IPAddress::getLocalAddress();
 | 
			
		||||
    message.setAttribute ("address", localAddress.toString());
 | 
			
		||||
    auto broadcastAddress = IPAddress::getInterfaceBroadcastAddress (localAddress);
 | 
			
		||||
    auto data = message.createDocument ({}, true, false);
 | 
			
		||||
    socket.write (broadcastAddress.toString(), broadcastPort, data.toRawUTF8(), (int) data.getNumBytesAsUTF8());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
NetworkServiceDiscovery::AvailableServiceList::AvailableServiceList (const String& serviceType, int broadcastPort)
 | 
			
		||||
    : Thread ("Discovery_listen"), serviceTypeUID (serviceType)
 | 
			
		||||
{
 | 
			
		||||
    socket.bindToPort (broadcastPort);
 | 
			
		||||
    startThread (2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NetworkServiceDiscovery::AvailableServiceList::~AvailableServiceList()
 | 
			
		||||
{
 | 
			
		||||
    socket.shutdown();
 | 
			
		||||
    stopThread (2000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NetworkServiceDiscovery::AvailableServiceList::run()
 | 
			
		||||
{
 | 
			
		||||
    while (! threadShouldExit())
 | 
			
		||||
    {
 | 
			
		||||
        if (socket.waitUntilReady (true, 200) == 1)
 | 
			
		||||
        {
 | 
			
		||||
            char buffer[1024];
 | 
			
		||||
            auto bytesRead = socket.read (buffer, sizeof (buffer) - 1, false);
 | 
			
		||||
 | 
			
		||||
            if (bytesRead > 10)
 | 
			
		||||
                if (auto xml = parseXML (String (CharPointer_UTF8 (buffer),
 | 
			
		||||
                                                 CharPointer_UTF8 (buffer + bytesRead))))
 | 
			
		||||
                    if (xml->hasTagName (serviceTypeUID))
 | 
			
		||||
                        handleMessage (*xml);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        removeTimedOutServices();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<NetworkServiceDiscovery::Service> NetworkServiceDiscovery::AvailableServiceList::getServices() const
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (listLock);
 | 
			
		||||
    auto listCopy = services;
 | 
			
		||||
    return listCopy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NetworkServiceDiscovery::AvailableServiceList::handleAsyncUpdate()
 | 
			
		||||
{
 | 
			
		||||
    if (onChange != nullptr)
 | 
			
		||||
        onChange();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NetworkServiceDiscovery::AvailableServiceList::handleMessage (const XmlElement& xml)
 | 
			
		||||
{
 | 
			
		||||
    Service service;
 | 
			
		||||
    service.instanceID = xml.getStringAttribute ("id");
 | 
			
		||||
 | 
			
		||||
    if (service.instanceID.trim().isNotEmpty())
 | 
			
		||||
    {
 | 
			
		||||
        service.description = xml.getStringAttribute ("name");
 | 
			
		||||
        service.address = IPAddress (xml.getStringAttribute ("address"));
 | 
			
		||||
        service.port = xml.getIntAttribute ("port");
 | 
			
		||||
        service.lastSeen = Time::getCurrentTime();
 | 
			
		||||
 | 
			
		||||
        handleMessage (service);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sortServiceList (std::vector<NetworkServiceDiscovery::Service>& services)
 | 
			
		||||
{
 | 
			
		||||
    auto compareServices = [] (const NetworkServiceDiscovery::Service& s1,
 | 
			
		||||
                               const NetworkServiceDiscovery::Service& s2)
 | 
			
		||||
    {
 | 
			
		||||
        return s1.instanceID < s2.instanceID;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    std::sort (services.begin(), services.end(), compareServices);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NetworkServiceDiscovery::AvailableServiceList::handleMessage (const Service& service)
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (listLock);
 | 
			
		||||
 | 
			
		||||
    for (auto& s : services)
 | 
			
		||||
    {
 | 
			
		||||
        if (s.instanceID == service.instanceID)
 | 
			
		||||
        {
 | 
			
		||||
            if (s.description != service.description
 | 
			
		||||
                 || s.address != service.address
 | 
			
		||||
                 || s.port != service.port)
 | 
			
		||||
            {
 | 
			
		||||
                s = service;
 | 
			
		||||
                triggerAsyncUpdate();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            s.lastSeen = service.lastSeen;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    services.push_back (service);
 | 
			
		||||
    sortServiceList (services);
 | 
			
		||||
    triggerAsyncUpdate();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NetworkServiceDiscovery::AvailableServiceList::removeTimedOutServices()
 | 
			
		||||
{
 | 
			
		||||
    const double timeoutSeconds = 5.0;
 | 
			
		||||
    auto oldestAllowedTime = Time::getCurrentTime() - RelativeTime::seconds (timeoutSeconds);
 | 
			
		||||
 | 
			
		||||
    const ScopedLock sl (listLock);
 | 
			
		||||
 | 
			
		||||
    auto oldEnd = std::end (services);
 | 
			
		||||
    auto newEnd = std::remove_if (std::begin (services), oldEnd,
 | 
			
		||||
                                  [=] (const Service& s) { return s.lastSeen < oldestAllowedTime; });
 | 
			
		||||
 | 
			
		||||
    if (newEnd != oldEnd)
 | 
			
		||||
    {
 | 
			
		||||
        services.erase (newEnd, oldEnd);
 | 
			
		||||
        triggerAsyncUpdate();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
							
								
								
									
										128
									
								
								modules/juce_events/interprocess/juce_NetworkServiceDiscovery.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								modules/juce_events/interprocess/juce_NetworkServiceDiscovery.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,128 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2017 - ROLI Ltd.
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   The code included in this file is provided under the terms of the ISC license
 | 
			
		||||
   http://www.isc.org/downloads/software-support-policy/isc-license. Permission
 | 
			
		||||
   To use, copy, modify, and/or distribute this software for any purpose with or
 | 
			
		||||
   without fee is hereby granted provided that the above copyright notice and
 | 
			
		||||
   this permission notice appear in all copies.
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Contains classes that implement a simple protocol for broadcasting the availability
 | 
			
		||||
    and location of a discoverable service on the local network, and for maintaining a
 | 
			
		||||
    list of known services.
 | 
			
		||||
*/
 | 
			
		||||
struct NetworkServiceDiscovery
 | 
			
		||||
{
 | 
			
		||||
    /** An object which runs a thread to repeatedly broadcast the existence of a
 | 
			
		||||
        discoverable service.
 | 
			
		||||
 | 
			
		||||
        To use, simply create an instance of an Advertiser and it'll broadcast until
 | 
			
		||||
        you delete it.
 | 
			
		||||
    */
 | 
			
		||||
    struct Advertiser  : private Thread
 | 
			
		||||
    {
 | 
			
		||||
        /** Creates and starts an Advertiser thread, broadcasting with the given properties.
 | 
			
		||||
            @param serviceTypeUID       A user-supplied string to define the type of service this represents
 | 
			
		||||
            @param serviceDescription   A description string that will appear in the Service::description field for clients
 | 
			
		||||
            @param broadcastPort        The port number on which to broadcast the service discovery packets
 | 
			
		||||
            @param connectionPort       The port number that will be sent to appear in the Service::port field
 | 
			
		||||
            @param minTimeBetweenBroadcasts   The interval to wait between sending broadcast messages
 | 
			
		||||
        */
 | 
			
		||||
        Advertiser (const String& serviceTypeUID,
 | 
			
		||||
                    const String& serviceDescription,
 | 
			
		||||
                    int broadcastPort,
 | 
			
		||||
                    int connectionPort,
 | 
			
		||||
                    RelativeTime minTimeBetweenBroadcasts = RelativeTime::seconds (1.5));
 | 
			
		||||
 | 
			
		||||
        /** Destructor */
 | 
			
		||||
        ~Advertiser() override;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        XmlElement message;
 | 
			
		||||
        const int broadcastPort;
 | 
			
		||||
        const RelativeTime minInterval;
 | 
			
		||||
        DatagramSocket socket { true };
 | 
			
		||||
 | 
			
		||||
        void run() override;
 | 
			
		||||
        void sendBroadcast();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /**
 | 
			
		||||
        Contains information about a service that has been found on the network.
 | 
			
		||||
        @see AvailableServiceList, Advertiser
 | 
			
		||||
    */
 | 
			
		||||
    struct Service
 | 
			
		||||
    {
 | 
			
		||||
        String instanceID;   /**< A UUID that identifies the particular instance of the Advertiser class.  */
 | 
			
		||||
        String description;  /**< The service description as sent by the Advertiser */
 | 
			
		||||
        IPAddress address;   /**< The IP address of the advertiser */
 | 
			
		||||
        int port;            /**< The port number of the advertiser */
 | 
			
		||||
        Time lastSeen;       /**< The time of the last ping received from the advertiser */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /**
 | 
			
		||||
        Watches the network for broadcasts from Advertiser objects, and keeps a list of
 | 
			
		||||
        all the currently active instances.
 | 
			
		||||
 | 
			
		||||
        Just create an instance of AvailableServiceList and it will start listening - you
 | 
			
		||||
        can register a callback with its onChange member to find out when services
 | 
			
		||||
        appear/disappear, and you can call getServices() to find out the current list.
 | 
			
		||||
        @see Service, Advertiser
 | 
			
		||||
    */
 | 
			
		||||
    struct AvailableServiceList  : private Thread,
 | 
			
		||||
                                   private AsyncUpdater
 | 
			
		||||
    {
 | 
			
		||||
        /** Creates an AvailableServiceList that will bind to the given port number and watch
 | 
			
		||||
            the network for Advertisers broadcasting the given service type.
 | 
			
		||||
 | 
			
		||||
            This will only detect broadcasts from an Advertiser object with a matching
 | 
			
		||||
            serviceTypeUID value, and where the broadcastPort matches.
 | 
			
		||||
        */
 | 
			
		||||
        AvailableServiceList (const String& serviceTypeUID, int broadcastPort);
 | 
			
		||||
 | 
			
		||||
        /** Destructor */
 | 
			
		||||
        ~AvailableServiceList() override;
 | 
			
		||||
 | 
			
		||||
        /** A lambda that can be set to recieve a callback when the list changes */
 | 
			
		||||
        std::function<void()> onChange;
 | 
			
		||||
 | 
			
		||||
        /** Returns a list of the currently known services. */
 | 
			
		||||
        std::vector<Service> getServices() const;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        DatagramSocket socket { true };
 | 
			
		||||
        String serviceTypeUID;
 | 
			
		||||
        CriticalSection listLock;
 | 
			
		||||
        std::vector<Service> services;
 | 
			
		||||
 | 
			
		||||
        void run() override;
 | 
			
		||||
        void handleAsyncUpdate() override;
 | 
			
		||||
        void handleMessage (const XmlElement&);
 | 
			
		||||
        void handleMessage (const Service&);
 | 
			
		||||
        void removeTimedOutServices();
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AvailableServiceList)
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
@ -66,6 +66,7 @@
 | 
			
		||||
#include "interprocess/juce_InterprocessConnection.cpp"
 | 
			
		||||
#include "interprocess/juce_InterprocessConnectionServer.cpp"
 | 
			
		||||
#include "interprocess/juce_ConnectedChildProcess.cpp"
 | 
			
		||||
#include "interprocess/juce_NetworkServiceDiscovery.cpp"
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if JUCE_MAC || JUCE_IOS
 | 
			
		||||
 | 
			
		||||
@ -31,7 +31,7 @@
 | 
			
		||||
 | 
			
		||||
  ID:               juce_events
 | 
			
		||||
  vendor:           juce
 | 
			
		||||
  version:          5.3.2
 | 
			
		||||
  version:          5.4.3
 | 
			
		||||
  name:             JUCE message and event handling classes
 | 
			
		||||
  description:      Classes for running an application's main event loop and sending/receiving messages, timers, etc.
 | 
			
		||||
  website:          http://www.juce.com/juce
 | 
			
		||||
@ -59,6 +59,12 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if JUCE_EVENTS_INCLUDE_WINRT_WRAPPER && JUCE_WINDOWS
 | 
			
		||||
 // If this header file is missing then you are probably attempting to use WinRT
 | 
			
		||||
 // functionality without the WinRT libraries installed on your system. Try installing
 | 
			
		||||
 // the latest Windows Standalone SDK and maybe also adding the path to the WinRT
 | 
			
		||||
 // headers to your build system. This path should have the form
 | 
			
		||||
 // "C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0\winrt".
 | 
			
		||||
 #include <inspectable.h>
 | 
			
		||||
 #include <hstring.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -81,6 +87,7 @@
 | 
			
		||||
#include "interprocess/juce_InterprocessConnection.h"
 | 
			
		||||
#include "interprocess/juce_InterprocessConnectionServer.h"
 | 
			
		||||
#include "interprocess/juce_ConnectedChildProcess.h"
 | 
			
		||||
#include "interprocess/juce_NetworkServiceDiscovery.h"
 | 
			
		||||
 | 
			
		||||
#if JUCE_LINUX
 | 
			
		||||
 #include "native/juce_linux_EventLoop.h"
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
JUCEApplicationBase::CreateInstanceFunction JUCEApplicationBase::createInstance = 0;
 | 
			
		||||
JUCEApplicationBase::CreateInstanceFunction JUCEApplicationBase::createInstance = nullptr;
 | 
			
		||||
JUCEApplicationBase* JUCEApplicationBase::appInstance = nullptr;
 | 
			
		||||
 | 
			
		||||
#if JUCE_IOS
 | 
			
		||||
 | 
			
		||||
@ -107,9 +107,11 @@ public:
 | 
			
		||||
        If your application class returns true for this, more than one instance is
 | 
			
		||||
        permitted to run (except on the Mac where this isn't possible).
 | 
			
		||||
 | 
			
		||||
        If it's false, the second instance won't start, but it you will still get a
 | 
			
		||||
        If it's false, the second instance won't start, but you will still get a
 | 
			
		||||
        callback to anotherInstanceStarted() to tell you about this - which
 | 
			
		||||
        gives you a chance to react to what the user was trying to do.
 | 
			
		||||
 | 
			
		||||
        @see anotherInstanceStarted
 | 
			
		||||
    */
 | 
			
		||||
    virtual bool moreThanOneInstanceAllowed() = 0;
 | 
			
		||||
 | 
			
		||||
@ -151,6 +153,9 @@ public:
 | 
			
		||||
    /** Indicates that the user has tried to start up another instance of the app.
 | 
			
		||||
 | 
			
		||||
        This will get called even if moreThanOneInstanceAllowed() is false.
 | 
			
		||||
        It is currently only implemented on Windows and Mac.
 | 
			
		||||
 | 
			
		||||
        @see moreThanOneInstanceAllowed
 | 
			
		||||
    */
 | 
			
		||||
    virtual void anotherInstanceStarted (const String& commandLine) = 0;
 | 
			
		||||
 | 
			
		||||
@ -270,7 +275,7 @@ public:
 | 
			
		||||
    static int main (int argc, const char* argv[]);
 | 
			
		||||
 | 
			
		||||
    static void appWillTerminateByForce();
 | 
			
		||||
    typedef JUCEApplicationBase* (*CreateInstanceFunction)();
 | 
			
		||||
    using CreateInstanceFunction = JUCEApplicationBase* (*)();
 | 
			
		||||
    static CreateInstanceFunction createInstance;
 | 
			
		||||
 | 
			
		||||
   #if JUCE_IOS
 | 
			
		||||
@ -290,8 +295,6 @@ private:
 | 
			
		||||
    bool stillInitialising = true;
 | 
			
		||||
 | 
			
		||||
    struct MultipleInstanceHandler;
 | 
			
		||||
    friend struct MultipleInstanceHandler;
 | 
			
		||||
    friend struct ContainerDeletePolicy<MultipleInstanceHandler>;
 | 
			
		||||
    std::unique_ptr<MultipleInstanceHandler> multipleInstanceHandler;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (JUCEApplicationBase)
 | 
			
		||||
 | 
			
		||||
@ -49,10 +49,10 @@ class JUCE_API  CallbackMessage   : public MessageManager::MessageBase
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    CallbackMessage() noexcept {}
 | 
			
		||||
    CallbackMessage() = default;
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~CallbackMessage() {}
 | 
			
		||||
    ~CallbackMessage() override = default;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Called when the message is delivered.
 | 
			
		||||
@ -63,7 +63,7 @@ public:
 | 
			
		||||
        Note that like all other messages, this object will be deleted immediately
 | 
			
		||||
        after this method has been invoked.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void messageCallback() = 0;
 | 
			
		||||
    virtual void messageCallback() override = 0;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    // Avoid the leak-detector because for plugins, the host can unload our DLL with undelivered
 | 
			
		||||
 | 
			
		||||
@ -116,7 +116,7 @@ public:
 | 
			
		||||
 #elif JUCE_ANDROID
 | 
			
		||||
 | 
			
		||||
  #define JUCE_CREATE_APPLICATION_DEFINE(AppClass) \
 | 
			
		||||
    juce::JUCEApplicationBase* juce_CreateApplication() { return new AppClass(); }
 | 
			
		||||
    extern "C" juce::JUCEApplicationBase* juce_CreateApplication() { return new AppClass(); }
 | 
			
		||||
 | 
			
		||||
  #define JUCE_MAIN_FUNCTION_DEFINITION
 | 
			
		||||
 | 
			
		||||
@ -155,7 +155,7 @@ public:
 | 
			
		||||
 | 
			
		||||
  #if JUCE_IOS
 | 
			
		||||
    /**
 | 
			
		||||
       You can instruct JUCE to use a custom iOS app delegate class instaed of JUCE's default
 | 
			
		||||
       You can instruct JUCE to use a custom iOS app delegate class instead of JUCE's default
 | 
			
		||||
       app delegate. For JUCE to work you must pass all messages to JUCE's internal app delegate.
 | 
			
		||||
       Below is an example of minimal forwarding custom delegate. Note that you are at your own
 | 
			
		||||
       risk if you decide to use your own delegate and subtle, hard to debug bugs may occur.
 | 
			
		||||
 | 
			
		||||
@ -46,7 +46,7 @@ public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an uninitialised message. */
 | 
			
		||||
    Message() noexcept;
 | 
			
		||||
    ~Message();
 | 
			
		||||
    ~Message() override;
 | 
			
		||||
 | 
			
		||||
    using Ptr = ReferenceCountedObjectPtr<Message>;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -35,7 +35,7 @@ void Message::messageCallback()
 | 
			
		||||
MessageListener::MessageListener() noexcept
 | 
			
		||||
{
 | 
			
		||||
    // Are you trying to create a messagelistener before or after juce has been intialised??
 | 
			
		||||
    jassert (MessageManager::getInstanceWithoutCreating() != nullptr);
 | 
			
		||||
    JUCE_ASSERT_MESSAGE_MANAGER_EXISTS
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MessageListener::~MessageListener()
 | 
			
		||||
 | 
			
		||||
@ -231,6 +231,22 @@ bool MessageManager::currentThreadHasLockedMessageManager() const noexcept
 | 
			
		||||
    return thisThread == messageThreadId || thisThread == threadWithLock.get();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MessageManager::existsAndIsLockedByCurrentThread() noexcept
 | 
			
		||||
{
 | 
			
		||||
    if (auto i = getInstanceWithoutCreating())
 | 
			
		||||
        return i->currentThreadHasLockedMessageManager();
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MessageManager::existsAndIsCurrentThread() noexcept
 | 
			
		||||
{
 | 
			
		||||
    if (auto i = getInstanceWithoutCreating())
 | 
			
		||||
        return i->isThisTheMessageThread();
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/*  The only safe way to lock the message thread while another thread does
 | 
			
		||||
@ -294,7 +310,7 @@ bool MessageManager::Lock::tryAcquire (bool lockIsMandatory) const noexcept
 | 
			
		||||
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        blockingMessage = new BlockingMessage (this);
 | 
			
		||||
        blockingMessage = *new BlockingMessage (this);
 | 
			
		||||
    }
 | 
			
		||||
    catch (...)
 | 
			
		||||
    {
 | 
			
		||||
@ -349,7 +365,7 @@ void MessageManager::Lock::exit() const noexcept
 | 
			
		||||
        lockGained.set (0);
 | 
			
		||||
 | 
			
		||||
        if (mm != nullptr)
 | 
			
		||||
            mm->threadWithLock = 0;
 | 
			
		||||
            mm->threadWithLock = {};
 | 
			
		||||
 | 
			
		||||
        if (blockingMessage != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
@ -417,7 +433,7 @@ bool MessageManagerLock::attemptLock (Thread* threadToCheck, ThreadPoolJob* jobT
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MessageManagerLock::~MessageManagerLock() noexcept     { mmLock.exit(); }
 | 
			
		||||
MessageManagerLock::~MessageManagerLock()  { mmLock.exit(); }
 | 
			
		||||
 | 
			
		||||
void MessageManagerLock::exitSignalSent()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
@ -35,7 +35,7 @@ class OpenGLContext;
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/** See MessageManager::callFunctionOnMessageThread() for use of this function type. */
 | 
			
		||||
typedef void* (MessageCallbackFunction) (void* userData);
 | 
			
		||||
using MessageCallbackFunction = void* (void* userData);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
@ -147,6 +147,16 @@ public:
 | 
			
		||||
    */
 | 
			
		||||
    bool currentThreadHasLockedMessageManager() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if there's an instance of the MessageManager, and if the current thread
 | 
			
		||||
        has the lock on it.
 | 
			
		||||
    */
 | 
			
		||||
    static bool existsAndIsLockedByCurrentThread() noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if there's an instance of the MessageManager, and if the current thread
 | 
			
		||||
        is running it.
 | 
			
		||||
    */
 | 
			
		||||
    static bool existsAndIsCurrentThread() noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sends a message to all other JUCE applications that are running.
 | 
			
		||||
 | 
			
		||||
@ -176,8 +186,8 @@ public:
 | 
			
		||||
    class JUCE_API  MessageBase  : public ReferenceCountedObject
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        MessageBase() noexcept {}
 | 
			
		||||
        virtual ~MessageBase() {}
 | 
			
		||||
        MessageBase() = default;
 | 
			
		||||
        ~MessageBase() override = default;
 | 
			
		||||
 | 
			
		||||
        virtual void messageCallback() = 0;
 | 
			
		||||
        bool post();
 | 
			
		||||
@ -280,13 +290,13 @@ public:
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        /** Provides the type of scoped lock to use with a CriticalSection. */
 | 
			
		||||
        typedef GenericScopedLock<Lock>       ScopedLockType;
 | 
			
		||||
        using ScopedLockType = GenericScopedLock<Lock>;
 | 
			
		||||
 | 
			
		||||
        /** Provides the type of scoped unlocker to use with a CriticalSection. */
 | 
			
		||||
        typedef GenericScopedUnlock<Lock>     ScopedUnlockType;
 | 
			
		||||
        using ScopedUnlockType = GenericScopedUnlock<Lock>;
 | 
			
		||||
 | 
			
		||||
        /** Provides the type of scoped try-locker to use with a CriticalSection. */
 | 
			
		||||
        typedef GenericScopedTryLock<Lock>    ScopedTryLockType;
 | 
			
		||||
        using ScopedTryLockType = GenericScopedTryLock<Lock>;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        struct BlockingMessage;
 | 
			
		||||
@ -442,7 +452,7 @@ public:
 | 
			
		||||
        Make sure this object is created and deleted by the same thread,
 | 
			
		||||
        otherwise there are no guarantees what will happen!
 | 
			
		||||
   */
 | 
			
		||||
    ~MessageManagerLock() noexcept;
 | 
			
		||||
    ~MessageManagerLock() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns true if the lock was successfully acquired.
 | 
			
		||||
@ -462,4 +472,28 @@ private:
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (MessageManagerLock)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/** This macro is used to catch unsafe use of functions which expect to only be called
 | 
			
		||||
    on the message thread, or when a MessageManagerLock is in place.
 | 
			
		||||
    It will also fail if you try to use the function before the message manager has been
 | 
			
		||||
    created, which could happen if you accidentally invoke it during a static constructor.
 | 
			
		||||
*/
 | 
			
		||||
#define JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED \
 | 
			
		||||
    jassert (juce::MessageManager::existsAndIsLockedByCurrentThread());
 | 
			
		||||
 | 
			
		||||
/** This macro is used to catch unsafe use of functions which expect to only be called
 | 
			
		||||
    on the message thread.
 | 
			
		||||
    It will also fail if you try to use the function before the message manager has been
 | 
			
		||||
    created, which could happen if you accidentally invoke it during a static constructor.
 | 
			
		||||
*/
 | 
			
		||||
#define JUCE_ASSERT_MESSAGE_THREAD \
 | 
			
		||||
    jassert (juce::MessageManager::existsAndIsCurrentThread());
 | 
			
		||||
 | 
			
		||||
/** This macro is used to catch unsafe use of functions which expect to not be called
 | 
			
		||||
    outside the lifetime of the MessageManager.
 | 
			
		||||
*/
 | 
			
		||||
#define JUCE_ASSERT_MESSAGE_MANAGER_EXISTS \
 | 
			
		||||
    jassert (juce::MessageManager::getInstanceWithoutCreating() != nullptr);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 | 
			
		||||
@ -48,7 +48,6 @@ public:
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    JUCE_PUBLIC_IN_DLL_BUILD (struct Pimpl)
 | 
			
		||||
    friend struct ContainerDeletePolicy<Pimpl>;
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MountedVolumeListChangeDetector)
 | 
			
		||||
 | 
			
		||||
@ -50,7 +50,7 @@ namespace Android
 | 
			
		||||
 | 
			
		||||
    struct Handler
 | 
			
		||||
    {
 | 
			
		||||
        Handler() : nativeHandler (getEnv()->NewObject (AndroidHandler, AndroidHandler.constructor)) {}
 | 
			
		||||
        Handler() : nativeHandler (LocalRef<jobject> (getEnv()->NewObject (AndroidHandler, AndroidHandler.constructor))) {}
 | 
			
		||||
        ~Handler() { clearSingletonInstance(); }
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_SINGLETON (Handler, false)
 | 
			
		||||
@ -72,19 +72,19 @@ struct AndroidMessageQueue     : private Android::Runnable
 | 
			
		||||
    JUCE_DECLARE_SINGLETON_SINGLETHREADED (AndroidMessageQueue, true)
 | 
			
		||||
 | 
			
		||||
    AndroidMessageQueue()
 | 
			
		||||
        : self (CreateJavaInterface (this, "java/lang/Runnable").get())
 | 
			
		||||
        : self (CreateJavaInterface (this, "java/lang/Runnable"))
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~AndroidMessageQueue()
 | 
			
		||||
    {
 | 
			
		||||
        jassert (MessageManager::getInstance()->isThisTheMessageThread());
 | 
			
		||||
        JUCE_ASSERT_MESSAGE_THREAD
 | 
			
		||||
        clearSingletonInstance();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool post (MessageManager::MessageBase::Ptr&& message)
 | 
			
		||||
    {
 | 
			
		||||
        queue.add (static_cast<MessageManager::MessageBase::Ptr&& > (message));
 | 
			
		||||
        queue.add (std::move (message));
 | 
			
		||||
 | 
			
		||||
        // this will call us on the message thread
 | 
			
		||||
        return handler.post (self.get());
 | 
			
		||||
@ -94,7 +94,7 @@ private:
 | 
			
		||||
 | 
			
		||||
    void run() override
 | 
			
		||||
    {
 | 
			
		||||
        while (true)
 | 
			
		||||
        for (;;)
 | 
			
		||||
        {
 | 
			
		||||
            MessageManager::MessageBase::Ptr message (queue.removeAndReturn (0));
 | 
			
		||||
 | 
			
		||||
@ -131,6 +131,7 @@ bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* cons
 | 
			
		||||
{
 | 
			
		||||
    return AndroidMessageQueue::getInstance()->post (message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void MessageManager::broadcastMessage (const String&)
 | 
			
		||||
{
 | 
			
		||||
@ -149,18 +150,26 @@ void MessageManager::stopDispatchLoop()
 | 
			
		||||
        void messageCallback() override
 | 
			
		||||
        {
 | 
			
		||||
            auto* env = getEnv();
 | 
			
		||||
            LocalRef<jobject> activity (getCurrentActivity());
 | 
			
		||||
 | 
			
		||||
            jmethodID quitMethod = env->GetMethodID (JuceAppActivity, "finishAndRemoveTask", "()V");
 | 
			
		||||
 | 
			
		||||
            if (quitMethod != 0)
 | 
			
		||||
            if (activity != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                env->CallVoidMethod (android.activity, quitMethod);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
                jmethodID quitMethod = env->GetMethodID (AndroidActivity, "finishAndRemoveTask", "()V");
 | 
			
		||||
 | 
			
		||||
            quitMethod = env->GetMethodID (JuceAppActivity, "finish", "()V");
 | 
			
		||||
            jassert (quitMethod != 0);
 | 
			
		||||
            env->CallVoidMethod (android.activity, quitMethod);
 | 
			
		||||
                if (quitMethod != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    env->CallVoidMethod (activity.get(), quitMethod);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                quitMethod = env->GetMethodID (AndroidActivity, "finish", "()V");
 | 
			
		||||
                jassert (quitMethod != 0);
 | 
			
		||||
                env->CallVoidMethod (activity.get(), quitMethod);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                jassertfalse;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@ -168,4 +177,134 @@ void MessageManager::stopDispatchLoop()
 | 
			
		||||
    quitMessagePosted = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class JuceAppLifecycle   : public ActivityLifecycleCallbacks
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JuceAppLifecycle (juce::JUCEApplicationBase* (*initSymbolAddr)())
 | 
			
		||||
        : createApplicationSymbol (initSymbolAddr)
 | 
			
		||||
    {
 | 
			
		||||
        LocalRef<jobject> appContext (getAppContext());
 | 
			
		||||
 | 
			
		||||
        if (appContext != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            auto* env = getEnv();
 | 
			
		||||
 | 
			
		||||
            myself = GlobalRef (CreateJavaInterface (this, "android/app/Application$ActivityLifecycleCallbacks"));
 | 
			
		||||
            env->CallVoidMethod (appContext.get(), AndroidApplication.registerActivityLifecycleCallbacks, myself.get());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~JuceAppLifecycle()
 | 
			
		||||
    {
 | 
			
		||||
        LocalRef<jobject> appContext (getAppContext());
 | 
			
		||||
 | 
			
		||||
        if (appContext != nullptr && myself != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            auto* env = getEnv();
 | 
			
		||||
 | 
			
		||||
            clear();
 | 
			
		||||
            env->CallVoidMethod (appContext.get(), AndroidApplication.unregisterActivityLifecycleCallbacks, myself.get());
 | 
			
		||||
            myself.clear();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void onActivityCreated (jobject, jobject) override
 | 
			
		||||
    {
 | 
			
		||||
        checkCreated();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void onActivityDestroyed (jobject activity) override
 | 
			
		||||
    {
 | 
			
		||||
        auto* env = getEnv();
 | 
			
		||||
 | 
			
		||||
        // if the main activity is being destroyed, only then tear-down JUCE
 | 
			
		||||
        if (env->IsSameObject (getMainActivity().get(), activity) != 0)
 | 
			
		||||
        {
 | 
			
		||||
            JUCEApplicationBase::appWillTerminateByForce();
 | 
			
		||||
            JNIClassBase::releaseAllClasses (env);
 | 
			
		||||
 | 
			
		||||
            jclass systemClass = (jclass) env->FindClass ("java/lang/System");
 | 
			
		||||
            jmethodID exitMethod = env->GetStaticMethodID (systemClass, "exit", "(I)V");
 | 
			
		||||
            env->CallStaticVoidMethod (systemClass, exitMethod, 0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void onActivityStarted (jobject) override
 | 
			
		||||
    {
 | 
			
		||||
        checkCreated();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void onActivityPaused (jobject) override
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* app = JUCEApplicationBase::getInstance())
 | 
			
		||||
            app->suspended();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void onActivityResumed (jobject) override
 | 
			
		||||
    {
 | 
			
		||||
        checkInitialised();
 | 
			
		||||
 | 
			
		||||
        if (auto* app = JUCEApplicationBase::getInstance())
 | 
			
		||||
            app->resumed();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static JuceAppLifecycle& getInstance (juce::JUCEApplicationBase* (*initSymbolAddr)())
 | 
			
		||||
    {
 | 
			
		||||
        static JuceAppLifecycle juceAppLifecycle (initSymbolAddr);
 | 
			
		||||
        return juceAppLifecycle;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void checkCreated()
 | 
			
		||||
    {
 | 
			
		||||
        if (JUCEApplicationBase::getInstance() == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            DBG (SystemStats::getJUCEVersion());
 | 
			
		||||
 | 
			
		||||
            JUCEApplicationBase::createInstance = createApplicationSymbol;
 | 
			
		||||
 | 
			
		||||
            initialiseJuce_GUI();
 | 
			
		||||
 | 
			
		||||
            if (! JUCEApplicationBase::createInstance())
 | 
			
		||||
                jassertfalse; // you must supply an application object for an android app!
 | 
			
		||||
 | 
			
		||||
            jassert (MessageManager::getInstance()->isThisTheMessageThread());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void checkInitialised()
 | 
			
		||||
    {
 | 
			
		||||
        checkCreated();
 | 
			
		||||
 | 
			
		||||
        if (! hasBeenInitialised)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* app = JUCEApplicationBase::getInstance())
 | 
			
		||||
            {
 | 
			
		||||
                hasBeenInitialised = app->initialiseApp();
 | 
			
		||||
 | 
			
		||||
                if (! hasBeenInitialised)
 | 
			
		||||
                    exit (app->shutdownApp());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    GlobalRef myself;
 | 
			
		||||
    juce::JUCEApplicationBase* (*createApplicationSymbol)();
 | 
			
		||||
    bool hasBeenInitialised = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
File juce_getExecutableFile();
 | 
			
		||||
 | 
			
		||||
void juce_juceEventsAndroidStartApp()
 | 
			
		||||
{
 | 
			
		||||
    auto dllPath = juce_getExecutableFile().getFullPathName();
 | 
			
		||||
    auto addr = reinterpret_cast<juce::JUCEApplicationBase*(*)()> (DynamicLibrary (dllPath)
 | 
			
		||||
                                                                    .getFunction ("juce_CreateApplication"));
 | 
			
		||||
 | 
			
		||||
    if (addr != nullptr)
 | 
			
		||||
        JuceAppLifecycle::getInstance (addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 | 
			
		||||
@ -23,13 +23,13 @@
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
typedef void (*AppFocusChangeCallback)();
 | 
			
		||||
using AppFocusChangeCallback = void (*)();
 | 
			
		||||
AppFocusChangeCallback appFocusChangeCallback = nullptr;
 | 
			
		||||
 | 
			
		||||
typedef bool (*CheckEventBlockedByModalComps) (NSEvent*);
 | 
			
		||||
using CheckEventBlockedByModalComps = bool (*)(NSEvent*);
 | 
			
		||||
CheckEventBlockedByModalComps isEventBlockedByModalComps = nullptr;
 | 
			
		||||
 | 
			
		||||
typedef void (*MenuTrackingChangedCallback)(bool);
 | 
			
		||||
using MenuTrackingChangedCallback = void (*)(bool);
 | 
			
		||||
MenuTrackingChangedCallback menuTrackingChangedCallback = nullptr;
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
@ -235,8 +235,10 @@ private:
 | 
			
		||||
        static String quotedIfContainsSpaces (NSString* file)
 | 
			
		||||
        {
 | 
			
		||||
            String s (nsStringToJuce (file));
 | 
			
		||||
            s = s.unquoted().replace ("\"", "\\\"");
 | 
			
		||||
 | 
			
		||||
            if (s.containsChar (' '))
 | 
			
		||||
                s = s.quoted ('"');
 | 
			
		||||
                s = s.quoted();
 | 
			
		||||
 | 
			
		||||
            return s;
 | 
			
		||||
        }
 | 
			
		||||
@ -381,7 +383,7 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
 | 
			
		||||
    jassert (millisecondsToRunFor >= 0);
 | 
			
		||||
    jassert (isThisTheMessageThread()); // must only be called by the message thread
 | 
			
		||||
 | 
			
		||||
    uint32 endTime = Time::getMillisecondCounter() + (uint32) millisecondsToRunFor;
 | 
			
		||||
    auto endTime = Time::currentTimeMillis() + millisecondsToRunFor;
 | 
			
		||||
 | 
			
		||||
    while (quitMessagePosted.get() == 0)
 | 
			
		||||
    {
 | 
			
		||||
@ -397,7 +399,7 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
 | 
			
		||||
            if (e != nil && (isEventBlockedByModalComps == nullptr || ! (*isEventBlockedByModalComps) (e)))
 | 
			
		||||
                [NSApp sendEvent: e];
 | 
			
		||||
 | 
			
		||||
            if (Time::getMillisecondCounter() >= endTime)
 | 
			
		||||
            if (Time::currentTimeMillis() >= endTime)
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -454,7 +456,7 @@ void __attribute__ ((visibility("default"))) repostCurrentNSEvent()
 | 
			
		||||
    struct EventReposter  : public CallbackMessage
 | 
			
		||||
    {
 | 
			
		||||
        EventReposter() : e ([[NSApp currentEvent] retain])  {}
 | 
			
		||||
        ~EventReposter()  { [e release]; }
 | 
			
		||||
        ~EventReposter() override  { [e release]; }
 | 
			
		||||
 | 
			
		||||
        void messageCallback() override
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
@ -25,12 +25,16 @@ namespace juce
 | 
			
		||||
 | 
			
		||||
extern HWND juce_messageWindowHandle;
 | 
			
		||||
 | 
			
		||||
typedef bool (*CheckEventBlockedByModalComps) (const MSG&);
 | 
			
		||||
using CheckEventBlockedByModalComps = bool (*)(const MSG&);
 | 
			
		||||
CheckEventBlockedByModalComps isEventBlockedByModalComps = nullptr;
 | 
			
		||||
 | 
			
		||||
typedef void (*SettingChangeCallbackFunc) (void);
 | 
			
		||||
using SettingChangeCallbackFunc = void (*)(void);
 | 
			
		||||
SettingChangeCallbackFunc settingChangeCallback = nullptr;
 | 
			
		||||
 | 
			
		||||
#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity
 | 
			
		||||
 bool juce_isRunningInUnity();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
namespace WindowsMessageHelpers
 | 
			
		||||
{
 | 
			
		||||
@ -42,7 +46,7 @@ namespace WindowsMessageHelpers
 | 
			
		||||
 | 
			
		||||
    void dispatchMessageFromLParam (LPARAM lParam)
 | 
			
		||||
    {
 | 
			
		||||
        if (MessageManager::MessageBase* message = reinterpret_cast<MessageManager::MessageBase*> (lParam))
 | 
			
		||||
        if (auto message = reinterpret_cast<MessageManager::MessageBase*> (lParam))
 | 
			
		||||
        {
 | 
			
		||||
            JUCE_TRY
 | 
			
		||||
            {
 | 
			
		||||
@ -68,7 +72,7 @@ namespace WindowsMessageHelpers
 | 
			
		||||
        return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void handleBroadcastMessage (const COPYDATASTRUCT* const data)
 | 
			
		||||
    void handleBroadcastMessage (const COPYDATASTRUCT* data)
 | 
			
		||||
    {
 | 
			
		||||
        if (data != nullptr && data->dwData == broadcastMessageMagicNumber)
 | 
			
		||||
        {
 | 
			
		||||
@ -87,7 +91,7 @@ namespace WindowsMessageHelpers
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    LRESULT CALLBACK messageWndProc (HWND h, const UINT message, const WPARAM wParam, const LPARAM lParam) noexcept
 | 
			
		||||
    LRESULT CALLBACK messageWndProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (h == juce_messageWindowHandle)
 | 
			
		||||
        {
 | 
			
		||||
@ -104,11 +108,10 @@ namespace WindowsMessageHelpers
 | 
			
		||||
                handleBroadcastMessage (reinterpret_cast<const COPYDATASTRUCT*> (lParam));
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
            else if (message == WM_SETTINGCHANGE)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            if (message == WM_SETTINGCHANGE)
 | 
			
		||||
                if (settingChangeCallback != nullptr)
 | 
			
		||||
                    settingChangeCallback();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return DefWindowProc (h, message, wParam, lParam);
 | 
			
		||||
@ -120,7 +123,7 @@ LRESULT juce_offerEventToActiveXControl (::MSG&);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
bool MessageManager::dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages)
 | 
			
		||||
bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
 | 
			
		||||
{
 | 
			
		||||
    using namespace WindowsMessageHelpers;
 | 
			
		||||
    MSG m;
 | 
			
		||||
@ -130,10 +133,10 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (const bool returnIfNoPend
 | 
			
		||||
 | 
			
		||||
    if (GetMessage (&m, (HWND) 0, 0, 0) >= 0)
 | 
			
		||||
    {
 | 
			
		||||
      #if JUCE_MODULE_AVAILABLE_juce_gui_extra
 | 
			
		||||
       #if JUCE_MODULE_AVAILABLE_juce_gui_extra
 | 
			
		||||
        if (juce_offerEventToActiveXControl (m) != S_FALSE)
 | 
			
		||||
            return true;
 | 
			
		||||
      #endif
 | 
			
		||||
       #endif
 | 
			
		||||
 | 
			
		||||
        if (m.message == customMessageID && m.hwnd == juce_messageWindowHandle)
 | 
			
		||||
        {
 | 
			
		||||
@ -151,7 +154,7 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (const bool returnIfNoPend
 | 
			
		||||
            {
 | 
			
		||||
                // if it's someone else's window being clicked on, and the focus is
 | 
			
		||||
                // currently on a juce window, pass the kb focus over..
 | 
			
		||||
                HWND currentFocus = GetFocus();
 | 
			
		||||
                auto currentFocus = GetFocus();
 | 
			
		||||
 | 
			
		||||
                if (currentFocus == 0 || JuceWindowIdentifier::isJUCEWindow (currentFocus))
 | 
			
		||||
                    SetFocus (m.hwnd);
 | 
			
		||||
@ -168,12 +171,18 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (const bool returnIfNoPend
 | 
			
		||||
bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
 | 
			
		||||
{
 | 
			
		||||
    message->incReferenceCount();
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity
 | 
			
		||||
    if (juce_isRunningInUnity())
 | 
			
		||||
        return SendNotifyMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0;
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    return PostMessage (juce_messageWindowHandle, WindowsMessageHelpers::customMessageID, 0, (LPARAM) message) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MessageManager::broadcastMessage (const String& value)
 | 
			
		||||
{
 | 
			
		||||
    const String localCopy (value);
 | 
			
		||||
    auto localCopy = value;
 | 
			
		||||
 | 
			
		||||
    Array<HWND> windows;
 | 
			
		||||
    EnumWindows (&WindowsMessageHelpers::broadcastEnumWindowProc, (LPARAM) &windows);
 | 
			
		||||
 | 
			
		||||
@ -22,5 +22,60 @@
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
    JUCE_IMPLEMENT_SINGLETON (WinRTWrapper)
 | 
			
		||||
 | 
			
		||||
WinRTWrapper::ScopedHString::ScopedHString (String str)
 | 
			
		||||
{
 | 
			
		||||
    if (WinRTWrapper::getInstance()->isInitialised())
 | 
			
		||||
        WinRTWrapper::getInstance()->createHString (str.toWideCharPointer(),
 | 
			
		||||
                                                    static_cast<uint32_t> (str.length()),
 | 
			
		||||
                                                    &hstr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WinRTWrapper::ScopedHString::~ScopedHString()
 | 
			
		||||
{
 | 
			
		||||
    if (WinRTWrapper::getInstance()->isInitialised() && hstr != nullptr)
 | 
			
		||||
        WinRTWrapper::getInstance()->deleteHString (hstr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WinRTWrapper::~WinRTWrapper()
 | 
			
		||||
{
 | 
			
		||||
    if (winRTHandle != nullptr)
 | 
			
		||||
        ::FreeLibrary (winRTHandle);
 | 
			
		||||
 | 
			
		||||
    clearSingletonInstance();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String WinRTWrapper::hStringToString (HSTRING hstr)
 | 
			
		||||
{
 | 
			
		||||
    if (isInitialised())
 | 
			
		||||
        if (const wchar_t* str = getHStringRawBuffer (hstr, nullptr))
 | 
			
		||||
            return String (str);
 | 
			
		||||
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WinRTWrapper::WinRTWrapper()
 | 
			
		||||
{
 | 
			
		||||
    winRTHandle = ::LoadLibraryA ("api-ms-win-core-winrt-l1-1-0");
 | 
			
		||||
 | 
			
		||||
    if (winRTHandle == nullptr)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    roInitialize           = (RoInitializeFuncPtr)              ::GetProcAddress (winRTHandle, "RoInitialize");
 | 
			
		||||
    createHString          = (WindowsCreateStringFuncPtr)       ::GetProcAddress (winRTHandle, "WindowsCreateString");
 | 
			
		||||
    deleteHString          = (WindowsDeleteStringFuncPtr)       ::GetProcAddress (winRTHandle, "WindowsDeleteString");
 | 
			
		||||
    getHStringRawBuffer    = (WindowsGetStringRawBufferFuncPtr) ::GetProcAddress (winRTHandle, "WindowsGetStringRawBuffer");
 | 
			
		||||
    roActivateInstance     = (RoActivateInstanceFuncPtr)        ::GetProcAddress (winRTHandle, "RoActivateInstance");
 | 
			
		||||
    roGetActivationFactory = (RoGetActivationFactoryFuncPtr)    ::GetProcAddress (winRTHandle, "RoGetActivationFactory");
 | 
			
		||||
 | 
			
		||||
    if (roInitialize == nullptr || createHString == nullptr || deleteHString == nullptr
 | 
			
		||||
        || getHStringRawBuffer == nullptr || roActivateInstance == nullptr || roGetActivationFactory == nullptr)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    HRESULT status = roInitialize (1);
 | 
			
		||||
    initialised = ! (status != S_OK && status != S_FALSE && status != 0x80010106L);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (WinRTWrapper)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -26,29 +26,14 @@ namespace juce
 | 
			
		||||
class WinRTWrapper :   public DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_DECLARE_SINGLETON (WinRTWrapper, true)
 | 
			
		||||
 | 
			
		||||
    class ScopedHString
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        ScopedHString (String str)
 | 
			
		||||
        {
 | 
			
		||||
            if (WinRTWrapper::getInstance()->isInitialised())
 | 
			
		||||
                WinRTWrapper::getInstance()->createHString (str.toWideCharPointer(),
 | 
			
		||||
                                                            static_cast<uint32_t> (str.length()),
 | 
			
		||||
                                                            &hstr);
 | 
			
		||||
        }
 | 
			
		||||
        ScopedHString (String);
 | 
			
		||||
 | 
			
		||||
        ~ScopedHString()
 | 
			
		||||
        {
 | 
			
		||||
            if (WinRTWrapper::getInstance()->isInitialised() && hstr != nullptr)
 | 
			
		||||
                WinRTWrapper::getInstance()->deleteHString (hstr);
 | 
			
		||||
        }
 | 
			
		||||
        ~ScopedHString();
 | 
			
		||||
 | 
			
		||||
        HSTRING get() const noexcept
 | 
			
		||||
        {
 | 
			
		||||
            return hstr;
 | 
			
		||||
        }
 | 
			
		||||
        HSTRING get() const noexcept          { return hstr; }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        HSTRING hstr = nullptr;
 | 
			
		||||
@ -56,36 +41,81 @@ public:
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ScopedHString)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ~WinRTWrapper()
 | 
			
		||||
    template <class ComClass>
 | 
			
		||||
    class ComPtr
 | 
			
		||||
    {
 | 
			
		||||
        if (winRTHandle != nullptr)
 | 
			
		||||
            ::FreeLibrary (winRTHandle);
 | 
			
		||||
    public:
 | 
			
		||||
        ComPtr() noexcept {}
 | 
			
		||||
        ComPtr (ComClass* obj) : p (obj) { if (p) p->AddRef(); }
 | 
			
		||||
        ComPtr (const ComPtr& other) : p (other.p) { if (p) p->AddRef(); }
 | 
			
		||||
        ~ComPtr() { release(); }
 | 
			
		||||
 | 
			
		||||
        clearSingletonInstance();
 | 
			
		||||
    }
 | 
			
		||||
        operator ComClass*()   const noexcept { return p; }
 | 
			
		||||
        ComClass& operator*()  const noexcept { return *p; }
 | 
			
		||||
        ComClass* operator->() const noexcept { return p; }
 | 
			
		||||
 | 
			
		||||
    String hStringToString (HSTRING hstr)
 | 
			
		||||
        ComPtr& operator= (ComClass* const newP)
 | 
			
		||||
        {
 | 
			
		||||
            if (newP != nullptr)
 | 
			
		||||
                newP->AddRef();
 | 
			
		||||
 | 
			
		||||
            release();
 | 
			
		||||
            p = newP;
 | 
			
		||||
            return *this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ComPtr& operator= (const ComPtr& newP) { return operator= (newP.p); }
 | 
			
		||||
 | 
			
		||||
        ComClass** resetAndGetPointerAddress()
 | 
			
		||||
        {
 | 
			
		||||
            release();
 | 
			
		||||
            p = nullptr;
 | 
			
		||||
            return &p;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        ComClass* p = nullptr;
 | 
			
		||||
 | 
			
		||||
        void release() { if (p != nullptr) p->Release(); }
 | 
			
		||||
 | 
			
		||||
        ComClass** operator&() noexcept; // private to avoid it being used accidentally
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_SINGLETON (WinRTWrapper, true)
 | 
			
		||||
 | 
			
		||||
    ~WinRTWrapper();
 | 
			
		||||
 | 
			
		||||
    String hStringToString (HSTRING);
 | 
			
		||||
 | 
			
		||||
    bool isInitialised() const noexcept       { return initialised; }
 | 
			
		||||
 | 
			
		||||
    template <class ComClass>
 | 
			
		||||
    ComPtr<ComClass> activateInstance (const wchar_t* runtimeClassID, REFCLSID classUUID)
 | 
			
		||||
    {
 | 
			
		||||
        ComPtr<ComClass> result;
 | 
			
		||||
 | 
			
		||||
        if (isInitialised())
 | 
			
		||||
            if (const wchar_t* str = getHStringRawBuffer (hstr, nullptr))
 | 
			
		||||
                return String (str);
 | 
			
		||||
        {
 | 
			
		||||
            ComPtr<IInspectable> inspectable;
 | 
			
		||||
            ScopedHString runtimeClass (runtimeClassID);
 | 
			
		||||
            auto hr = roActivateInstance (runtimeClass.get(), inspectable.resetAndGetPointerAddress());
 | 
			
		||||
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
            if (SUCCEEDED (hr))
 | 
			
		||||
                inspectable->QueryInterface (classUUID, (void**) result.resetAndGetPointerAddress());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    bool isInitialised() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return initialised;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <class ComClass>
 | 
			
		||||
    ComSmartPtr<ComClass> getWRLFactory (const wchar_t* runtimeClassID)
 | 
			
		||||
    ComPtr<ComClass> getWRLFactory (const wchar_t* runtimeClassID)
 | 
			
		||||
    {
 | 
			
		||||
        ComSmartPtr<ComClass> comPtr;
 | 
			
		||||
        ComPtr<ComClass> comPtr;
 | 
			
		||||
 | 
			
		||||
        if (isInitialised())
 | 
			
		||||
        {
 | 
			
		||||
            ScopedHString classID (runtimeClassID);
 | 
			
		||||
 | 
			
		||||
            if (classID.get() != nullptr)
 | 
			
		||||
                roGetActivationFactory (classID.get(), __uuidof (ComClass), (void**) comPtr.resetAndGetPointerAddress());
 | 
			
		||||
        }
 | 
			
		||||
@ -94,25 +124,7 @@ public:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    WinRTWrapper()
 | 
			
		||||
    {
 | 
			
		||||
        winRTHandle = ::LoadLibraryA ("api-ms-win-core-winrt-l1-1-0");
 | 
			
		||||
        if (winRTHandle == nullptr)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        roInitialize           = (RoInitializeFuncPtr)              ::GetProcAddress (winRTHandle, "RoInitialize");
 | 
			
		||||
        createHString          = (WindowsCreateStringFuncPtr)       ::GetProcAddress (winRTHandle, "WindowsCreateString");
 | 
			
		||||
        deleteHString          = (WindowsDeleteStringFuncPtr)       ::GetProcAddress (winRTHandle, "WindowsDeleteString");
 | 
			
		||||
        getHStringRawBuffer    = (WindowsGetStringRawBufferFuncPtr) ::GetProcAddress (winRTHandle, "WindowsGetStringRawBuffer");
 | 
			
		||||
        roGetActivationFactory = (RoGetActivationFactoryFuncPtr)    ::GetProcAddress (winRTHandle, "RoGetActivationFactory");
 | 
			
		||||
 | 
			
		||||
        if (roInitialize == nullptr || createHString == nullptr || deleteHString == nullptr
 | 
			
		||||
         || getHStringRawBuffer == nullptr || roGetActivationFactory == nullptr)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        HRESULT status = roInitialize (1);
 | 
			
		||||
        initialised = ! (status != S_OK && status != S_FALSE && status != 0x80010106L);
 | 
			
		||||
    }
 | 
			
		||||
    WinRTWrapper();
 | 
			
		||||
 | 
			
		||||
    HMODULE winRTHandle = nullptr;
 | 
			
		||||
    bool initialised = false;
 | 
			
		||||
@ -121,12 +133,14 @@ private:
 | 
			
		||||
    typedef HRESULT (WINAPI* WindowsCreateStringFuncPtr) (LPCWSTR, UINT32, HSTRING*);
 | 
			
		||||
    typedef HRESULT (WINAPI* WindowsDeleteStringFuncPtr) (HSTRING);
 | 
			
		||||
    typedef PCWSTR  (WINAPI* WindowsGetStringRawBufferFuncPtr) (HSTRING, UINT32*);
 | 
			
		||||
    typedef HRESULT (WINAPI* RoActivateInstanceFuncPtr) (HSTRING, IInspectable**);
 | 
			
		||||
    typedef HRESULT (WINAPI* RoGetActivationFactoryFuncPtr) (HSTRING, REFIID, void**);
 | 
			
		||||
 | 
			
		||||
    RoInitializeFuncPtr roInitialize = nullptr;
 | 
			
		||||
    WindowsCreateStringFuncPtr createHString = nullptr;
 | 
			
		||||
    WindowsDeleteStringFuncPtr deleteHString = nullptr;
 | 
			
		||||
    WindowsGetStringRawBufferFuncPtr getHStringRawBuffer = nullptr;
 | 
			
		||||
    RoActivateInstanceFuncPtr roActivateInstance = nullptr;
 | 
			
		||||
    RoGetActivationFactoryFuncPtr roGetActivationFactory = nullptr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,7 @@ class Timer::TimerThread  : private Thread,
 | 
			
		||||
                            private AsyncUpdater
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    typedef CriticalSection LockType; // (mysteriously, using a SpinLock here causes problems on some XP machines..)
 | 
			
		||||
    using LockType = CriticalSection; // (mysteriously, using a SpinLock here causes problems on some XP machines..)
 | 
			
		||||
 | 
			
		||||
    TimerThread()  : Thread ("JUCE Timer")
 | 
			
		||||
    {
 | 
			
		||||
@ -36,7 +36,7 @@ public:
 | 
			
		||||
        triggerAsyncUpdate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~TimerThread() noexcept
 | 
			
		||||
    ~TimerThread() override
 | 
			
		||||
    {
 | 
			
		||||
        signalThreadShouldExit();
 | 
			
		||||
        callbackArrived.signal();
 | 
			
		||||
@ -324,7 +324,7 @@ void Timer::startTimer (int interval) noexcept
 | 
			
		||||
{
 | 
			
		||||
    // If you're calling this before (or after) the MessageManager is
 | 
			
		||||
    // running, then you're not going to get any timer callbacks!
 | 
			
		||||
    jassert (MessageManager::getInstanceWithoutCreating() != nullptr);
 | 
			
		||||
    JUCE_ASSERT_MESSAGE_MANAGER_EXISTS
 | 
			
		||||
 | 
			
		||||
    const TimerThread::LockType::ScopedLockType sl (TimerThread::lock);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user