| @@ -118,8 +118,8 @@ class LADSPAPluginInstance : public AudioPluginInstance | |||
| { | |||
| public: | |||
| LADSPAPluginInstance (const LADSPAModuleHandle::Ptr& m) | |||
| : plugin (nullptr), handle (nullptr), initialised (false), | |||
| tempBuffer (1, 1), module (m) | |||
| : module (m), plugin (nullptr), handle (nullptr), | |||
| initialised (false), tempBuffer (1, 1) | |||
| { | |||
| ++insideLADSPACallback; | |||
| @@ -79,10 +79,11 @@ JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger() | |||
| return juce_isRunningUnderDebugger(); | |||
| } | |||
| static void swapUserAndEffectiveUser() | |||
| static bool swapUserAndEffectiveUser() | |||
| { | |||
| (void) setreuid (geteuid(), getuid()); | |||
| (void) setregid (getegid(), getgid()); | |||
| int result1 = setreuid (geteuid(), getuid()); | |||
| int result2 = setregid (getegid(), getgid()); | |||
| return result1 == 0 && result2 == 0; | |||
| } | |||
| JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() { if (geteuid() != 0 && getuid() == 0) swapUserAndEffectiveUser(); } | |||
| @@ -94,24 +94,20 @@ private: | |||
| //============================================================================== | |||
| Value::Value() | |||
| : value (new SimpleValueSource()) | |||
| Value::Value() : value (new SimpleValueSource()) | |||
| { | |||
| } | |||
| Value::Value (ValueSource* const v) | |||
| : value (v) | |||
| Value::Value (ValueSource* const v) : value (v) | |||
| { | |||
| jassert (v != nullptr); | |||
| } | |||
| Value::Value (const var& initialValue) | |||
| : value (new SimpleValueSource (initialValue)) | |||
| Value::Value (const var& initialValue) : value (new SimpleValueSource (initialValue)) | |||
| { | |||
| } | |||
| Value::Value (const Value& other) | |||
| : value (other.value) | |||
| Value::Value (const Value& other) : value (other.value) | |||
| { | |||
| } | |||
| @@ -123,12 +119,22 @@ Value& Value::operator= (const Value& other) | |||
| #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||
| Value::Value (Value&& other) noexcept | |||
| : value (static_cast<ReferenceCountedObjectPtr<ValueSource>&&> (other.value)) | |||
| { | |||
| // moving a Value with listeners will lose those listeners, which | |||
| // probably isn't what you wanted to happen! | |||
| jassert (other.listeners.size() == 0); | |||
| other.removeFromListenerList(); | |||
| value = static_cast<ReferenceCountedObjectPtr<ValueSource>&&> (other.value); | |||
| } | |||
| Value& Value::operator= (Value&& other) noexcept | |||
| { | |||
| // moving a Value with listeners will lose those listeners, which | |||
| // probably isn't what you wanted to happen! | |||
| jassert (other.listeners.size() == 0); | |||
| other.removeFromListenerList(); | |||
| value = static_cast<ReferenceCountedObjectPtr<ValueSource>&&> (other.value); | |||
| return *this; | |||
| } | |||
| @@ -136,7 +142,12 @@ Value& Value::operator= (Value&& other) noexcept | |||
| Value::~Value() | |||
| { | |||
| if (listeners.size() > 0) | |||
| removeFromListenerList(); | |||
| } | |||
| void Value::removeFromListenerList() | |||
| { | |||
| if (listeners.size() > 0 && value != nullptr) // may be nullptr after a move operation | |||
| value->valuesWithListeners.removeValue (this); | |||
| } | |||
| @@ -217,6 +217,7 @@ private: | |||
| ListenerList<Listener> listeners; | |||
| void callListeners(); | |||
| void removeFromListenerList(); | |||
| // This is disallowed to avoid confusion about whether it should | |||
| // do a by-value or by-reference copy. | |||
| @@ -27,7 +27,7 @@ enum { magicMastSlaveConnectionHeader = 0x712baf04 }; | |||
| static const char* startMessage = "__ipc_st"; | |||
| static const char* killMessage = "__ipc_k_"; | |||
| static const char* pingMessage = "__ipc_p_"; | |||
| enum { specialMessageSize = 8 }; | |||
| enum { specialMessageSize = 8, defaultTimeoutMs = 8000 }; | |||
| static String getCommandLinePrefix (const String& commandLineUniqueID) | |||
| { | |||
| @@ -40,7 +40,7 @@ static String getCommandLinePrefix (const String& commandLineUniqueID) | |||
| struct ChildProcessPingThread : public Thread, | |||
| private AsyncUpdater | |||
| { | |||
| ChildProcessPingThread() : Thread ("IPC ping"), timeoutMs (8000) | |||
| ChildProcessPingThread (int timeout) : Thread ("IPC ping"), timeoutMs (timeout) | |||
| { | |||
| pingReceived(); | |||
| } | |||
| @@ -84,8 +84,10 @@ private: | |||
| struct ChildProcessMaster::Connection : public InterprocessConnection, | |||
| private ChildProcessPingThread | |||
| { | |||
| Connection (ChildProcessMaster& m, const String& pipeName) | |||
| : InterprocessConnection (false, magicMastSlaveConnectionHeader), owner (m) | |||
| Connection (ChildProcessMaster& m, const String& pipeName, int timeout) | |||
| : InterprocessConnection (false, magicMastSlaveConnectionHeader), | |||
| ChildProcessPingThread (timeout), | |||
| owner (m) | |||
| { | |||
| if (createPipe (pipeName, timeoutMs)) | |||
| startThread (4); | |||
| @@ -140,7 +142,7 @@ bool ChildProcessMaster::sendMessageToSlave (const MemoryBlock& mb) | |||
| return false; | |||
| } | |||
| bool ChildProcessMaster::launchSlaveProcess (const File& executable, const String& commandLineUniqueID) | |||
| bool ChildProcessMaster::launchSlaveProcess (const File& executable, const String& commandLineUniqueID, int timeoutMs) | |||
| { | |||
| connection = nullptr; | |||
| jassert (childProcess.kill()); | |||
| @@ -153,7 +155,7 @@ bool ChildProcessMaster::launchSlaveProcess (const File& executable, const Strin | |||
| if (childProcess.start (args)) | |||
| { | |||
| connection = new Connection (*this, pipeName); | |||
| connection = new Connection (*this, pipeName, timeoutMs <= 0 ? defaultTimeoutMs : timeoutMs); | |||
| if (connection->isConnected()) | |||
| { | |||
| @@ -171,8 +173,10 @@ bool ChildProcessMaster::launchSlaveProcess (const File& executable, const Strin | |||
| struct ChildProcessSlave::Connection : public InterprocessConnection, | |||
| private ChildProcessPingThread | |||
| { | |||
| Connection (ChildProcessSlave& p, const String& pipeName) | |||
| : InterprocessConnection (false, magicMastSlaveConnectionHeader), owner (p) | |||
| Connection (ChildProcessSlave& p, const String& pipeName, int timeout) | |||
| : InterprocessConnection (false, magicMastSlaveConnectionHeader), | |||
| ChildProcessPingThread (timeout), | |||
| owner (p) | |||
| { | |||
| connectToPipe (pipeName, timeoutMs); | |||
| startThread (4); | |||
| @@ -237,7 +241,8 @@ bool ChildProcessSlave::sendMessageToMaster (const MemoryBlock& mb) | |||
| } | |||
| bool ChildProcessSlave::initialiseFromCommandLine (const String& commandLine, | |||
| const String& commandLineUniqueID) | |||
| const String& commandLineUniqueID, | |||
| int timeoutMs) | |||
| { | |||
| String prefix (getCommandLinePrefix (commandLineUniqueID)); | |||
| @@ -248,7 +253,7 @@ bool ChildProcessSlave::initialiseFromCommandLine (const String& commandLine, | |||
| if (pipeName.isNotEmpty()) | |||
| { | |||
| connection = new Connection (*this, pipeName); | |||
| connection = new Connection (*this, pipeName, timeoutMs <= 0 ? defaultTimeoutMs : timeoutMs); | |||
| if (! connection->isConnected()) | |||
| connection = nullptr; | |||
| @@ -64,10 +64,16 @@ public: | |||
| The commandLineUniqueID should be a short alphanumeric identifier (no spaces!) | |||
| that matches the string passed to ChildProcessMaster::launchSlaveProcess(). | |||
| The timeoutMs parameter lets you specify how long the child process is allowed | |||
| to run without receiving a ping from the master before the master is considered to | |||
| have died, and handleConnectionLost() will be called. Passing <= 0 for this timeout | |||
| makes it use a default value. | |||
| Returns true if the command-line matches and the connection is made successfully. | |||
| */ | |||
| bool initialiseFromCommandLine (const String& commandLine, | |||
| const String& commandLineUniqueID); | |||
| const String& commandLineUniqueID, | |||
| int timeoutMs = 0); | |||
| //============================================================================== | |||
| /** This will be called to deliver messages from the master process. | |||
| @@ -141,11 +147,17 @@ public: | |||
| that gets launched must respond by calling ChildProcessSlave::initialiseFromCommandLine() | |||
| in its startup code, and must use a matching ID to commandLineUniqueID. | |||
| The timeoutMs parameter lets you specify how long the child process is allowed | |||
| to go without sending a ping before it is considered to have died and | |||
| handleConnectionLost() will be called. Passing <= 0 for this timeout makes | |||
| it use a default value. | |||
| If this all works, the method returns true, and you can begin sending and | |||
| receiving messages with the slave process. | |||
| */ | |||
| bool launchSlaveProcess (const File& executableToLaunch, | |||
| const String& commandLineUniqueID); | |||
| const String& commandLineUniqueID, | |||
| int timeoutMs = 0); | |||
| /** This will be called to deliver a message from the slave process. | |||
| The call will probably be made on a background thread, so be careful with your thread-safety! | |||
| @@ -589,6 +589,10 @@ namespace EdgeTableFillers | |||
| filler[2].set (sourceColour); | |||
| filler[3].set (sourceColour); | |||
| } | |||
| else | |||
| { | |||
| areRGBComponentsEqual = false; | |||
| } | |||
| } | |||
| forcedinline void setEdgeTableYPos (const int y) noexcept | |||
| @@ -3049,7 +3049,7 @@ void Desktop::Displays::findDisplays (float masterScale) | |||
| d.userArea = d.totalArea = Rectangle<int> (screens[j].x_org, | |||
| screens[j].y_org, | |||
| screens[j].width, | |||
| screens[j].height) * masterScale; | |||
| screens[j].height) / masterScale; | |||
| d.isMain = (index == 0); | |||
| d.scale = masterScale; | |||
| d.dpi = getDisplayDPI (0); // (all screens share the same DPI) | |||
| @@ -1931,7 +1931,7 @@ bool TextEditor::deleteBackwards (bool moveInWholeWordSteps) | |||
| if (moveInWholeWordSteps) | |||
| moveCaretTo (findWordBreakBefore (getCaretPosition()), true); | |||
| else if (selection.isEmpty() && selection.getStart() > 0) | |||
| selection.setStart (selection.getEnd() - 1); | |||
| selection = Range<int> (selection.getEnd() - 1, selection.getEnd()); | |||
| cut(); | |||
| return true; | |||
| @@ -1940,7 +1940,7 @@ bool TextEditor::deleteBackwards (bool moveInWholeWordSteps) | |||
| bool TextEditor::deleteForwards (bool /*moveInWholeWordSteps*/) | |||
| { | |||
| if (selection.isEmpty() && selection.getStart() < getTotalNumChars()) | |||
| selection.setEnd (selection.getStart() + 1); | |||
| selection = Range<int> (selection.getStart(), selection.getStart() + 1); | |||
| cut(); | |||
| return true; | |||