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:
Alex Birch
2019-06-22 20:41:38 +01:00
parent d22c2cd4fa
commit 9ee566b251
1140 changed files with 67534 additions and 105952 deletions

View File

@ -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)

View File

@ -35,7 +35,7 @@ class JUCE_API ActionListener
{
public:
/** Destructor. */
virtual ~ActionListener() {}
virtual ~ActionListener() = default;
/** Overridden by your subclass to receive the callback.

View File

@ -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();

View File

@ -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();

View File

@ -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.

View File

@ -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);
}

View File

@ -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)

View File

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

View File

@ -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);

View File

@ -45,7 +45,7 @@ public:
InterprocessConnectionServer();
/** Destructor. */
~InterprocessConnectionServer();
~InterprocessConnectionServer() override;
//==============================================================================
/** Starts an internal thread which listens on the given port number.

View File

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

View 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

View File

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

View File

@ -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"

View File

@ -23,7 +23,7 @@
namespace juce
{
JUCEApplicationBase::CreateInstanceFunction JUCEApplicationBase::createInstance = 0;
JUCEApplicationBase::CreateInstanceFunction JUCEApplicationBase::createInstance = nullptr;
JUCEApplicationBase* JUCEApplicationBase::appInstance = nullptr;
#if JUCE_IOS

View File

@ -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)

View File

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

View File

@ -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.

View File

@ -46,7 +46,7 @@ public:
//==============================================================================
/** Creates an uninitialised message. */
Message() noexcept;
~Message();
~Message() override;
using Ptr = ReferenceCountedObjectPtr<Message>;

View File

@ -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()

View File

@ -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()
{

View File

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

View File

@ -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)

View File

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

View File

@ -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
{

View File

@ -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);

View File

@ -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)
}

View File

@ -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;
};

View File

@ -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);