| @@ -32,6 +32,8 @@ | |||
| #include "linuxincludes.h" | |||
| #include <dlfcn.h> | |||
| #include <sys/file.h> | |||
| #include <sys/types.h> | |||
| #include <sys/ptrace.h> | |||
| #include "../../../src/juce_core/basics/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| @@ -339,6 +341,26 @@ void Process::terminate() | |||
| exit (0); | |||
| } | |||
| bool juce_isRunningUnderDebugger() throw() | |||
| { | |||
| static char testResult = 0; | |||
| if (testResult == 0) | |||
| { | |||
| testResult = (ptrace (PTRACE_TRACEME, 0, 0, 0) < 0) ? 1 : -1; | |||
| if (testResult < 0) | |||
| ptrace (PTRACE_DETACH, 0, (caddr_t) 1, 0); | |||
| } | |||
| return testResult > 0; | |||
| } | |||
| bool Process::isRunningUnderDebugger() throw() | |||
| { | |||
| return juce_isRunningUnderDebugger(); | |||
| } | |||
| void Process::raisePrivilege() | |||
| { | |||
| // If running suid root, change effective user | |||
| @@ -1,364 +1,386 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../src/juce_core/basics/juce_StandardHeader.h" | |||
| #include <pthread.h> | |||
| #include <sched.h> | |||
| #include <sys/file.h> | |||
| #include <Carbon/Carbon.h> | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "../../../src/juce_core/threads/juce_CriticalSection.h" | |||
| #include "../../../src/juce_core/threads/juce_WaitableEvent.h" | |||
| #include "../../../src/juce_core/threads/juce_Thread.h" | |||
| #include "../../../src/juce_core/threads/juce_Process.h" | |||
| #include "../../../src/juce_core/threads/juce_InterProcessLock.h" | |||
| #include "../../../src/juce_core/misc/juce_PlatformUtilities.h" | |||
| #include "../../../src/juce_core/io/files/juce_File.h" | |||
| //============================================================================== | |||
| CriticalSection::CriticalSection() throw() | |||
| { | |||
| pthread_mutexattr_t atts; | |||
| pthread_mutexattr_init (&atts); | |||
| pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE); | |||
| pthread_mutex_init (&internal, &atts); | |||
| } | |||
| CriticalSection::~CriticalSection() throw() | |||
| { | |||
| pthread_mutex_destroy (&internal); | |||
| } | |||
| void CriticalSection::enter() const throw() | |||
| { | |||
| pthread_mutex_lock (&internal); | |||
| } | |||
| bool CriticalSection::tryEnter() const throw() | |||
| { | |||
| return pthread_mutex_trylock (&internal) == 0; | |||
| } | |||
| void CriticalSection::exit() const throw() | |||
| { | |||
| pthread_mutex_unlock (&internal); | |||
| } | |||
| //============================================================================== | |||
| struct EventStruct | |||
| { | |||
| pthread_cond_t condition; | |||
| pthread_mutex_t mutex; | |||
| bool triggered; | |||
| }; | |||
| WaitableEvent::WaitableEvent() throw() | |||
| { | |||
| EventStruct* const es = new EventStruct(); | |||
| es->triggered = false; | |||
| pthread_cond_init (&es->condition, 0); | |||
| pthread_mutex_init (&es->mutex, 0); | |||
| internal = es; | |||
| } | |||
| WaitableEvent::~WaitableEvent() throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| pthread_cond_destroy (&es->condition); | |||
| pthread_mutex_destroy (&es->mutex); | |||
| delete es; | |||
| } | |||
| bool WaitableEvent::wait (const int timeOutMillisecs) const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| bool ok = true; | |||
| pthread_mutex_lock (&es->mutex); | |||
| if (! es->triggered) | |||
| { | |||
| if (timeOutMillisecs < 0) | |||
| { | |||
| pthread_cond_wait (&es->condition, &es->mutex); | |||
| } | |||
| else | |||
| { | |||
| struct timespec time; | |||
| time.tv_sec = timeOutMillisecs / 1000; | |||
| time.tv_nsec = (timeOutMillisecs % 1000) * 1000000; | |||
| pthread_cond_timedwait_relative_np (&es->condition, &es->mutex, &time); | |||
| } | |||
| ok = es->triggered; | |||
| } | |||
| es->triggered = false; | |||
| pthread_mutex_unlock (&es->mutex); | |||
| return ok; | |||
| } | |||
| void WaitableEvent::signal() const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| pthread_mutex_lock (&es->mutex); | |||
| es->triggered = true; | |||
| pthread_cond_signal (&es->condition); | |||
| pthread_mutex_unlock (&es->mutex); | |||
| } | |||
| void WaitableEvent::reset() const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| pthread_mutex_lock (&es->mutex); | |||
| es->triggered = false; | |||
| pthread_mutex_unlock (&es->mutex); | |||
| } | |||
| //============================================================================== | |||
| void JUCE_API juce_threadEntryPoint (void*); | |||
| void* threadEntryProc (void* userData) throw() | |||
| { | |||
| juce_threadEntryPoint (userData); | |||
| return 0; | |||
| } | |||
| void* juce_createThread (void* userData) throw() | |||
| { | |||
| pthread_t handle = 0; | |||
| if (pthread_create (&handle, 0, threadEntryProc, userData) == 0) | |||
| { | |||
| pthread_detach (handle); | |||
| return (void*) handle; | |||
| } | |||
| return 0; | |||
| } | |||
| void juce_killThread (void* handle) throw() | |||
| { | |||
| if (handle != 0) | |||
| pthread_cancel ((pthread_t) handle); | |||
| } | |||
| void juce_setCurrentThreadName (const String& /*name*/) throw() | |||
| { | |||
| } | |||
| int Thread::getCurrentThreadId() throw() | |||
| { | |||
| return (int) pthread_self(); | |||
| } | |||
| void juce_setThreadPriority (void* handle, int priority) throw() | |||
| { | |||
| if (handle == 0) | |||
| handle = (void*) pthread_self(); | |||
| struct sched_param param; | |||
| int policy; | |||
| pthread_getschedparam ((pthread_t) handle, &policy, ¶m); | |||
| param.sched_priority = jlimit (1, 127, 1 + (priority * 126) / 11); | |||
| pthread_setschedparam ((pthread_t) handle, policy, ¶m); | |||
| } | |||
| void Thread::yield() throw() | |||
| { | |||
| sched_yield(); | |||
| } | |||
| void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) throw() | |||
| { | |||
| // xxx | |||
| jassertfalse | |||
| } | |||
| void JUCE_CALLTYPE Thread::sleep (int millisecs) throw() | |||
| { | |||
| struct timespec time; | |||
| time.tv_sec = millisecs / 1000; | |||
| time.tv_nsec = (millisecs % 1000) * 1000000; | |||
| nanosleep (&time, 0); | |||
| } | |||
| //============================================================================== | |||
| void Process::raisePrivilege() | |||
| { | |||
| jassertfalse | |||
| } | |||
| void Process::lowerPrivilege() | |||
| { | |||
| jassertfalse | |||
| } | |||
| void Process::terminate() | |||
| { | |||
| ExitToShell(); | |||
| } | |||
| void Process::setPriority (ProcessPriority p) | |||
| { | |||
| // xxx | |||
| } | |||
| void* Process::loadDynamicLibrary (const String& name) | |||
| { | |||
| // xxx needs to use bundles | |||
| FSSpec fs; | |||
| if (PlatformUtilities::makeFSSpecFromPath (&fs, name)) | |||
| { | |||
| CFragConnectionID connID; | |||
| Ptr mainPtr; | |||
| Str255 errorMessage; | |||
| Str63 nm; | |||
| PlatformUtilities::copyToStr63 (nm, name); | |||
| const OSErr err = GetDiskFragment (&fs, 0, kCFragGoesToEOF, nm, kReferenceCFrag, &connID, &mainPtr, errorMessage); | |||
| if (err == noErr) | |||
| return (void*)connID; | |||
| } | |||
| return 0; | |||
| } | |||
| void Process::freeDynamicLibrary (void* handle) | |||
| { | |||
| if (handle != 0) | |||
| CloseConnection ((CFragConnectionID*)&handle); | |||
| } | |||
| void* Process::getProcedureEntryPoint (void* h, const String& procedureName) | |||
| { | |||
| if (h != 0) | |||
| { | |||
| CFragSymbolClass cl; | |||
| Ptr ptr; | |||
| Str255 name; | |||
| PlatformUtilities::copyToStr255 (name, procedureName); | |||
| if (FindSymbol ((CFragConnectionID) h, name, &ptr, &cl) == noErr) | |||
| { | |||
| return ptr; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| //============================================================================== | |||
| InterProcessLock::InterProcessLock (const String& name_) throw() | |||
| : internal (0), | |||
| name (name_), | |||
| reentrancyLevel (0) | |||
| { | |||
| const File tempDir (File::getSpecialLocation (File::tempDirectory)); | |||
| const File temp (tempDir.getChildFile (name)); | |||
| temp.create(); | |||
| internal = (void*) open (temp.getFullPathName().toUTF8(), O_NONBLOCK | O_RDONLY); | |||
| } | |||
| InterProcessLock::~InterProcessLock() throw() | |||
| { | |||
| while (reentrancyLevel > 0) | |||
| this->exit(); | |||
| close ((int) internal); | |||
| } | |||
| bool InterProcessLock::enter (const int timeOutMillisecs) throw() | |||
| { | |||
| if (internal == 0) | |||
| return false; | |||
| if (reentrancyLevel != 0) | |||
| return true; | |||
| if (timeOutMillisecs <= 0) | |||
| { | |||
| if (flock ((int) internal, | |||
| timeOutMillisecs < 0 ? LOCK_EX | |||
| : (LOCK_EX | LOCK_NB)) == 0) | |||
| { | |||
| ++reentrancyLevel; | |||
| return true; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs; | |||
| for (;;) | |||
| { | |||
| if (flock ((int) internal, LOCK_EX | LOCK_NB) == 0) | |||
| { | |||
| ++reentrancyLevel; | |||
| return true; | |||
| } | |||
| if (Time::currentTimeMillis() >= endTime) | |||
| break; | |||
| Thread::sleep (10); | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| void InterProcessLock::exit() throw() | |||
| { | |||
| if (reentrancyLevel > 0 && internal != 0) | |||
| { | |||
| --reentrancyLevel; | |||
| const int result = flock ((int) internal, LOCK_UN); | |||
| (void) result; | |||
| jassert (result == 0); | |||
| } | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../src/juce_core/basics/juce_StandardHeader.h" | |||
| #include <pthread.h> | |||
| #include <sched.h> | |||
| #include <sys/file.h> | |||
| #include <sys/types.h> | |||
| #include <sys/ptrace.h> | |||
| #include <Carbon/Carbon.h> | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "../../../src/juce_core/threads/juce_CriticalSection.h" | |||
| #include "../../../src/juce_core/threads/juce_WaitableEvent.h" | |||
| #include "../../../src/juce_core/threads/juce_Thread.h" | |||
| #include "../../../src/juce_core/threads/juce_Process.h" | |||
| #include "../../../src/juce_core/threads/juce_InterProcessLock.h" | |||
| #include "../../../src/juce_core/misc/juce_PlatformUtilities.h" | |||
| #include "../../../src/juce_core/io/files/juce_File.h" | |||
| //============================================================================== | |||
| CriticalSection::CriticalSection() throw() | |||
| { | |||
| pthread_mutexattr_t atts; | |||
| pthread_mutexattr_init (&atts); | |||
| pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE); | |||
| pthread_mutex_init (&internal, &atts); | |||
| } | |||
| CriticalSection::~CriticalSection() throw() | |||
| { | |||
| pthread_mutex_destroy (&internal); | |||
| } | |||
| void CriticalSection::enter() const throw() | |||
| { | |||
| pthread_mutex_lock (&internal); | |||
| } | |||
| bool CriticalSection::tryEnter() const throw() | |||
| { | |||
| return pthread_mutex_trylock (&internal) == 0; | |||
| } | |||
| void CriticalSection::exit() const throw() | |||
| { | |||
| pthread_mutex_unlock (&internal); | |||
| } | |||
| //============================================================================== | |||
| struct EventStruct | |||
| { | |||
| pthread_cond_t condition; | |||
| pthread_mutex_t mutex; | |||
| bool triggered; | |||
| }; | |||
| WaitableEvent::WaitableEvent() throw() | |||
| { | |||
| EventStruct* const es = new EventStruct(); | |||
| es->triggered = false; | |||
| pthread_cond_init (&es->condition, 0); | |||
| pthread_mutex_init (&es->mutex, 0); | |||
| internal = es; | |||
| } | |||
| WaitableEvent::~WaitableEvent() throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| pthread_cond_destroy (&es->condition); | |||
| pthread_mutex_destroy (&es->mutex); | |||
| delete es; | |||
| } | |||
| bool WaitableEvent::wait (const int timeOutMillisecs) const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| bool ok = true; | |||
| pthread_mutex_lock (&es->mutex); | |||
| if (! es->triggered) | |||
| { | |||
| if (timeOutMillisecs < 0) | |||
| { | |||
| pthread_cond_wait (&es->condition, &es->mutex); | |||
| } | |||
| else | |||
| { | |||
| struct timespec time; | |||
| time.tv_sec = timeOutMillisecs / 1000; | |||
| time.tv_nsec = (timeOutMillisecs % 1000) * 1000000; | |||
| pthread_cond_timedwait_relative_np (&es->condition, &es->mutex, &time); | |||
| } | |||
| ok = es->triggered; | |||
| } | |||
| es->triggered = false; | |||
| pthread_mutex_unlock (&es->mutex); | |||
| return ok; | |||
| } | |||
| void WaitableEvent::signal() const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| pthread_mutex_lock (&es->mutex); | |||
| es->triggered = true; | |||
| pthread_cond_signal (&es->condition); | |||
| pthread_mutex_unlock (&es->mutex); | |||
| } | |||
| void WaitableEvent::reset() const throw() | |||
| { | |||
| EventStruct* const es = (EventStruct*) internal; | |||
| pthread_mutex_lock (&es->mutex); | |||
| es->triggered = false; | |||
| pthread_mutex_unlock (&es->mutex); | |||
| } | |||
| //============================================================================== | |||
| void JUCE_API juce_threadEntryPoint (void*); | |||
| void* threadEntryProc (void* userData) throw() | |||
| { | |||
| juce_threadEntryPoint (userData); | |||
| return 0; | |||
| } | |||
| void* juce_createThread (void* userData) throw() | |||
| { | |||
| pthread_t handle = 0; | |||
| if (pthread_create (&handle, 0, threadEntryProc, userData) == 0) | |||
| { | |||
| pthread_detach (handle); | |||
| return (void*) handle; | |||
| } | |||
| return 0; | |||
| } | |||
| void juce_killThread (void* handle) throw() | |||
| { | |||
| if (handle != 0) | |||
| pthread_cancel ((pthread_t) handle); | |||
| } | |||
| void juce_setCurrentThreadName (const String& /*name*/) throw() | |||
| { | |||
| } | |||
| int Thread::getCurrentThreadId() throw() | |||
| { | |||
| return (int) pthread_self(); | |||
| } | |||
| void juce_setThreadPriority (void* handle, int priority) throw() | |||
| { | |||
| if (handle == 0) | |||
| handle = (void*) pthread_self(); | |||
| struct sched_param param; | |||
| int policy; | |||
| pthread_getschedparam ((pthread_t) handle, &policy, ¶m); | |||
| param.sched_priority = jlimit (1, 127, 1 + (priority * 126) / 11); | |||
| pthread_setschedparam ((pthread_t) handle, policy, ¶m); | |||
| } | |||
| void Thread::yield() throw() | |||
| { | |||
| sched_yield(); | |||
| } | |||
| void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) throw() | |||
| { | |||
| // xxx | |||
| jassertfalse | |||
| } | |||
| void JUCE_CALLTYPE Thread::sleep (int millisecs) throw() | |||
| { | |||
| struct timespec time; | |||
| time.tv_sec = millisecs / 1000; | |||
| time.tv_nsec = (millisecs % 1000) * 1000000; | |||
| nanosleep (&time, 0); | |||
| } | |||
| //============================================================================== | |||
| bool juce_isRunningUnderDebugger() throw() | |||
| { | |||
| static char testResult = 0; | |||
| if (testResult == 0) | |||
| { | |||
| testResult = (ptrace (PT_TRACE_ME, 0, 0, 0) < 0) ? 1 : -1; | |||
| if (testResult < 0) | |||
| ptrace (PT_DETACH, 0, (caddr_t) 1, 0); | |||
| } | |||
| return testResult > 0; | |||
| } | |||
| bool Process::isRunningUnderDebugger() throw() | |||
| { | |||
| return juce_isRunningUnderDebugger(); | |||
| } | |||
| void Process::raisePrivilege() | |||
| { | |||
| jassertfalse | |||
| } | |||
| void Process::lowerPrivilege() | |||
| { | |||
| jassertfalse | |||
| } | |||
| void Process::terminate() | |||
| { | |||
| ExitToShell(); | |||
| } | |||
| void Process::setPriority (ProcessPriority p) | |||
| { | |||
| // xxx | |||
| } | |||
| void* Process::loadDynamicLibrary (const String& name) | |||
| { | |||
| // xxx needs to use bundles | |||
| FSSpec fs; | |||
| if (PlatformUtilities::makeFSSpecFromPath (&fs, name)) | |||
| { | |||
| CFragConnectionID connID; | |||
| Ptr mainPtr; | |||
| Str255 errorMessage; | |||
| Str63 nm; | |||
| PlatformUtilities::copyToStr63 (nm, name); | |||
| const OSErr err = GetDiskFragment (&fs, 0, kCFragGoesToEOF, nm, kReferenceCFrag, &connID, &mainPtr, errorMessage); | |||
| if (err == noErr) | |||
| return (void*)connID; | |||
| } | |||
| return 0; | |||
| } | |||
| void Process::freeDynamicLibrary (void* handle) | |||
| { | |||
| if (handle != 0) | |||
| CloseConnection ((CFragConnectionID*)&handle); | |||
| } | |||
| void* Process::getProcedureEntryPoint (void* h, const String& procedureName) | |||
| { | |||
| if (h != 0) | |||
| { | |||
| CFragSymbolClass cl; | |||
| Ptr ptr; | |||
| Str255 name; | |||
| PlatformUtilities::copyToStr255 (name, procedureName); | |||
| if (FindSymbol ((CFragConnectionID) h, name, &ptr, &cl) == noErr) | |||
| { | |||
| return ptr; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| //============================================================================== | |||
| InterProcessLock::InterProcessLock (const String& name_) throw() | |||
| : internal (0), | |||
| name (name_), | |||
| reentrancyLevel (0) | |||
| { | |||
| const File tempDir (File::getSpecialLocation (File::tempDirectory)); | |||
| const File temp (tempDir.getChildFile (name)); | |||
| temp.create(); | |||
| internal = (void*) open (temp.getFullPathName().toUTF8(), O_NONBLOCK | O_RDONLY); | |||
| } | |||
| InterProcessLock::~InterProcessLock() throw() | |||
| { | |||
| while (reentrancyLevel > 0) | |||
| this->exit(); | |||
| close ((int) internal); | |||
| } | |||
| bool InterProcessLock::enter (const int timeOutMillisecs) throw() | |||
| { | |||
| if (internal == 0) | |||
| return false; | |||
| if (reentrancyLevel != 0) | |||
| return true; | |||
| if (timeOutMillisecs <= 0) | |||
| { | |||
| if (flock ((int) internal, | |||
| timeOutMillisecs < 0 ? LOCK_EX | |||
| : (LOCK_EX | LOCK_NB)) == 0) | |||
| { | |||
| ++reentrancyLevel; | |||
| return true; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| const int64 endTime = Time::currentTimeMillis() + timeOutMillisecs; | |||
| for (;;) | |||
| { | |||
| if (flock ((int) internal, LOCK_EX | LOCK_NB) == 0) | |||
| { | |||
| ++reentrancyLevel; | |||
| return true; | |||
| } | |||
| if (Time::currentTimeMillis() >= endTime) | |||
| break; | |||
| Thread::sleep (10); | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| void InterProcessLock::exit() throw() | |||
| { | |||
| if (reentrancyLevel > 0 && internal != 0) | |||
| { | |||
| --reentrancyLevel; | |||
| const int result = flock ((int) internal, LOCK_UN); | |||
| (void) result; | |||
| jassert (result == 0); | |||
| } | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -299,6 +299,17 @@ void Process::setPriority (ProcessPriority prior) | |||
| } | |||
| } | |||
| bool juce_isRunningUnderDebugger() throw() | |||
| { | |||
| return IsDebuggerPresent() != FALSE; | |||
| } | |||
| bool Process::isRunningUnderDebugger() throw() | |||
| { | |||
| return juce_isRunningUnderDebugger(); | |||
| } | |||
| //============================================================================== | |||
| void Process::raisePrivilege() | |||
| { | |||
| @@ -35,12 +35,31 @@ | |||
| #include <windows.h> | |||
| #include <float.h> | |||
| #pragma warning (disable : 4312) | |||
| #elif defined LINUX | |||
| #include <float.h> | |||
| #include <sys/time.h> | |||
| #include <X11/Xlib.h> | |||
| #include <X11/Xutil.h> | |||
| #include <X11/Xatom.h> | |||
| #undef Font | |||
| #undef KeyPress | |||
| #undef Drawable | |||
| #undef Time | |||
| class VSTPluginWindow; | |||
| #else | |||
| #include <Carbon/Carbon.h> | |||
| #endif | |||
| #include "../../../../../juce.h" | |||
| #include "juce_VSTPluginInstance.h" | |||
| #if JUCE_LINUX | |||
| #define Font JUCE_NAMESPACE::Font | |||
| #define KeyPress JUCE_NAMESPACE::KeyPress | |||
| #define Drawable JUCE_NAMESPACE::Drawable | |||
| #define Time JUCE_NAMESPACE::Time | |||
| #endif | |||
| #include "../juce_PluginDescription.h" | |||
| #if ! JUCE_WIN32 | |||
| @@ -173,6 +192,117 @@ static void* NewCFMFromMachO (void* const machofp) throw() | |||
| #endif | |||
| #endif | |||
| //============================================================================== | |||
| #if JUCE_LINUX | |||
| BEGIN_JUCE_NAMESPACE | |||
| extern Display* display; | |||
| extern XContext improbableNumber; | |||
| END_JUCE_NAMESPACE | |||
| typedef void (*EventProcPtr) (XEvent* ev); | |||
| static bool xErrorTriggered; | |||
| static int temporaryErrorHandler (Display*, XErrorEvent*) | |||
| { | |||
| xErrorTriggered = true; | |||
| return 0; | |||
| } | |||
| static int getPropertyFromXWindow (Window handle, Atom atom) | |||
| { | |||
| XErrorHandler oldErrorHandler = XSetErrorHandler (temporaryErrorHandler); | |||
| xErrorTriggered = false; | |||
| int userSize; | |||
| unsigned long bytes, userCount; | |||
| unsigned char* data; | |||
| Atom userType; | |||
| XGetWindowProperty (display, handle, atom, 0, 1, false, AnyPropertyType, | |||
| &userType, &userSize, &userCount, &bytes, &data); | |||
| XSetErrorHandler (oldErrorHandler); | |||
| return (userCount == 1 && ! xErrorTriggered) ? *(int*) data | |||
| : 0; | |||
| } | |||
| static Window getChildWindow (Window windowToCheck) | |||
| { | |||
| Window rootWindow, parentWindow; | |||
| Window* childWindows; | |||
| unsigned int numChildren; | |||
| XQueryTree (display, | |||
| windowToCheck, | |||
| &rootWindow, | |||
| &parentWindow, | |||
| &childWindows, | |||
| &numChildren); | |||
| if (numChildren > 0) | |||
| return childWindows [0]; | |||
| return 0; | |||
| } | |||
| static void translateJuceToXButtonModifiers (const MouseEvent& e, XEvent& ev) throw() | |||
| { | |||
| if (e.mods.isLeftButtonDown()) | |||
| { | |||
| ev.xbutton.button = Button1; | |||
| ev.xbutton.state |= Button1Mask; | |||
| } | |||
| else if (e.mods.isRightButtonDown()) | |||
| { | |||
| ev.xbutton.button = Button3; | |||
| ev.xbutton.state |= Button3Mask; | |||
| } | |||
| else if (e.mods.isMiddleButtonDown()) | |||
| { | |||
| ev.xbutton.button = Button2; | |||
| ev.xbutton.state |= Button2Mask; | |||
| } | |||
| } | |||
| static void translateJuceToXMotionModifiers (const MouseEvent& e, XEvent& ev) throw() | |||
| { | |||
| if (e.mods.isLeftButtonDown()) | |||
| ev.xmotion.state |= Button1Mask; | |||
| else if (e.mods.isRightButtonDown()) | |||
| ev.xmotion.state |= Button3Mask; | |||
| else if (e.mods.isMiddleButtonDown()) | |||
| ev.xmotion.state |= Button2Mask; | |||
| } | |||
| static void translateJuceToXCrossingModifiers (const MouseEvent& e, XEvent& ev) throw() | |||
| { | |||
| if (e.mods.isLeftButtonDown()) | |||
| ev.xcrossing.state |= Button1Mask; | |||
| else if (e.mods.isRightButtonDown()) | |||
| ev.xcrossing.state |= Button3Mask; | |||
| else if (e.mods.isMiddleButtonDown()) | |||
| ev.xcrossing.state |= Button2Mask; | |||
| } | |||
| static void translateJuceToXMouseWheelModifiers (const MouseEvent& e, const float increment, XEvent& ev) throw() | |||
| { | |||
| if (increment < 0) | |||
| { | |||
| ev.xbutton.button = Button5; | |||
| ev.xbutton.state |= Button5Mask; | |||
| } | |||
| else if (increment > 0) | |||
| { | |||
| ev.xbutton.button = Button4; | |||
| ev.xbutton.state |= Button4Mask; | |||
| } | |||
| } | |||
| #endif | |||
| //============================================================================== | |||
| static VoidArray activeModules; | |||
| @@ -217,9 +347,9 @@ public: | |||
| ModuleHandle (const File& file_) | |||
| : file (file_), | |||
| moduleMain (0), | |||
| #if JUCE_WIN32 | |||
| #if JUCE_WIN32 || JUCE_LINUX | |||
| hModule (0) | |||
| #else | |||
| #elif JUCE_MAC | |||
| fragId (0), | |||
| resHandle (0), | |||
| bundleRef (0), | |||
| @@ -228,9 +358,9 @@ public: | |||
| { | |||
| activeModules.add (this); | |||
| #if JUCE_WIN32 | |||
| #if JUCE_WIN32 || JUCE_LINUX | |||
| fullParentDirectoryPathName = file_.getParentDirectory().getFullPathName(); | |||
| #else | |||
| #elif JUCE_MAC | |||
| PlatformUtilities::makeFSSpecFromPath (&parentDirFSSpec, file_.getParentDirectory().getFullPathName()); | |||
| #endif | |||
| } | |||
| @@ -246,27 +376,13 @@ public: | |||
| juce_UseDebuggingNewOperator | |||
| //============================================================================== | |||
| #if JUCE_WIN32 | |||
| HMODULE hModule; | |||
| #if JUCE_WIN32 || JUCE_LINUX | |||
| void* hModule; | |||
| String fullParentDirectoryPathName; | |||
| static HMODULE loadDLL (const TCHAR* filename) throw() | |||
| { | |||
| HMODULE h = 0; | |||
| __try | |||
| { | |||
| h = LoadLibrary (filename); | |||
| } | |||
| __finally | |||
| { | |||
| } | |||
| return h; | |||
| } | |||
| bool open() | |||
| { | |||
| #if JUCE_WIN32 | |||
| static bool timePeriodSet = false; | |||
| if (! timePeriodSet) | |||
| @@ -274,18 +390,16 @@ public: | |||
| timePeriodSet = true; | |||
| timeBeginPeriod (2); | |||
| } | |||
| #endif | |||
| pluginName = file.getFileNameWithoutExtension(); | |||
| hModule = loadDLL (file.getFullPathName()); | |||
| hModule = Process::loadDynamicLibrary (file.getFullPathName()); | |||
| if (hModule == 0) | |||
| return false; | |||
| moduleMain = (MainCall) GetProcAddress (hModule, "VSTPluginMain"); | |||
| moduleMain = (MainCall) Process::getProcedureEntryPoint (hModule, "VSTPluginMain"); | |||
| if (moduleMain == 0) | |||
| moduleMain = (MainCall) GetProcAddress (hModule, "main"); | |||
| moduleMain = (MainCall) Process::getProcedureEntryPoint (hModule, "main"); | |||
| return moduleMain != 0; | |||
| } | |||
| @@ -294,16 +408,7 @@ public: | |||
| { | |||
| _fpreset(); // (doesn't do any harm) | |||
| if (hModule != 0) | |||
| { | |||
| __try | |||
| { | |||
| FreeLibrary (hModule); | |||
| } | |||
| __finally | |||
| { | |||
| } | |||
| } | |||
| Process::freeDynamicLibrary (hModule); | |||
| } | |||
| void closeEffect (AEffect* eff) | |||
| @@ -758,7 +863,11 @@ void VSTPluginInstance::processBlock (AudioSampleBuffer& buffer, | |||
| { | |||
| #if JUCE_WIN32 | |||
| vstHostTime.nanoSeconds = timeGetTime() * 1000000.0; | |||
| #else | |||
| #elif JUCE_LINUX | |||
| timeval micro; | |||
| gettimeofday (µ, 0); | |||
| vstHostTime.nanoSeconds = micro.tv_usec * 1000.0; | |||
| #elif JUCE_MAC | |||
| UnsignedWide micro; | |||
| Microseconds (µ); | |||
| vstHostTime.nanoSeconds = micro.lo * 1000.0; | |||
| @@ -944,6 +1053,9 @@ public: | |||
| #if JUCE_WIN32 | |||
| sizeCheckCount = 0; | |||
| pluginHWND = 0; | |||
| #elif JUCE_LINUX | |||
| pluginWindow = None; | |||
| pluginProc = None; | |||
| #else | |||
| pluginViewRef = 0; | |||
| #endif | |||
| @@ -1014,9 +1126,16 @@ public: | |||
| { | |||
| repaint(); | |||
| } | |||
| #else | |||
| #elif JUCE_WIN32 | |||
| if (pluginHWND != 0) | |||
| MoveWindow (pluginHWND, x, y, getWidth(), getHeight(), TRUE); | |||
| #elif JUCE_LINUX | |||
| if (pluginWindow != 0) | |||
| { | |||
| XResizeWindow (display, pluginWindow, getWidth(), getHeight()); | |||
| XMoveWindow (display, pluginWindow, x, y); | |||
| XMapRaised (display, pluginWindow); | |||
| } | |||
| #endif | |||
| recursiveResize = false; | |||
| @@ -1072,6 +1191,23 @@ public: | |||
| #if JUCE_MAC | |||
| dispatch (effEditDraw, 0, 0, 0, 0); | |||
| #elif JUCE_LINUX | |||
| if (pluginWindow != 0) | |||
| { | |||
| const Rectangle clip (g.getClipBounds()); | |||
| XEvent ev; | |||
| zerostruct (ev); | |||
| ev.xexpose.type = Expose; | |||
| ev.xexpose.display = display; | |||
| ev.xexpose.window = pluginWindow; | |||
| ev.xexpose.x = clip.getX(); | |||
| ev.xexpose.y = clip.getY(); | |||
| ev.xexpose.width = clip.getWidth(); | |||
| ev.xexpose.height = clip.getHeight(); | |||
| sendEventToChild (&ev); | |||
| } | |||
| #endif | |||
| } | |||
| } | |||
| @@ -1123,6 +1259,29 @@ public: | |||
| { | |||
| PostEvent (::mouseDown, 0); | |||
| } | |||
| #elif JUCE_LINUX | |||
| if (pluginWindow == 0) | |||
| return; | |||
| toFront (true); | |||
| XEvent ev; | |||
| zerostruct (ev); | |||
| ev.xbutton.display = display; | |||
| ev.xbutton.type = ButtonPress; | |||
| ev.xbutton.window = pluginWindow; | |||
| ev.xbutton.root = RootWindow (display, DefaultScreen (display)); | |||
| ev.xbutton.time = CurrentTime; | |||
| ev.xbutton.x = e.x; | |||
| ev.xbutton.y = e.y; | |||
| ev.xbutton.x_root = e.getScreenX(); | |||
| ev.xbutton.y_root = e.getScreenY(); | |||
| translateJuceToXButtonModifiers (e, ev); | |||
| sendEventToChild (&ev); | |||
| #else | |||
| (void) e; | |||
| @@ -1152,9 +1311,12 @@ private: | |||
| HWND pluginHWND; | |||
| void* originalWndProc; | |||
| int sizeCheckCount; | |||
| #else | |||
| #elif JUCE_MAC | |||
| HIViewRef pluginViewRef; | |||
| WindowRef pluginWindowRef; | |||
| #elif JUCE_LINUX | |||
| Window pluginWindow; | |||
| EventProcPtr pluginProc; | |||
| #endif | |||
| //============================================================================== | |||
| @@ -1231,7 +1393,7 @@ private: | |||
| } | |||
| } | |||
| } | |||
| #else | |||
| #elif JUCE_MAC | |||
| HIViewRef root = HIViewGetRoot ((WindowRef) getWindowHandle()); | |||
| HIViewFindByID (root, kHIViewWindowContentID, &root); | |||
| pluginViewRef = HIViewGetFirstSubview (root); | |||
| @@ -1269,6 +1431,30 @@ private: | |||
| h = 150; | |||
| } | |||
| } | |||
| #elif JUCE_LINUX | |||
| pluginWindow = getChildWindow ((Window) getWindowHandle()); | |||
| if (pluginWindow != 0) | |||
| pluginProc = (EventProcPtr) getPropertyFromXWindow (pluginWindow, | |||
| XInternAtom (display, "_XEventProc", False)); | |||
| int w = 250, h = 150; | |||
| if (rect != 0) | |||
| { | |||
| w = rect->right - rect->left; | |||
| h = rect->bottom - rect->top; | |||
| if (w == 0 || h == 0) | |||
| { | |||
| w = 250; | |||
| h = 150; | |||
| } | |||
| } | |||
| if (pluginWindow != 0) | |||
| XMapRaised (display, pluginWindow); | |||
| #endif | |||
| // double-check it's not too tiny | |||
| @@ -1310,10 +1496,14 @@ private: | |||
| DestroyWindow (pluginHWND); | |||
| pluginHWND = 0; | |||
| #else | |||
| #elif JUCE_MAC | |||
| dispatch (effEditSleep, 0, 0, 0, 0); | |||
| pluginViewRef = 0; | |||
| stopTimer(); | |||
| #elif JUCE_LINUX | |||
| stopTimer(); | |||
| pluginWindow = 0; | |||
| pluginProc = 0; | |||
| #endif | |||
| } | |||
| } | |||
| @@ -1408,6 +1598,168 @@ private: | |||
| return DefWindowProc (hW, message, wParam, lParam); | |||
| } | |||
| #endif | |||
| #if JUCE_LINUX | |||
| //============================================================================== | |||
| // overload mouse/keyboard events to forward them to the plugin's inner window.. | |||
| void sendEventToChild (XEvent* event) | |||
| { | |||
| if (pluginProc != 0) | |||
| { | |||
| // if the plugin publishes an event procedure, pass the event directly.. | |||
| pluginProc (event); | |||
| } | |||
| else if (pluginWindow != 0) | |||
| { | |||
| // if the plugin has a window, then send the event to the window so that | |||
| // its message thread will pick it up.. | |||
| XSendEvent (display, pluginWindow, False, 0L, event); | |||
| XFlush (display); | |||
| } | |||
| } | |||
| void mouseEnter (const MouseEvent& e) | |||
| { | |||
| if (pluginWindow != 0) | |||
| { | |||
| XEvent ev; | |||
| zerostruct (ev); | |||
| ev.xcrossing.display = display; | |||
| ev.xcrossing.type = EnterNotify; | |||
| ev.xcrossing.window = pluginWindow; | |||
| ev.xcrossing.root = RootWindow (display, DefaultScreen (display)); | |||
| ev.xcrossing.time = CurrentTime; | |||
| ev.xcrossing.x = e.x; | |||
| ev.xcrossing.y = e.y; | |||
| ev.xcrossing.x_root = e.getScreenX(); | |||
| ev.xcrossing.y_root = e.getScreenY(); | |||
| ev.xcrossing.mode = NotifyNormal; // NotifyGrab, NotifyUngrab | |||
| ev.xcrossing.detail = NotifyAncestor; // NotifyVirtual, NotifyInferior, NotifyNonlinear,NotifyNonlinearVirtual | |||
| translateJuceToXCrossingModifiers (e, ev); | |||
| sendEventToChild (&ev); | |||
| } | |||
| } | |||
| void mouseExit (const MouseEvent& e) | |||
| { | |||
| if (pluginWindow != 0) | |||
| { | |||
| XEvent ev; | |||
| zerostruct (ev); | |||
| ev.xcrossing.display = display; | |||
| ev.xcrossing.type = LeaveNotify; | |||
| ev.xcrossing.window = pluginWindow; | |||
| ev.xcrossing.root = RootWindow (display, DefaultScreen (display)); | |||
| ev.xcrossing.time = CurrentTime; | |||
| ev.xcrossing.x = e.x; | |||
| ev.xcrossing.y = e.y; | |||
| ev.xcrossing.x_root = e.getScreenX(); | |||
| ev.xcrossing.y_root = e.getScreenY(); | |||
| ev.xcrossing.mode = NotifyNormal; // NotifyGrab, NotifyUngrab | |||
| ev.xcrossing.detail = NotifyAncestor; // NotifyVirtual, NotifyInferior, NotifyNonlinear,NotifyNonlinearVirtual | |||
| ev.xcrossing.focus = hasKeyboardFocus (true); // TODO - yes ? | |||
| translateJuceToXCrossingModifiers (e, ev); | |||
| sendEventToChild (&ev); | |||
| } | |||
| } | |||
| void mouseMove (const MouseEvent& e) | |||
| { | |||
| if (pluginWindow != 0) | |||
| { | |||
| XEvent ev; | |||
| zerostruct (ev); | |||
| ev.xmotion.display = display; | |||
| ev.xmotion.type = MotionNotify; | |||
| ev.xmotion.window = pluginWindow; | |||
| ev.xmotion.root = RootWindow (display, DefaultScreen (display)); | |||
| ev.xmotion.time = CurrentTime; | |||
| ev.xmotion.is_hint = NotifyNormal; | |||
| ev.xmotion.x = e.x; | |||
| ev.xmotion.y = e.y; | |||
| ev.xmotion.x_root = e.getScreenX(); | |||
| ev.xmotion.y_root = e.getScreenY(); | |||
| sendEventToChild (&ev); | |||
| } | |||
| } | |||
| void mouseDrag (const MouseEvent& e) | |||
| { | |||
| if (pluginWindow != 0) | |||
| { | |||
| XEvent ev; | |||
| zerostruct (ev); | |||
| ev.xmotion.display = display; | |||
| ev.xmotion.type = MotionNotify; | |||
| ev.xmotion.window = pluginWindow; | |||
| ev.xmotion.root = RootWindow (display, DefaultScreen (display)); | |||
| ev.xmotion.time = CurrentTime; | |||
| ev.xmotion.x = e.x ; | |||
| ev.xmotion.y = e.y; | |||
| ev.xmotion.x_root = e.getScreenX(); | |||
| ev.xmotion.y_root = e.getScreenY(); | |||
| ev.xmotion.is_hint = NotifyNormal; | |||
| translateJuceToXMotionModifiers (e, ev); | |||
| sendEventToChild (&ev); | |||
| } | |||
| } | |||
| void mouseUp (const MouseEvent& e) | |||
| { | |||
| if (pluginWindow != 0) | |||
| { | |||
| XEvent ev; | |||
| zerostruct (ev); | |||
| ev.xbutton.display = display; | |||
| ev.xbutton.type = ButtonRelease; | |||
| ev.xbutton.window = pluginWindow; | |||
| ev.xbutton.root = RootWindow (display, DefaultScreen (display)); | |||
| ev.xbutton.time = CurrentTime; | |||
| ev.xbutton.x = e.x; | |||
| ev.xbutton.y = e.y; | |||
| ev.xbutton.x_root = e.getScreenX(); | |||
| ev.xbutton.y_root = e.getScreenY(); | |||
| translateJuceToXButtonModifiers (e, ev); | |||
| sendEventToChild (&ev); | |||
| } | |||
| } | |||
| void mouseWheelMove (const MouseEvent& e, | |||
| float incrementX, | |||
| float incrementY) | |||
| { | |||
| if (pluginWindow != 0) | |||
| { | |||
| XEvent ev; | |||
| zerostruct (ev); | |||
| ev.xbutton.display = display; | |||
| ev.xbutton.type = ButtonPress; | |||
| ev.xbutton.window = pluginWindow; | |||
| ev.xbutton.root = RootWindow (display, DefaultScreen (display)); | |||
| ev.xbutton.time = CurrentTime; | |||
| ev.xbutton.x = e.x; | |||
| ev.xbutton.y = e.y; | |||
| ev.xbutton.x_root = e.getScreenX(); | |||
| ev.xbutton.y_root = e.getScreenY(); | |||
| translateJuceToXMouseWheelModifiers (e, incrementY, ev); | |||
| sendEventToChild (&ev); | |||
| // TODO - put a usleep here ? | |||
| ev.xbutton.type = ButtonRelease; | |||
| sendEventToChild (&ev); | |||
| } | |||
| } | |||
| #endif | |||
| }; | |||
| //============================================================================== | |||
| @@ -2533,9 +2885,12 @@ bool VSTPluginFormat::fileMightContainThisPluginType (const File& f) | |||
| #endif | |||
| return false; | |||
| #else | |||
| #elif JUCE_WIN32 | |||
| return f.existsAsFile() | |||
| && f.hasFileExtension (T(".dll")); | |||
| #elif JUCE_LINUX | |||
| return f.existsAsFile() | |||
| && f.hasFileExtension (T(".so")); | |||
| #endif | |||
| } | |||
| @@ -2543,9 +2898,11 @@ const FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch() | |||
| { | |||
| #if JUCE_MAC | |||
| return FileSearchPath ("~/Library/Audio/Plug-Ins/VST;/Library/Audio/Plug-Ins/VST"); | |||
| #else | |||
| #elif JUCE_WIN32 | |||
| const String programFiles (File::getSpecialLocation (File::globalApplicationsDirectory).getFullPathName()); | |||
| return FileSearchPath (programFiles + "\\Steinberg\\VstPlugins"); | |||
| #elif JUCE_LINUX | |||
| return FileSearchPath ("/usr/lib/vst"); | |||
| #endif | |||
| } | |||
| @@ -5160,7 +5160,7 @@ static const unsigned char temp9[] = {47,42,13,10,32,32,61,61,61,61,61,61,61,61, | |||
| 46,76,105,98,34,41,13,10,32,35,101,110,100,105,102,13,10,35,101,108,105,102,32,100,101,102,105,110,101,100,32,40,76,73,78,85,88,41,13,10, | |||
| 32,35,105,110,99,108,117,100,101,32,60,71,76,47,103,108,46,104,62,13,10,32,35,105,110,99,108,117,100,101,32,60,71,76,47,103,108,117,116,46, | |||
| 104,62,13,10,32,35,117,110,100,101,102,32,75,101,121,80,114,101,115,115,13,10,35,101,108,115,101,13,10,32,35,105,110,99,108,117,100,101,32,60, | |||
| 97,103,108,47,97,103,108,46,104,62,13,10,32,35,105,110,99,108,117,100,101,32,60,103,108,117,116,47,103,108,117,116,46,104,62,13,10,35,101,110, | |||
| 65,71,76,47,97,103,108,46,104,62,13,10,32,35,105,110,99,108,117,100,101,32,60,71,76,85,84,47,103,108,117,116,46,104,62,13,10,35,101,110, | |||
| 100,105,102,13,10,13,10,35,105,102,110,100,101,102,32,71,76,95,66,71,82,65,95,69,88,84,13,10,32,35,100,101,102,105,110,101,32,71,76,95, | |||
| 66,71,82,65,95,69,88,84,32,48,120,56,48,101,49,13,10,35,101,110,100,105,102,13,10,13,10,47,47,61,61,61,61,61,61,61,61,61,61,61, | |||
| 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, | |||
| @@ -343,6 +343,22 @@ public: | |||
| void handleAsyncUpdate(); | |||
| /** @internal */ | |||
| const String getTooltip() { return label->getTooltip(); } | |||
| /** @internal */ | |||
| void mouseDown (const MouseEvent&); | |||
| /** @internal */ | |||
| void mouseDrag (const MouseEvent&); | |||
| /** @internal */ | |||
| void mouseUp (const MouseEvent&); | |||
| /** @internal */ | |||
| void lookAndFeelChanged(); | |||
| /** @internal */ | |||
| void paint (Graphics&); | |||
| /** @internal */ | |||
| void resized(); | |||
| /** @internal */ | |||
| bool keyStateChanged(); | |||
| /** @internal */ | |||
| bool keyPressed (const KeyPress&); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| @@ -367,15 +383,6 @@ private: | |||
| Label* label; | |||
| String textWhenNothingSelected, noChoicesMessage; | |||
| void mouseDown (const MouseEvent&); | |||
| void mouseDrag (const MouseEvent&); | |||
| void mouseUp (const MouseEvent&); | |||
| void lookAndFeelChanged(); | |||
| void paint (Graphics&); | |||
| void resized(); | |||
| bool keyStateChanged(); | |||
| bool keyPressed (const KeyPress&); | |||
| void showPopup(); | |||
| ItemInfo* getItemForId (const int id) const throw(); | |||
| @@ -190,6 +190,10 @@ | |||
| //============================================================================== | |||
| // Assertions.. | |||
| BEGIN_JUCE_NAMESPACE | |||
| extern bool juce_isRunningUnderDebugger() throw(); | |||
| END_JUCE_NAMESPACE | |||
| #if JUCE_MSVC || DOXYGEN | |||
| #if JUCE_USE_INTRINSICS | |||
| @@ -202,7 +206,7 @@ | |||
| @see jassert() | |||
| */ | |||
| #define jassertfalse { juce_LogCurrentAssertion; __debugbreak(); } | |||
| #define jassertfalse { juce_LogCurrentAssertion; if (juce_isRunningUnderDebugger()) __debugbreak(); } | |||
| #else | |||
| /** This will always cause an assertion failure. | |||
| @@ -210,12 +214,12 @@ | |||
| @see jassert() | |||
| */ | |||
| #define jassertfalse { juce_LogCurrentAssertion; __asm int 3 } | |||
| #define jassertfalse { juce_LogCurrentAssertion; if (juce_isRunningUnderDebugger()) { __asm int 3 } } | |||
| #endif | |||
| #elif defined (JUCE_MAC) | |||
| #define jassertfalse { juce_LogCurrentAssertion; Debugger(); } | |||
| #define jassertfalse { juce_LogCurrentAssertion; if (juce_isRunningUnderDebugger()) Debugger(); } | |||
| #elif defined (JUCE_GCC) || defined (JUCE_LINUX) | |||
| #define jassertfalse { juce_LogCurrentAssertion; asm("int $3"); } | |||
| #define jassertfalse { juce_LogCurrentAssertion; if (juce_isRunningUnderDebugger()) asm("int $3"); } | |||
| #endif | |||
| //============================================================================== | |||
| @@ -54,12 +54,20 @@ | |||
| //============================================================================== | |||
| #include "../../../juce_Config.h" | |||
| //============================================================================== | |||
| #ifdef JUCE_NAMESPACE | |||
| #define BEGIN_JUCE_NAMESPACE namespace JUCE_NAMESPACE { | |||
| #define END_JUCE_NAMESPACE } | |||
| #else | |||
| #define BEGIN_JUCE_NAMESPACE | |||
| #define END_JUCE_NAMESPACE | |||
| #endif | |||
| //============================================================================== | |||
| // This sets up the JUCE_WIN32, JUCE_MAC, or JUCE_LINUX macros | |||
| #include "juce_PlatformDefs.h" | |||
| //============================================================================== | |||
| // Now we'll include any OS headers we need.. (at this point we are outside the Juce namespace). | |||
| #if JUCE_MSVC | |||
| #pragma warning (push) | |||
| #pragma warning (disable: 4514 4245 4100) | |||
| @@ -93,15 +101,6 @@ | |||
| #pragma warning (pop) | |||
| #endif | |||
| //============================================================================== | |||
| #ifdef JUCE_NAMESPACE | |||
| #define BEGIN_JUCE_NAMESPACE namespace JUCE_NAMESPACE { | |||
| #define END_JUCE_NAMESPACE } | |||
| #else | |||
| #define BEGIN_JUCE_NAMESPACE | |||
| #define END_JUCE_NAMESPACE | |||
| #endif | |||
| //============================================================================== | |||
| // DLL building settings on Win32 | |||
| #if JUCE_MSVC | |||
| @@ -439,15 +439,19 @@ bool File::isAChildOf (const File& potentialParent) const throw() | |||
| } | |||
| //============================================================================== | |||
| const File File::getChildFile (String relativePath) const throw() | |||
| bool File::isAbsolutePath (const String& path) throw() | |||
| { | |||
| if (relativePath.startsWithChar (T('/')) | |||
| || relativePath.startsWithChar (T('\\')) | |||
| return path.startsWithChar (T('/')) || path.startsWithChar (T('\\')) | |||
| #if JUCE_WIN32 | |||
| || (relativePath.isNotEmpty() && ((const String&) relativePath)[1] == T(':'))) | |||
| || (path.isNotEmpty() && ((const String&) path)[1] == T(':')); | |||
| #else | |||
| || relativePath.startsWithChar (T('~'))) | |||
| || path.startsWithChar (T('~')); | |||
| #endif | |||
| } | |||
| const File File::getChildFile (String relativePath) const throw() | |||
| { | |||
| if (isAbsolutePath (relativePath)) | |||
| { | |||
| // the path is really absolute.. | |||
| return File (relativePath); | |||
| @@ -182,7 +182,7 @@ public: | |||
| be relative to. If this is actually a file rather than | |||
| a directory, its parent directory will be used instead. | |||
| If it doesn't exist, it's assumed to be a directory. | |||
| @see getChildFile | |||
| @see getChildFile, isAbsolutePath | |||
| */ | |||
| const String getRelativePathFrom (const File& directoryToBeRelativeTo) const throw(); | |||
| @@ -834,6 +834,10 @@ public: | |||
| */ | |||
| static bool areFileNamesCaseSensitive(); | |||
| /** Returns true if the string seems to be a fully-specified absolute path. | |||
| */ | |||
| static bool isAbsolutePath (const String& path) throw(); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| @@ -93,6 +93,11 @@ public: | |||
| */ | |||
| static void lowerPrivilege(); | |||
| //============================================================================== | |||
| /** Returns true if this process is being hosted by a debugger. | |||
| */ | |||
| static bool isRunningUnderDebugger() throw(); | |||
| //============================================================================== | |||
| /** Loads a dynamically-linked library into the process's address space. | |||