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