diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 89274645ce..846e474229 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -96,17 +96,24 @@ #define JUCE_INTEL 1 #endif -#if JUCE_MAC +#if JUCE_MAC || JUCE_IOS - #ifndef NDEBUG + #if defined (DEBUG) || defined (_DEBUG) || ! (defined (NDEBUG) || defined (_NDEBUG)) #define JUCE_DEBUG 1 #endif + #if ! (defined (DEBUG) || defined (_DEBUG) || defined (NDEBUG) || defined (_NDEBUG)) + #warning "Neither NDEBUG or DEBUG has been defined - you should set one of these to make it clear whether this is a release build," + #endif + #ifdef __LITTLE_ENDIAN__ #define JUCE_LITTLE_ENDIAN 1 #else #define JUCE_BIG_ENDIAN 1 #endif +#endif + +#if JUCE_MAC #if defined (__ppc__) || defined (__ppc64__) #define JUCE_PPC 1 @@ -130,19 +137,6 @@ #endif -#if JUCE_IOS - - #ifndef NDEBUG - #define JUCE_DEBUG 1 - #endif - - #ifdef __LITTLE_ENDIAN__ - #define JUCE_LITTLE_ENDIAN 1 - #else - #define JUCE_BIG_ENDIAN 1 - #endif -#endif - #if JUCE_LINUX #ifdef _DEBUG @@ -2241,8 +2235,6 @@ JUCE_API void JUCE_CALLTYPE shutdownJuce_NonGUI() #if ! JUCE_ONLY_BUILD_CORE_LIBRARY -void juce_setCurrentThreadName (const String& name); - static bool juceInitialisedGUI = false; JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI() @@ -2256,12 +2248,9 @@ JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI() MessageManager::getInstance(); LookAndFeel::setDefaultLookAndFeel (0); - juce_setCurrentThreadName ("Juce Message Thread"); #if JUCE_DEBUG - // This section is just for catching people who mess up their project settings and - // turn RTTI off.. - try + try // This section is just a safety-net for catching builds without RTTI enabled.. { MemoryOutputStream mo; OutputStream* o = &mo; @@ -16905,65 +16894,123 @@ END_JUCE_NAMESPACE /*** Start of inlined file: juce_Thread.cpp ***/ BEGIN_JUCE_NAMESPACE -// these functions are implemented in the platform-specific code. -void* juce_createThread (void* userData); -void juce_killThread (void* handle); -bool juce_setThreadPriority (void* handle, int priority); -void juce_setCurrentThreadName (const String& name); -#if JUCE_WINDOWS -void juce_CloseThreadHandle (void* handle); -#endif - -void Thread::threadEntryPoint (Thread* const thread) +class RunningThreadsList { +public: + RunningThreadsList() { - const ScopedLock sl (runningThreadsLock); - runningThreads.add (thread); } + void add (Thread* const thread) + { + const ScopedLock sl (lock); + jassert (! threads.contains (thread)); + threads.add (thread); + } + + void remove (Thread* const thread) + { + const ScopedLock sl (lock); + jassert (threads.contains (thread)); + threads.removeValue (thread); + } + + int size() const throw() + { + return threads.size(); + } + + Thread* getThreadWithID (const Thread::ThreadID targetID) const throw() + { + const ScopedLock sl (lock); + + for (int i = threads.size(); --i >= 0;) + { + Thread* const t = threads.getUnchecked(i); + + if (t->getThreadId() == targetID) + return t; + } + + return 0; + } + + void stopAll (const int timeOutMilliseconds) + { + signalAllThreadsToStop(); + + for (;;) + { + Thread* firstThread = getFirstThread(); + + if (firstThread != 0) + firstThread->stopThread (timeOutMilliseconds); + else + break; + } + } + + static RunningThreadsList& getInstance() + { + static RunningThreadsList runningThreads; + return runningThreads; + } + +private: + Array threads; + CriticalSection lock; + + void signalAllThreadsToStop() + { + const ScopedLock sl (lock); + + for (int i = threads.size(); --i >= 0;) + threads.getUnchecked(i)->signalThreadShouldExit(); + } + + Thread* getFirstThread() const + { + const ScopedLock sl (lock); + return threads.getFirst(); + } +}; + +void Thread::threadEntryPoint() +{ + RunningThreadsList::getInstance().add (this); + JUCE_TRY { - thread->threadId_ = Thread::getCurrentThreadId(); + jassert (getCurrentThreadId() == threadId_); - if (thread->threadName_.isNotEmpty()) - juce_setCurrentThreadName (thread->threadName_); + if (threadName_.isNotEmpty()) + setCurrentThreadName (threadName_); - if (thread->startSuspensionEvent_.wait (10000)) + if (startSuspensionEvent_.wait (10000)) { - if (thread->affinityMask_ != 0) - setCurrentThreadAffinityMask (thread->affinityMask_); + if (affinityMask_ != 0) + setCurrentThreadAffinityMask (affinityMask_); - thread->run(); + run(); } } JUCE_CATCH_ALL_ASSERT - { - const ScopedLock sl (runningThreadsLock); - - jassert (runningThreads.contains (thread)); - runningThreads.removeValue (thread); - } - -#if JUCE_WINDOWS - juce_CloseThreadHandle (thread->threadHandle_); -#endif - - thread->threadHandle_ = 0; - thread->threadId_ = 0; + RunningThreadsList::getInstance().remove (this); + closeThreadHandle(); } // used to wrap the incoming call from the platform-specific code void JUCE_API juce_threadEntryPoint (void* userData) { - Thread::threadEntryPoint (static_cast (userData)); + static_cast (userData)->threadEntryPoint(); } Thread::Thread (const String& threadName) : threadName_ (threadName), threadHandle_ (0), - threadPriority_ (5), threadId_ (0), + threadPriority_ (5), affinityMask_ (0), threadShouldExit_ (false) { @@ -16972,8 +17019,8 @@ Thread::Thread (const String& threadName) Thread::~Thread() { /* If your thread class's destructor has been called without first stopping the thread, that - means that this partially destructed object is still performing some work - and that's not - unlikely to be a safe approach to take! + means that this partially destructed object is still performing some work - and that's + probably a Bad Thing! To avoid this type of nastiness, always make sure you call stopThread() before or during your subclass's destructor. @@ -16991,8 +17038,8 @@ void Thread::startThread() if (threadHandle_ == 0) { - threadHandle_ = juce_createThread (this); - juce_setThreadPriority (threadHandle_, threadPriority_); + launchThread(); + setThreadPriority (threadHandle_, threadPriority_); startSuspensionEvent_.signal(); } } @@ -17059,18 +17106,16 @@ void Thread::stopThread (const int timeOutMilliseconds) if (isThreadRunning()) { - // very bad karma if this point is reached, as - // there are bound to be locks and events left in - // silly states when a thread is killed by force.. + // very bad karma if this point is reached, as there are bound to be + // locks and events left in silly states when a thread is killed by force.. jassertfalse; Logger::writeToLog ("!! killing thread by force !!"); - juce_killThread (threadHandle_); + killThread(); + + RunningThreadsList::getInstance().remove (this); threadHandle_ = 0; threadId_ = 0; - - const ScopedLock sl2 (runningThreadsLock); - runningThreads.removeValue (this); } } } @@ -17079,17 +17124,18 @@ bool Thread::setPriority (const int priority) { const ScopedLock sl (startStopLock); - const bool worked = juce_setThreadPriority (threadHandle_, priority); - - if (worked) + if (setThreadPriority (threadHandle_, priority)) + { threadPriority_ = priority; + return true; + } - return worked; + return false; } bool Thread::setCurrentThreadPriority (const int priority) { - return juce_setThreadPriority (0, priority); + return setThreadPriority (0, priority); } void Thread::setAffinityMask (const uint32 affinityMask) @@ -17109,54 +17155,19 @@ void Thread::notify() const int Thread::getNumRunningThreads() { - return runningThreads.size(); + return RunningThreadsList::getInstance().size(); } Thread* Thread::getCurrentThread() { - const ThreadID thisId = getCurrentThreadId(); - - const ScopedLock sl (runningThreadsLock); - - for (int i = runningThreads.size(); --i >= 0;) - { - Thread* const t = runningThreads.getUnchecked(i); - - if (t->threadId_ == thisId) - return t; - } - - return 0; + return RunningThreadsList::getInstance().getThreadWithID (getCurrentThreadId()); } void Thread::stopAllThreads (const int timeOutMilliseconds) { - { - const ScopedLock sl (runningThreadsLock); - - for (int i = runningThreads.size(); --i >= 0;) - runningThreads.getUnchecked(i)->signalThreadShouldExit(); - } - - for (;;) - { - Thread* firstThread; - - { - const ScopedLock sl (runningThreadsLock); - firstThread = runningThreads.getFirst(); - } - - if (firstThread == 0) - break; - - firstThread->stopThread (timeOutMilliseconds); - } + RunningThreadsList::getInstance().stopAll (timeOutMilliseconds); } -Array Thread::runningThreads; -CriticalSection Thread::runningThreadsLock; - END_JUCE_NAMESPACE /*** End of inlined file: juce_Thread.cpp ***/ @@ -22383,8 +22394,8 @@ public: const double sampleRate, const int numChannels, const int samplesPerThumbSample, LevelDataSource* levelData, const OwnedArray& channels) { - refillCache (area.getWidth(), startTime, (endTime - startTime) / area.getWidth(), - sampleRate, numChannels, samplesPerThumbSample, levelData, channels); + refillCache (area.getWidth(), startTime, endTime, sampleRate, + numChannels, samplesPerThumbSample, levelData, channels); if (isPositiveAndBelow (channelNum, numChannelsCached)) { @@ -22418,10 +22429,12 @@ private: int numChannelsCached, numSamplesCached; bool cacheNeedsRefilling; - void refillCache (const int numSamples, double startTime, const double timePerPixel, + void refillCache (const int numSamples, double startTime, const double endTime, const double sampleRate, const int numChannels, const int samplesPerThumbSample, LevelDataSource* levelData, const OwnedArray& channels) { + const double timePerPixel = (endTime - startTime) / numSamples; + if (numSamples <= 0 || timePerPixel <= 0.0 || sampleRate <= 0) { invalidate(); @@ -22715,7 +22728,7 @@ double AudioThumbnail::getTotalLength() const throw() bool AudioThumbnail::isFullyLoaded() const throw() { - return numSamplesFinished >= totalSamples; + return numSamplesFinished >= totalSamples - samplesPerThumbSample; } void AudioThumbnail::drawChannel (Graphics& g, const Rectangle& area, double startTime, @@ -39106,6 +39119,9 @@ MessageManager::MessageManager() throw() threadWithLock (0) { messageThreadId = Thread::getCurrentThreadId(); + + if (JUCEApplication::isStandaloneApp()) + Thread::setCurrentThreadName ("Juce Message Thread"); } MessageManager::~MessageManager() throw() @@ -237631,8 +237647,6 @@ void* DynamicLibraryLoader::findProcAddress (const String& functionName) // compiled on its own). #if JUCE_INCLUDED_FILE -extern void juce_initialiseThreadEvents(); - void Logger::outputDebugString (const String& text) { OutputDebugString (text + "\n"); @@ -237711,8 +237725,6 @@ const String SystemStats::getCpuVendor() void SystemStats::initialiseStats() { - juce_initialiseThreadEvents(); - cpuFlags.hasMMX = IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE) != 0; cpuFlags.hasSSE = IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0; cpuFlags.hasSSE2 = IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0; @@ -238046,10 +238058,10 @@ void JUCE_API juce_threadEntryPoint (void*); static unsigned int __stdcall threadEntryProc (void* userData) { -#if ! JUCE_ONLY_BUILD_CORE_LIBRARY + #if ! JUCE_ONLY_BUILD_CORE_LIBRARY AttachThreadInput (GetWindowThreadProcessId (juce_messageWindowHandle, 0), GetCurrentThreadId(), TRUE); -#endif + #endif juce_threadEntryPoint (userData); @@ -238057,31 +238069,34 @@ static unsigned int __stdcall threadEntryProc (void* userData) return 0; } -void juce_CloseThreadHandle (void* handle) +void Thread::launchThread() { - CloseHandle ((HANDLE) handle); + unsigned int newThreadId; + threadHandle_ = (void*) _beginthreadex (0, 0, &threadEntryProc, this, 0, &newThreadId); + threadId_ = (ThreadID) newThreadId; } -void* juce_createThread (void* userData) +void Thread::closeThreadHandle() { - unsigned int threadId; - return (void*) _beginthreadex (0, 0, &threadEntryProc, userData, 0, &threadId); + CloseHandle ((HANDLE) threadHandle_); + threadId_ = 0; + threadHandle_ = 0; } -void juce_killThread (void* handle) +void Thread::killThread() { - if (handle != 0) + if (threadHandle_ != 0) { -#if JUCE_DEBUG + #if JUCE_DEBUG OutputDebugString (_T("** Warning - Forced thread termination **\n")); -#endif - TerminateThread (handle, 0); + #endif + TerminateThread (threadHandle_, 0); } } -void juce_setCurrentThreadName (const String& name) +void Thread::setCurrentThreadName (const String& name) { -#if JUCE_DEBUG && JUCE_MSVC + #if JUCE_DEBUG && JUCE_MSVC struct { DWORD dwType; @@ -238101,9 +238116,9 @@ void juce_setCurrentThreadName (const String& name) } __except (EXCEPTION_CONTINUE_EXECUTION) {} -#else + #else (void) name; -#endif + #endif } Thread::ThreadID Thread::getCurrentThreadId() @@ -238111,8 +238126,7 @@ Thread::ThreadID Thread::getCurrentThreadId() return (ThreadID) (pointer_sized_int) GetCurrentThreadId(); } -// priority 1 to 10 where 5=normal, 1=low -bool juce_setThreadPriority (void* threadHandle, int priority) +bool Thread::setThreadPriority (void* handle, int priority) { int pri = THREAD_PRIORITY_TIME_CRITICAL; @@ -238123,10 +238137,10 @@ bool juce_setThreadPriority (void* threadHandle, int priority) else if (priority < 9) pri = THREAD_PRIORITY_ABOVE_NORMAL; else if (priority < 10) pri = THREAD_PRIORITY_HIGHEST; - if (threadHandle == 0) - threadHandle = GetCurrentThread(); + if (handle == 0) + handle = GetCurrentThread(); - return SetThreadPriority (threadHandle, pri) != FALSE; + return SetThreadPriority (handle, pri) != FALSE; } void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) @@ -238134,22 +238148,22 @@ void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) SetThreadAffinityMask (GetCurrentThread(), affinityMask); } -static HANDLE sleepEvent = 0; - -void juce_initialiseThreadEvents() +struct SleepEvent { - if (sleepEvent == 0) -#if JUCE_DEBUG - sleepEvent = CreateEvent (0, 0, 0, _T("Juce Sleep Event")); -#else - sleepEvent = CreateEvent (0, 0, 0, 0); -#endif -} + SleepEvent() + : handle (CreateEvent (0, 0, 0, + #if JUCE_DEBUG + _T("Juce Sleep Event"))) + #else + 0)) + #endif + { + } -void Thread::yield() -{ - Sleep (0); -} + HANDLE handle; +}; + +static SleepEvent sleepEvent; void JUCE_CALLTYPE Thread::sleep (const int millisecs) { @@ -238159,15 +238173,18 @@ void JUCE_CALLTYPE Thread::sleep (const int millisecs) } else { - jassert (sleepEvent != 0); - // unlike Sleep() this is guaranteed to return to the current thread after // the time expires, so we'll use this for short waits, which are more likely // to need to be accurate - WaitForSingleObject (sleepEvent, millisecs); + WaitForSingleObject (sleepEvent.handle, millisecs); } } +void Thread::yield() +{ + Sleep (0); +} + static int lastProcessPriority = -1; // called by WindowDriver because Windows does wierd things to process priority @@ -255061,30 +255078,36 @@ void* threadEntryProc (void* userData) return 0; } -void* juce_createThread (void* userData) +void Thread::launchThread() { + threadHandle_ = 0; pthread_t handle = 0; - if (pthread_create (&handle, 0, threadEntryProc, userData) == 0) + if (pthread_create (&handle, 0, threadEntryProc, this) == 0) { pthread_detach (handle); - return (void*) handle; + threadHandle_ = (void*) handle; + threadId_ = (ThreadID) threadHandle_; } - - return 0; } -void juce_killThread (void* handle) +void Thread::closeThreadHandle() { - if (handle != 0) - pthread_cancel ((pthread_t) handle); + threadId_ = 0; + threadHandle_ = 0; } -void juce_setCurrentThreadName (const String& /*name*/) +void Thread::killThread() +{ + if (threadHandle_ != 0) + pthread_cancel ((pthread_t) threadHandle_); +} + +void Thread::setCurrentThreadName (const String& /*name*/) { } -bool juce_setThreadPriority (void* handle, int priority) +bool Thread::setThreadPriority (void* handle, int priority) { struct sched_param param; int policy; @@ -258216,6 +258239,63 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XBitmapImage); }; +namespace PixmapHelpers +{ + Pixmap createColourPixmapFromImage (Display* display, const Image& image) + { + ScopedXLock xlock; + + const int width = image.getWidth(); + const int height = image.getHeight(); + HeapBlock colour (width * height); + int index = 0; + + for (int y = 0; y < height; ++y) + for (int x = 0; x < width; ++x) + colour[index++] = image.getPixelAt (x, y).getARGB(); + + XImage* ximage = XCreateImage (display, CopyFromParent, 24, ZPixmap, + 0, reinterpret_cast (colour.getData()), + width, height, 32, 0); + + Pixmap pixmap = XCreatePixmap (display, DefaultRootWindow (display), + width, height, 24); + + GC gc = XCreateGC (display, pixmap, 0, 0); + XPutImage (display, pixmap, gc, ximage, 0, 0, 0, 0, width, height); + XFreeGC (display, gc); + + return pixmap; + } + + Pixmap createMaskPixmapFromImage (Display* display, const Image& image) + { + ScopedXLock xlock; + + const int width = image.getWidth(); + const int height = image.getHeight(); + const int stride = (width + 7) >> 3; + HeapBlock mask; + mask.calloc (stride * height); + const bool msbfirst = (BitmapBitOrder (display) == MSBFirst); + + for (int y = 0; y < height; ++y) + { + for (int x = 0; x < width; ++x) + { + const char bit = (char) (1 << (msbfirst ? (7 - (x & 7)) : (x & 7))); + const int offset = y * stride + (x >> 3); + + if (image.getPixelAt (x, y).getAlpha() >= 128) + mask[offset] |= bit; + } + } + + return XCreatePixmapFromBitmapData (display, DefaultRootWindow (display), + mask.getData(), width, height, 1, 0, 1); + } +} + class LinuxComponentPeer : public ComponentPeer { public: @@ -258285,17 +258365,17 @@ public: void setTitle (const String& title) { - setWindowTitle (windowH, title); - } + XTextProperty nameProperty; + char* strings[] = { const_cast (title.toUTF8()) }; + ScopedXLock xlock; - void setPosition (int x, int y) - { - setBounds (x, y, ww, wh, false); - } + if (XStringListToTextProperty (strings, 1, &nameProperty)) + { + XSetWMName (display, windowH, &nameProperty); + XSetWMIconName (display, windowH, &nameProperty); - void setSize (int w, int h) - { - setBounds (wx, wy, w, h, false); + XFree (nameProperty.value); + } } void setBounds (int x, int y, int w, int h, bool isNowFullScreen) @@ -258343,8 +258423,10 @@ public: } } + void setPosition (int x, int y) { setBounds (x, y, ww, wh, false); } + void setSize (int w, int h) { setBounds (wx, wy, w, h, false); } const Rectangle getBounds() const { return Rectangle (wx, wy, ww, wh); } - const Point getScreenPosition() const { return Point (wx, wy); } + const Point getScreenPosition() const { return Point (wx, wy); } const Point localToGlobal (const Point& relativePosition) { @@ -258620,60 +258702,6 @@ public: repainter->performAnyPendingRepaintsNow(); } - static Pixmap juce_createColourPixmapFromImage (Display* display, const Image& image) - { - ScopedXLock xlock; - - const int width = image.getWidth(); - const int height = image.getHeight(); - HeapBlock colour (width * height); - int index = 0; - - for (int y = 0; y < height; ++y) - for (int x = 0; x < width; ++x) - colour[index++] = image.getPixelAt (x, y).getARGB(); - - XImage* ximage = XCreateImage (display, CopyFromParent, 24, ZPixmap, - 0, reinterpret_cast (colour.getData()), - width, height, 32, 0); - - Pixmap pixmap = XCreatePixmap (display, DefaultRootWindow (display), - width, height, 24); - - GC gc = XCreateGC (display, pixmap, 0, 0); - XPutImage (display, pixmap, gc, ximage, 0, 0, 0, 0, width, height); - XFreeGC (display, gc); - - return pixmap; - } - - static Pixmap juce_createMaskPixmapFromImage (Display* display, const Image& image) - { - ScopedXLock xlock; - - const int width = image.getWidth(); - const int height = image.getHeight(); - const int stride = (width + 7) >> 3; - HeapBlock mask; - mask.calloc (stride * height); - const bool msbfirst = (BitmapBitOrder (display) == MSBFirst); - - for (int y = 0; y < height; ++y) - { - for (int x = 0; x < width; ++x) - { - const char bit = (char) (1 << (msbfirst ? (7 - (x & 7)) : (x & 7))); - const int offset = y * stride + (x >> 3); - - if (image.getPixelAt (x, y).getAlpha() >= 128) - mask[offset] |= bit; - } - } - - return XCreatePixmapFromBitmapData (display, DefaultRootWindow (display), - mask.getData(), width, height, 1, 0, 1); - } - void setIcon (const Image& newIcon) { const int dataSize = newIcon.getWidth() * newIcon.getHeight() + 2; @@ -258701,8 +258729,8 @@ public: wmHints = XAllocWMHints(); wmHints->flags |= IconPixmapHint | IconMaskHint; - wmHints->icon_pixmap = juce_createColourPixmapFromImage (display, newIcon); - wmHints->icon_mask = juce_createMaskPixmapFromImage (display, newIcon); + wmHints->icon_pixmap = PixmapHelpers::createColourPixmapFromImage (display, newIcon); + wmHints->icon_mask = PixmapHelpers::createMaskPixmapFromImage (display, newIcon); XSetWMHints (display, windowH, wmHints); XFree (wmHints); @@ -258738,315 +258766,22 @@ public: { switch (event->xany.type) { - case 2: // 'KeyPress' - { - char utf8 [64] = { 0 }; - juce_wchar unicodeChar = 0; - int keyCode = 0; - bool keyDownChange = false; - KeySym sym; - - { - ScopedXLock xlock; - XKeyEvent* const keyEvent = (XKeyEvent*) &event->xkey; - updateKeyStates (keyEvent->keycode, true); - - const char* oldLocale = ::setlocale (LC_ALL, 0); - ::setlocale (LC_ALL, ""); - XLookupString (keyEvent, utf8, sizeof (utf8), &sym, 0); - ::setlocale (LC_ALL, oldLocale); - - unicodeChar = String::fromUTF8 (utf8, sizeof (utf8) - 1) [0]; - keyCode = (int) unicodeChar; - - if (keyCode < 0x20) - keyCode = XKeycodeToKeysym (display, keyEvent->keycode, currentModifiers.isShiftDown() ? 1 : 0); - - keyDownChange = (sym != NoSymbol) && ! updateKeyModifiersFromSym (sym, true); - } - - const ModifierKeys oldMods (currentModifiers); - bool keyPressed = false; - - if ((sym & 0xff00) == 0xff00) - { - switch (sym) // Translate keypad - { - case XK_KP_Divide: keyCode = XK_slash; break; - case XK_KP_Multiply: keyCode = XK_asterisk; break; - case XK_KP_Subtract: keyCode = XK_hyphen; break; - case XK_KP_Add: keyCode = XK_plus; break; - case XK_KP_Enter: keyCode = XK_Return; break; - case XK_KP_Decimal: keyCode = Keys::numLock ? XK_period : XK_Delete; break; - case XK_KP_0: keyCode = Keys::numLock ? XK_0 : XK_Insert; break; - case XK_KP_1: keyCode = Keys::numLock ? XK_1 : XK_End; break; - case XK_KP_2: keyCode = Keys::numLock ? XK_2 : XK_Down; break; - case XK_KP_3: keyCode = Keys::numLock ? XK_3 : XK_Page_Down; break; - case XK_KP_4: keyCode = Keys::numLock ? XK_4 : XK_Left; break; - case XK_KP_5: keyCode = XK_5; break; - case XK_KP_6: keyCode = Keys::numLock ? XK_6 : XK_Right; break; - case XK_KP_7: keyCode = Keys::numLock ? XK_7 : XK_Home; break; - case XK_KP_8: keyCode = Keys::numLock ? XK_8 : XK_Up; break; - case XK_KP_9: keyCode = Keys::numLock ? XK_9 : XK_Page_Up; break; - default: break; - } - - switch (sym) - { - case XK_Left: - case XK_Right: - case XK_Up: - case XK_Down: - case XK_Page_Up: - case XK_Page_Down: - case XK_End: - case XK_Home: - case XK_Delete: - case XK_Insert: - keyPressed = true; - keyCode = (sym & 0xff) | Keys::extendedKeyModifier; - break; - case XK_Tab: - case XK_Return: - case XK_Escape: - case XK_BackSpace: - keyPressed = true; - keyCode &= 0xff; - break; - default: - { - if (sym >= XK_F1 && sym <= XK_F16) - { - keyPressed = true; - keyCode = (sym & 0xff) | Keys::extendedKeyModifier; - } - break; - } - } - } - - if (utf8[0] != 0 || ((sym & 0xff00) == 0 && sym >= 8)) - keyPressed = true; - - if (oldMods != currentModifiers) - handleModifierKeysChange(); - - if (keyDownChange) - handleKeyUpOrDown (true); - - if (keyPressed) - handleKeyPress (keyCode, unicodeChar); - - break; - } - - case KeyRelease: - { - const XKeyEvent* const keyEvent = (const XKeyEvent*) &event->xkey; - updateKeyStates (keyEvent->keycode, false); - KeySym sym; - - { - ScopedXLock xlock; - sym = XKeycodeToKeysym (display, keyEvent->keycode, 0); - } - - const ModifierKeys oldMods (currentModifiers); - const bool keyDownChange = (sym != NoSymbol) && ! updateKeyModifiersFromSym (sym, false); - - if (oldMods != currentModifiers) - handleModifierKeysChange(); - - if (keyDownChange) - handleKeyUpOrDown (false); - - break; - } - - case ButtonPress: - { - const XButtonPressedEvent* const buttonPressEvent = (const XButtonPressedEvent*) &event->xbutton; - updateKeyModifiers (buttonPressEvent->state); - - bool buttonMsg = false; - const int map = pointerMap [buttonPressEvent->button - Button1]; - - if (map == Keys::WheelUp || map == Keys::WheelDown) - { - handleMouseWheel (0, Point (buttonPressEvent->x, buttonPressEvent->y), - getEventTime (buttonPressEvent->time), 0, map == Keys::WheelDown ? -84.0f : 84.0f); - } - if (map == Keys::LeftButton) - { - currentModifiers = currentModifiers.withFlags (ModifierKeys::leftButtonModifier); - buttonMsg = true; - } - else if (map == Keys::RightButton) - { - currentModifiers = currentModifiers.withFlags (ModifierKeys::rightButtonModifier); - buttonMsg = true; - } - else if (map == Keys::MiddleButton) - { - currentModifiers = currentModifiers.withFlags (ModifierKeys::middleButtonModifier); - buttonMsg = true; - } - - if (buttonMsg) - { - toFront (true); - - handleMouseEvent (0, Point (buttonPressEvent->x, buttonPressEvent->y), currentModifiers, - getEventTime (buttonPressEvent->time)); - } - - clearLastMousePos(); - break; - } - - case ButtonRelease: - { - const XButtonReleasedEvent* const buttonRelEvent = (const XButtonReleasedEvent*) &event->xbutton; - updateKeyModifiers (buttonRelEvent->state); - - const int map = pointerMap [buttonRelEvent->button - Button1]; - - if (map == Keys::LeftButton) - currentModifiers = currentModifiers.withoutFlags (ModifierKeys::leftButtonModifier); - else if (map == Keys::RightButton) - currentModifiers = currentModifiers.withoutFlags (ModifierKeys::rightButtonModifier); - else if (map == Keys::MiddleButton) - currentModifiers = currentModifiers.withoutFlags (ModifierKeys::middleButtonModifier); - - handleMouseEvent (0, Point (buttonRelEvent->x, buttonRelEvent->y), currentModifiers, - getEventTime (buttonRelEvent->time)); - - clearLastMousePos(); - break; - } - - case MotionNotify: - { - const XPointerMovedEvent* const movedEvent = (const XPointerMovedEvent*) &event->xmotion; - updateKeyModifiers (movedEvent->state); - - const Point mousePos (Desktop::getMousePosition()); - - if (lastMousePos != mousePos) - { - lastMousePos = mousePos; - - if (parentWindow != 0 && (styleFlags & windowHasTitleBar) == 0) - { - Window wRoot = 0, wParent = 0; - - { - ScopedXLock xlock; - unsigned int numChildren; - Window* wChild = 0; - XQueryTree (display, windowH, &wRoot, &wParent, &wChild, &numChildren); - } - - if (wParent != 0 - && wParent != windowH - && wParent != wRoot) - { - parentWindow = wParent; - updateBounds(); - } - else - { - parentWindow = 0; - } - } - - handleMouseEvent (0, mousePos - getScreenPosition(), currentModifiers, getEventTime (movedEvent->time)); - } - - break; - } - - case EnterNotify: - { - clearLastMousePos(); - const XEnterWindowEvent* const enterEvent = (const XEnterWindowEvent*) &event->xcrossing; - - if (! currentModifiers.isAnyMouseButtonDown()) - { - updateKeyModifiers (enterEvent->state); - handleMouseEvent (0, Point (enterEvent->x, enterEvent->y), currentModifiers, getEventTime (enterEvent->time)); - } - - break; - } - - case LeaveNotify: - { - const XLeaveWindowEvent* const leaveEvent = (const XLeaveWindowEvent*) &event->xcrossing; - - // Suppress the normal leave if we've got a pointer grab, or if - // it's a bogus one caused by clicking a mouse button when running - // in a Window manager - if (((! currentModifiers.isAnyMouseButtonDown()) && leaveEvent->mode == NotifyNormal) - || leaveEvent->mode == NotifyUngrab) - { - updateKeyModifiers (leaveEvent->state); - handleMouseEvent (0, Point (leaveEvent->x, leaveEvent->y), currentModifiers, getEventTime (leaveEvent->time)); - } - - break; - } - - case FocusIn: - { - isActiveApplication = true; - if (isFocused()) - handleFocusGain(); - - break; - } - - case FocusOut: - { - isActiveApplication = false; - if (! isFocused()) - handleFocusLoss(); - - break; - } - - case Expose: - { - // Batch together all pending expose events - XExposeEvent* exposeEvent = (XExposeEvent*) &event->xexpose; - XEvent nextEvent; - ScopedXLock xlock; - - if (exposeEvent->window != windowH) - { - Window child; - XTranslateCoordinates (display, exposeEvent->window, windowH, - exposeEvent->x, exposeEvent->y, &exposeEvent->x, &exposeEvent->y, - &child); - } - - repaint (Rectangle (exposeEvent->x, exposeEvent->y, - exposeEvent->width, exposeEvent->height)); - - while (XEventsQueued (display, QueuedAfterFlush) > 0) - { - XPeekEvent (display, (XEvent*) &nextEvent); - if (nextEvent.type != Expose || nextEvent.xany.window != event->xany.window) - break; - - XNextEvent (display, (XEvent*) &nextEvent); - XExposeEvent* nextExposeEvent = (XExposeEvent*) &nextEvent.xexpose; - repaint (Rectangle (nextExposeEvent->x, nextExposeEvent->y, - nextExposeEvent->width, nextExposeEvent->height)); - } - - break; - } + case 2: /* KeyPress */ handleKeyPressEvent ((XKeyEvent*) &event->xkey); break; + case KeyRelease: handleKeyReleaseEvent ((const XKeyEvent*) &event->xkey); break; + case ButtonPress: handleButtonPressEvent ((const XButtonPressedEvent*) &event->xbutton); break; + case ButtonRelease: handleButtonReleaseEvent ((const XButtonReleasedEvent*) &event->xbutton); break; + case MotionNotify: handleMotionNotifyEvent ((const XPointerMovedEvent*) &event->xmotion); break; + case EnterNotify: handleEnterNotifyEvent ((const XEnterWindowEvent*) &event->xcrossing); break; + case LeaveNotify: handleLeaveNotifyEvent ((const XLeaveWindowEvent*) &event->xcrossing); break; + case FocusIn: handleFocusInEvent(); break; + case FocusOut: handleFocusOutEvent(); break; + case Expose: handleExposeEvent ((XExposeEvent*) &event->xexpose); break; + case MappingNotify: handleMappingNotify ((XMappingEvent*) &event->xmapping); break; + case ClientMessage: handleClientMessageEvent ((XClientMessageEvent*) &event->xclient, event); break; + case SelectionNotify: handleDragAndDropSelection (event); break; + case ConfigureNotify: handleConfigureNotifyEvent ((XConfigureEvent*) &event->xconfigure); break; + case ReparentNotify: handleReparentNotifyEvent(); break; + case GravityNotify: handleGravityNotify(); break; case CirculateNotify: case CreateNotify: @@ -259054,63 +258789,6 @@ public: // Think we can ignore these break; - case ConfigureNotify: - { - updateBounds(); - updateBorderSize(); - handleMovedOrResized(); - - // if the native title bar is dragged, need to tell any active menus, etc. - if ((styleFlags & windowHasTitleBar) != 0 - && component->isCurrentlyBlockedByAnotherModalComponent()) - { - Component* const currentModalComp = Component::getCurrentlyModalComponent(); - - if (currentModalComp != 0) - currentModalComp->inputAttemptWhenModal(); - } - - XConfigureEvent* const confEvent = (XConfigureEvent*) &event->xconfigure; - - if (confEvent->window == windowH - && confEvent->above != 0 - && isFrontWindow()) - { - handleBroughtToFront(); - } - - break; - } - - case ReparentNotify: - { - parentWindow = 0; - Window wRoot = 0; - Window* wChild = 0; - unsigned int numChildren; - - { - ScopedXLock xlock; - XQueryTree (display, windowH, &wRoot, &parentWindow, &wChild, &numChildren); - } - - if (parentWindow == windowH || parentWindow == wRoot) - parentWindow = 0; - - updateBounds(); - updateBorderSize(); - handleMovedOrResized(); - break; - } - - case GravityNotify: - { - updateBounds(); - updateBorderSize(); - handleMovedOrResized(); - break; - } - case MapNotify: mapped = true; handleBroughtToFront(); @@ -259120,103 +258798,418 @@ public: mapped = false; break; - case MappingNotify: - { - XMappingEvent* mappingEvent = (XMappingEvent*) &event->xmapping; - - if (mappingEvent->request != MappingPointer) - { - // Deal with modifier/keyboard mapping - ScopedXLock xlock; - XRefreshKeyboardMapping (mappingEvent); - updateModifierMappings(); - } - - break; - } - - case ClientMessage: - { - const XClientMessageEvent* const clientMsg = (const XClientMessageEvent*) &event->xclient; - - if (clientMsg->message_type == Atoms::Protocols && clientMsg->format == 32) - { - const Atom atom = (Atom) clientMsg->data.l[0]; - - if (atom == Atoms::ProtocolList [Atoms::PING]) - { - Window root = RootWindow (display, DefaultScreen (display)); - - event->xclient.window = root; - - XSendEvent (display, root, False, NoEventMask, event); - XFlush (display); - } - else if (atom == Atoms::ProtocolList [Atoms::TAKE_FOCUS]) - { - XWindowAttributes atts; - - ScopedXLock xlock; - if (clientMsg->window != 0 - && XGetWindowAttributes (display, clientMsg->window, &atts)) - { - if (atts.map_state == IsViewable) - XSetInputFocus (display, clientMsg->window, RevertToParent, clientMsg->data.l[1]); - } - } - else if (atom == Atoms::ProtocolList [Atoms::DELETE_WINDOW]) - { - handleUserClosingWindow(); - } - } - else if (clientMsg->message_type == Atoms::XdndEnter) - { - handleDragAndDropEnter (clientMsg); - } - else if (clientMsg->message_type == Atoms::XdndLeave) - { - resetDragAndDrop(); - } - else if (clientMsg->message_type == Atoms::XdndPosition) - { - handleDragAndDropPosition (clientMsg); - } - else if (clientMsg->message_type == Atoms::XdndDrop) - { - handleDragAndDropDrop (clientMsg); - } - else if (clientMsg->message_type == Atoms::XdndStatus) - { - handleDragAndDropStatus (clientMsg); - } - else if (clientMsg->message_type == Atoms::XdndFinished) - { - resetDragAndDrop(); - } - - break; - } - - case SelectionNotify: - handleDragAndDropSelection (event); - break; - case SelectionClear: case SelectionRequest: break; default: -#if JUCE_USE_XSHM - { - ScopedXLock xlock; - if (event->xany.type == XShmGetEventBase (display)) - repainter->notifyPaintCompleted(); - } -#endif + #if JUCE_USE_XSHM + { + ScopedXLock xlock; + if (event->xany.type == XShmGetEventBase (display)) + repainter->notifyPaintCompleted(); + } + #endif break; } } + void handleKeyPressEvent (XKeyEvent* const keyEvent) + { + char utf8 [64] = { 0 }; + juce_wchar unicodeChar = 0; + int keyCode = 0; + bool keyDownChange = false; + KeySym sym; + + { + ScopedXLock xlock; + updateKeyStates (keyEvent->keycode, true); + + const char* oldLocale = ::setlocale (LC_ALL, 0); + ::setlocale (LC_ALL, ""); + XLookupString (keyEvent, utf8, sizeof (utf8), &sym, 0); + ::setlocale (LC_ALL, oldLocale); + + unicodeChar = String::fromUTF8 (utf8, sizeof (utf8) - 1) [0]; + keyCode = (int) unicodeChar; + + if (keyCode < 0x20) + keyCode = XKeycodeToKeysym (display, keyEvent->keycode, currentModifiers.isShiftDown() ? 1 : 0); + + keyDownChange = (sym != NoSymbol) && ! updateKeyModifiersFromSym (sym, true); + } + + const ModifierKeys oldMods (currentModifiers); + bool keyPressed = false; + + if ((sym & 0xff00) == 0xff00) + { + switch (sym) // Translate keypad + { + case XK_KP_Divide: keyCode = XK_slash; break; + case XK_KP_Multiply: keyCode = XK_asterisk; break; + case XK_KP_Subtract: keyCode = XK_hyphen; break; + case XK_KP_Add: keyCode = XK_plus; break; + case XK_KP_Enter: keyCode = XK_Return; break; + case XK_KP_Decimal: keyCode = Keys::numLock ? XK_period : XK_Delete; break; + case XK_KP_0: keyCode = Keys::numLock ? XK_0 : XK_Insert; break; + case XK_KP_1: keyCode = Keys::numLock ? XK_1 : XK_End; break; + case XK_KP_2: keyCode = Keys::numLock ? XK_2 : XK_Down; break; + case XK_KP_3: keyCode = Keys::numLock ? XK_3 : XK_Page_Down; break; + case XK_KP_4: keyCode = Keys::numLock ? XK_4 : XK_Left; break; + case XK_KP_5: keyCode = XK_5; break; + case XK_KP_6: keyCode = Keys::numLock ? XK_6 : XK_Right; break; + case XK_KP_7: keyCode = Keys::numLock ? XK_7 : XK_Home; break; + case XK_KP_8: keyCode = Keys::numLock ? XK_8 : XK_Up; break; + case XK_KP_9: keyCode = Keys::numLock ? XK_9 : XK_Page_Up; break; + default: break; + } + + switch (sym) + { + case XK_Left: + case XK_Right: + case XK_Up: + case XK_Down: + case XK_Page_Up: + case XK_Page_Down: + case XK_End: + case XK_Home: + case XK_Delete: + case XK_Insert: + keyPressed = true; + keyCode = (sym & 0xff) | Keys::extendedKeyModifier; + break; + + case XK_Tab: + case XK_Return: + case XK_Escape: + case XK_BackSpace: + keyPressed = true; + keyCode &= 0xff; + break; + + default: + if (sym >= XK_F1 && sym <= XK_F16) + { + keyPressed = true; + keyCode = (sym & 0xff) | Keys::extendedKeyModifier; + } + break; + } + } + + if (utf8[0] != 0 || ((sym & 0xff00) == 0 && sym >= 8)) + keyPressed = true; + + if (oldMods != currentModifiers) + handleModifierKeysChange(); + + if (keyDownChange) + handleKeyUpOrDown (true); + + if (keyPressed) + handleKeyPress (keyCode, unicodeChar); + } + + void handleKeyReleaseEvent (const XKeyEvent* const keyEvent) + { + updateKeyStates (keyEvent->keycode, false); + KeySym sym; + + { + ScopedXLock xlock; + sym = XKeycodeToKeysym (display, keyEvent->keycode, 0); + } + + const ModifierKeys oldMods (currentModifiers); + const bool keyDownChange = (sym != NoSymbol) && ! updateKeyModifiersFromSym (sym, false); + + if (oldMods != currentModifiers) + handleModifierKeysChange(); + + if (keyDownChange) + handleKeyUpOrDown (false); + } + + void handleButtonPressEvent (const XButtonPressedEvent* const buttonPressEvent) + { + updateKeyModifiers (buttonPressEvent->state); + + bool buttonMsg = false; + const int map = pointerMap [buttonPressEvent->button - Button1]; + + if (map == Keys::WheelUp || map == Keys::WheelDown) + { + handleMouseWheel (0, Point (buttonPressEvent->x, buttonPressEvent->y), + getEventTime (buttonPressEvent->time), 0, map == Keys::WheelDown ? -84.0f : 84.0f); + } + if (map == Keys::LeftButton) + { + currentModifiers = currentModifiers.withFlags (ModifierKeys::leftButtonModifier); + buttonMsg = true; + } + else if (map == Keys::RightButton) + { + currentModifiers = currentModifiers.withFlags (ModifierKeys::rightButtonModifier); + buttonMsg = true; + } + else if (map == Keys::MiddleButton) + { + currentModifiers = currentModifiers.withFlags (ModifierKeys::middleButtonModifier); + buttonMsg = true; + } + + if (buttonMsg) + { + toFront (true); + + handleMouseEvent (0, Point (buttonPressEvent->x, buttonPressEvent->y), currentModifiers, + getEventTime (buttonPressEvent->time)); + } + + clearLastMousePos(); + } + + void handleButtonReleaseEvent (const XButtonReleasedEvent* const buttonRelEvent) + { + updateKeyModifiers (buttonRelEvent->state); + const int map = pointerMap [buttonRelEvent->button - Button1]; + + if (map == Keys::LeftButton) currentModifiers = currentModifiers.withoutFlags (ModifierKeys::leftButtonModifier); + else if (map == Keys::RightButton) currentModifiers = currentModifiers.withoutFlags (ModifierKeys::rightButtonModifier); + else if (map == Keys::MiddleButton) currentModifiers = currentModifiers.withoutFlags (ModifierKeys::middleButtonModifier); + + handleMouseEvent (0, Point (buttonRelEvent->x, buttonRelEvent->y), currentModifiers, + getEventTime (buttonRelEvent->time)); + + clearLastMousePos(); + } + + void handleMotionNotifyEvent (const XPointerMovedEvent* const movedEvent) + { + updateKeyModifiers (movedEvent->state); + const Point mousePos (Desktop::getMousePosition()); + + if (lastMousePos != mousePos) + { + lastMousePos = mousePos; + + if (parentWindow != 0 && (styleFlags & windowHasTitleBar) == 0) + { + Window wRoot = 0, wParent = 0; + + { + ScopedXLock xlock; + unsigned int numChildren; + Window* wChild = 0; + XQueryTree (display, windowH, &wRoot, &wParent, &wChild, &numChildren); + } + + if (wParent != 0 + && wParent != windowH + && wParent != wRoot) + { + parentWindow = wParent; + updateBounds(); + } + else + { + parentWindow = 0; + } + } + + handleMouseEvent (0, mousePos - getScreenPosition(), currentModifiers, getEventTime (movedEvent->time)); + } + } + + void handleEnterNotifyEvent (const XEnterWindowEvent* const enterEvent) + { + clearLastMousePos(); + + if (! currentModifiers.isAnyMouseButtonDown()) + { + updateKeyModifiers (enterEvent->state); + handleMouseEvent (0, Point (enterEvent->x, enterEvent->y), currentModifiers, getEventTime (enterEvent->time)); + } + } + + void handleLeaveNotifyEvent (const XLeaveWindowEvent* const leaveEvent) + { + // Suppress the normal leave if we've got a pointer grab, or if + // it's a bogus one caused by clicking a mouse button when running + // in a Window manager + if (((! currentModifiers.isAnyMouseButtonDown()) && leaveEvent->mode == NotifyNormal) + || leaveEvent->mode == NotifyUngrab) + { + updateKeyModifiers (leaveEvent->state); + handleMouseEvent (0, Point (leaveEvent->x, leaveEvent->y), currentModifiers, getEventTime (leaveEvent->time)); + } + } + + void handleFocusInEvent() + { + isActiveApplication = true; + if (isFocused()) + handleFocusGain(); + } + + void handleFocusOutEvent() + { + isActiveApplication = false; + if (! isFocused()) + handleFocusLoss(); + } + + void handleExposeEvent (XExposeEvent* exposeEvent) + { + // Batch together all pending expose events + XEvent nextEvent; + ScopedXLock xlock; + + if (exposeEvent->window != windowH) + { + Window child; + XTranslateCoordinates (display, exposeEvent->window, windowH, + exposeEvent->x, exposeEvent->y, &exposeEvent->x, &exposeEvent->y, + &child); + } + + repaint (Rectangle (exposeEvent->x, exposeEvent->y, + exposeEvent->width, exposeEvent->height)); + + while (XEventsQueued (display, QueuedAfterFlush) > 0) + { + XPeekEvent (display, (XEvent*) &nextEvent); + if (nextEvent.type != Expose || nextEvent.xany.window != exposeEvent->window) + break; + + XNextEvent (display, (XEvent*) &nextEvent); + XExposeEvent* nextExposeEvent = (XExposeEvent*) &nextEvent.xexpose; + repaint (Rectangle (nextExposeEvent->x, nextExposeEvent->y, + nextExposeEvent->width, nextExposeEvent->height)); + } + } + + void handleConfigureNotifyEvent (XConfigureEvent* const confEvent) + { + updateBounds(); + updateBorderSize(); + handleMovedOrResized(); + + // if the native title bar is dragged, need to tell any active menus, etc. + if ((styleFlags & windowHasTitleBar) != 0 + && component->isCurrentlyBlockedByAnotherModalComponent()) + { + Component* const currentModalComp = Component::getCurrentlyModalComponent(); + + if (currentModalComp != 0) + currentModalComp->inputAttemptWhenModal(); + } + + if (confEvent->window == windowH + && confEvent->above != 0 + && isFrontWindow()) + { + handleBroughtToFront(); + } + } + + void handleReparentNotifyEvent() + { + parentWindow = 0; + Window wRoot = 0; + Window* wChild = 0; + unsigned int numChildren; + + { + ScopedXLock xlock; + XQueryTree (display, windowH, &wRoot, &parentWindow, &wChild, &numChildren); + } + + if (parentWindow == windowH || parentWindow == wRoot) + parentWindow = 0; + + handleGravityNotify(); + } + + void handleGravityNotify() + { + updateBounds(); + updateBorderSize(); + handleMovedOrResized(); + } + + void handleMappingNotify (XMappingEvent* const mappingEvent) + { + if (mappingEvent->request != MappingPointer) + { + // Deal with modifier/keyboard mapping + ScopedXLock xlock; + XRefreshKeyboardMapping (mappingEvent); + updateModifierMappings(); + } + } + + void handleClientMessageEvent (XClientMessageEvent* const clientMsg, XEvent* event) + { + if (clientMsg->message_type == Atoms::Protocols && clientMsg->format == 32) + { + const Atom atom = (Atom) clientMsg->data.l[0]; + + if (atom == Atoms::ProtocolList [Atoms::PING]) + { + Window root = RootWindow (display, DefaultScreen (display)); + + clientMsg->window = root; + + XSendEvent (display, root, False, NoEventMask, event); + XFlush (display); + } + else if (atom == Atoms::ProtocolList [Atoms::TAKE_FOCUS]) + { + XWindowAttributes atts; + + ScopedXLock xlock; + if (clientMsg->window != 0 + && XGetWindowAttributes (display, clientMsg->window, &atts)) + { + if (atts.map_state == IsViewable) + XSetInputFocus (display, clientMsg->window, RevertToParent, clientMsg->data.l[1]); + } + } + else if (atom == Atoms::ProtocolList [Atoms::DELETE_WINDOW]) + { + handleUserClosingWindow(); + } + } + else if (clientMsg->message_type == Atoms::XdndEnter) + { + handleDragAndDropEnter (clientMsg); + } + else if (clientMsg->message_type == Atoms::XdndLeave) + { + resetDragAndDrop(); + } + else if (clientMsg->message_type == Atoms::XdndPosition) + { + handleDragAndDropPosition (clientMsg); + } + else if (clientMsg->message_type == Atoms::XdndDrop) + { + handleDragAndDropDrop (clientMsg); + } + else if (clientMsg->message_type == Atoms::XdndStatus) + { + handleDragAndDropStatus (clientMsg); + } + else if (clientMsg->message_type == Atoms::XdndFinished) + { + resetDragAndDrop(); + } + } + void showMouseCursor (Cursor cursor) throw() { ScopedXLock xlock; @@ -259296,7 +259289,7 @@ private: : peer (peer_), lastTimeImageUsed (0) { -#if JUCE_USE_XSHM + #if JUCE_USE_XSHM shmCompletedDrawing = true; useARGBImagesForRendering = XSHMHelpers::isShmAvailable(); @@ -259313,19 +259306,15 @@ private: useARGBImagesForRendering = (testImage->bits_per_pixel == 32); XDestroyImage (testImage); } -#endif - } - - ~LinuxRepaintManager() - { + #endif } void timerCallback() { -#if JUCE_USE_XSHM + #if JUCE_USE_XSHM if (! shmCompletedDrawing) return; -#endif + #endif if (! regionsNeedingRepaint.isEmpty()) { stopTimer(); @@ -259348,13 +259337,13 @@ private: void performAnyPendingRepaintsNow() { -#if JUCE_USE_XSHM + #if JUCE_USE_XSHM if (! shmCompletedDrawing) { startTimer (repaintTimerPeriod); return; } -#endif + #endif peer->clearMaskedRegion(); @@ -259367,12 +259356,12 @@ private: if (image.isNull() || image.getWidth() < totalArea.getWidth() || image.getHeight() < totalArea.getHeight()) { -#if JUCE_USE_XSHM + #if JUCE_USE_XSHM image = Image (new XBitmapImage (useARGBImagesForRendering ? Image::ARGB : Image::RGB, -#else + #else image = Image (new XBitmapImage (Image::RGB, -#endif + #endif (totalArea.getWidth() + 31) & ~31, (totalArea.getHeight() + 31) & ~31, false, peer->depth, peer->visual)); @@ -259399,9 +259388,9 @@ private: for (RectangleList::Iterator i (originalRepaintRegion); i.next();) { -#if JUCE_USE_XSHM + #if JUCE_USE_XSHM shmCompletedDrawing = false; -#endif + #endif const Rectangle& r = *i.getRectangle(); static_cast (image.getSharedImage()) @@ -259415,9 +259404,9 @@ private: startTimer (repaintTimerPeriod); } -#if JUCE_USE_XSHM + #if JUCE_USE_XSHM void notifyPaintCompleted() { shmCompletedDrawing = true; } -#endif + #endif private: enum { repaintTimerPeriod = 1000 / 100 }; @@ -259427,9 +259416,9 @@ private: uint32 lastTimeImageUsed; RectangleList regionsNeedingRepaint; -#if JUCE_USE_XSHM + #if JUCE_USE_XSHM bool useARGBImagesForRendering, shmCompletedDrawing; -#endif + #endif JUCE_DECLARE_NON_COPYABLE (LinuxRepaintManager); }; @@ -259756,8 +259745,7 @@ private: else addWindowButtons (windowH); - // Set window name - setWindowTitle (windowH, getComponent()->getName()); + setTitle (getComponent()->getName()); // Associate the PID, allowing to be shut down when something goes wrong unsigned long pid = getpid(); @@ -259853,21 +259841,6 @@ private: return eventTimeOffset + thisMessageTime; } - static void setWindowTitle (Window xwin, const String& title) - { - XTextProperty nameProperty; - char* strings[] = { const_cast (title.toUTF8()) }; - ScopedXLock xlock; - - if (XStringListToTextProperty (strings, 1, &nameProperty)) - { - XSetWMName (display, xwin, &nameProperty); - XSetWMIconName (display, xwin, &nameProperty); - - XFree (nameProperty.value); - } - } - void updateBorderSize() { if ((styleFlags & windowHasTitleBar) == 0) @@ -260266,7 +260239,7 @@ void juce_updateMultiMonitorInfo (Array >& monitorCoords, const if (display == 0) return; -#if JUCE_USE_XINERAMA + #if JUCE_USE_XINERAMA int major_opcode, first_event, first_error; ScopedXLock xlock; @@ -260323,7 +260296,7 @@ void juce_updateMultiMonitorInfo (Array >& monitorCoords, const } if (monitorCoords.size() == 0) -#endif + #endif { Atom hints = XInternAtom (display, "_NET_WORKAREA", True); @@ -260445,7 +260418,7 @@ void* MouseCursor::createMouseCursorFromImage (const Image& image, int hotspotX, const unsigned int imageW = image.getWidth(); const unsigned int imageH = image.getHeight(); -#if JUCE_USE_XCURSOR + #if JUCE_USE_XCURSOR { typedef XcursorBool (*tXcursorSupportsARGB) (Display*); typedef XcursorImage* (*tXcursorImageCreate) (int, int); @@ -260499,7 +260472,7 @@ void* MouseCursor::createMouseCursorFromImage (const Image& image, int hotspotX, } } } -#endif + #endif Window root = RootWindow (display, DefaultScreen (display)); unsigned int cursorW, cursorH; @@ -264896,30 +264869,36 @@ void* threadEntryProc (void* userData) return 0; } -void* juce_createThread (void* userData) +void Thread::launchThread() { + threadHandle_ = 0; pthread_t handle = 0; - if (pthread_create (&handle, 0, threadEntryProc, userData) == 0) + if (pthread_create (&handle, 0, threadEntryProc, this) == 0) { pthread_detach (handle); - return (void*) handle; + threadHandle_ = (void*) handle; + threadId_ = (ThreadID) threadHandle_; } - - return 0; } -void juce_killThread (void* handle) +void Thread::closeThreadHandle() { - if (handle != 0) - pthread_cancel ((pthread_t) handle); + threadId_ = 0; + threadHandle_ = 0; } -void juce_setCurrentThreadName (const String& /*name*/) +void Thread::killThread() +{ + if (threadHandle_ != 0) + pthread_cancel ((pthread_t) threadHandle_); +} + +void Thread::setCurrentThreadName (const String& /*name*/) { } -bool juce_setThreadPriority (void* handle, int priority) +bool Thread::setThreadPriority (void* handle, int priority) { struct sched_param param; int policy; diff --git a/juce_amalgamated.h b/juce_amalgamated.h index dd4c2223d2..8202de0258 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -64,7 +64,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 99 +#define JUCE_BUILDNUMBER 100 /** Current Juce version number. @@ -134,17 +134,24 @@ #define JUCE_INTEL 1 #endif -#if JUCE_MAC +#if JUCE_MAC || JUCE_IOS - #ifndef NDEBUG + #if defined (DEBUG) || defined (_DEBUG) || ! (defined (NDEBUG) || defined (_NDEBUG)) #define JUCE_DEBUG 1 #endif + #if ! (defined (DEBUG) || defined (_DEBUG) || defined (NDEBUG) || defined (_NDEBUG)) + #warning "Neither NDEBUG or DEBUG has been defined - you should set one of these to make it clear whether this is a release build," + #endif + #ifdef __LITTLE_ENDIAN__ #define JUCE_LITTLE_ENDIAN 1 #else #define JUCE_BIG_ENDIAN 1 #endif +#endif + +#if JUCE_MAC #if defined (__ppc__) || defined (__ppc64__) #define JUCE_PPC 1 @@ -168,19 +175,6 @@ #endif -#if JUCE_IOS - - #ifndef NDEBUG - #define JUCE_DEBUG 1 - #endif - - #ifdef __LITTLE_ENDIAN__ - #define JUCE_LITTLE_ENDIAN 1 - #else - #define JUCE_BIG_ENDIAN 1 - #endif -#endif - #if JUCE_LINUX #ifdef _DEBUG @@ -18352,18 +18346,22 @@ private: const String threadName_; void* volatile threadHandle_; + ThreadID threadId_; CriticalSection startStopLock; WaitableEvent startSuspensionEvent_, defaultEvent_; - int threadPriority_; - ThreadID threadId_; uint32 affinityMask_; bool volatile threadShouldExit_; + friend class MessageManager; friend void JUCE_API juce_threadEntryPoint (void*); - static void threadEntryPoint (Thread* thread); - static Array runningThreads; - static CriticalSection runningThreadsLock; + + void launchThread(); + void closeThreadHandle(); + void killThread(); + void threadEntryPoint(); + static void setCurrentThreadName (const String& name); + static bool setThreadPriority (void* handle, int priority); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Thread); }; diff --git a/src/audio/audio_file_formats/juce_AudioThumbnail.cpp b/src/audio/audio_file_formats/juce_AudioThumbnail.cpp index 685f3884ff..5d3bf6f4f0 100644 --- a/src/audio/audio_file_formats/juce_AudioThumbnail.cpp +++ b/src/audio/audio_file_formats/juce_AudioThumbnail.cpp @@ -349,8 +349,8 @@ public: const double sampleRate, const int numChannels, const int samplesPerThumbSample, LevelDataSource* levelData, const OwnedArray& channels) { - refillCache (area.getWidth(), startTime, (endTime - startTime) / area.getWidth(), - sampleRate, numChannels, samplesPerThumbSample, levelData, channels); + refillCache (area.getWidth(), startTime, endTime, sampleRate, + numChannels, samplesPerThumbSample, levelData, channels); if (isPositiveAndBelow (channelNum, numChannelsCached)) { @@ -384,10 +384,12 @@ private: int numChannelsCached, numSamplesCached; bool cacheNeedsRefilling; - void refillCache (const int numSamples, double startTime, const double timePerPixel, + void refillCache (const int numSamples, double startTime, const double endTime, const double sampleRate, const int numChannels, const int samplesPerThumbSample, LevelDataSource* levelData, const OwnedArray& channels) { + const double timePerPixel = (endTime - startTime) / numSamples; + if (numSamples <= 0 || timePerPixel <= 0.0 || sampleRate <= 0) { invalidate(); @@ -685,7 +687,7 @@ double AudioThumbnail::getTotalLength() const throw() bool AudioThumbnail::isFullyLoaded() const throw() { - return numSamplesFinished >= totalSamples; + return numSamplesFinished >= totalSamples - samplesPerThumbSample; } void AudioThumbnail::drawChannel (Graphics& g, const Rectangle& area, double startTime, diff --git a/src/core/juce_Initialisation.cpp b/src/core/juce_Initialisation.cpp index b969c5b9b4..6ea9fc76b5 100644 --- a/src/core/juce_Initialisation.cpp +++ b/src/core/juce_Initialisation.cpp @@ -104,8 +104,6 @@ JUCE_API void JUCE_CALLTYPE shutdownJuce_NonGUI() //============================================================================== #if ! JUCE_ONLY_BUILD_CORE_LIBRARY -void juce_setCurrentThreadName (const String& name); - static bool juceInitialisedGUI = false; JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI() @@ -119,12 +117,9 @@ JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI() MessageManager::getInstance(); LookAndFeel::setDefaultLookAndFeel (0); - juce_setCurrentThreadName ("Juce Message Thread"); #if JUCE_DEBUG - // This section is just for catching people who mess up their project settings and - // turn RTTI off.. - try + try // This section is just a safety-net for catching builds without RTTI enabled.. { MemoryOutputStream mo; OutputStream* o = &mo; diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index e239d6e351..34a5768f6b 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -33,7 +33,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 99 +#define JUCE_BUILDNUMBER 100 /** Current Juce version number. diff --git a/src/core/juce_TargetPlatform.h b/src/core/juce_TargetPlatform.h index 1287da1ea7..309b543e6b 100644 --- a/src/core/juce_TargetPlatform.h +++ b/src/core/juce_TargetPlatform.h @@ -83,17 +83,24 @@ #endif //============================================================================== -#if JUCE_MAC +#if JUCE_MAC || JUCE_IOS - #ifndef NDEBUG + #if defined (DEBUG) || defined (_DEBUG) || ! (defined (NDEBUG) || defined (_NDEBUG)) #define JUCE_DEBUG 1 #endif + #if ! (defined (DEBUG) || defined (_DEBUG) || defined (NDEBUG) || defined (_NDEBUG)) + #warning "Neither NDEBUG or DEBUG has been defined - you should set one of these to make it clear whether this is a release build," + #endif + #ifdef __LITTLE_ENDIAN__ #define JUCE_LITTLE_ENDIAN 1 #else #define JUCE_BIG_ENDIAN 1 #endif +#endif + +#if JUCE_MAC #if defined (__ppc__) || defined (__ppc64__) #define JUCE_PPC 1 @@ -117,19 +124,6 @@ #endif -//============================================================================== -#if JUCE_IOS - - #ifndef NDEBUG - #define JUCE_DEBUG 1 - #endif - - #ifdef __LITTLE_ENDIAN__ - #define JUCE_LITTLE_ENDIAN 1 - #else - #define JUCE_BIG_ENDIAN 1 - #endif -#endif //============================================================================== #if JUCE_LINUX diff --git a/src/events/juce_MessageManager.cpp b/src/events/juce_MessageManager.cpp index 3acb204dcb..7e7c56df65 100644 --- a/src/events/juce_MessageManager.cpp +++ b/src/events/juce_MessageManager.cpp @@ -52,6 +52,9 @@ MessageManager::MessageManager() throw() threadWithLock (0) { messageThreadId = Thread::getCurrentThreadId(); + + if (JUCEApplication::isStandaloneApp()) + Thread::setCurrentThreadName ("Juce Message Thread"); } MessageManager::~MessageManager() throw() diff --git a/src/native/common/juce_posix_SharedCode.h b/src/native/common/juce_posix_SharedCode.h index 4a0c39fdeb..3b0796e316 100644 --- a/src/native/common/juce_posix_SharedCode.h +++ b/src/native/common/juce_posix_SharedCode.h @@ -660,30 +660,36 @@ void* threadEntryProc (void* userData) return 0; } -void* juce_createThread (void* userData) +void Thread::launchThread() { + threadHandle_ = 0; pthread_t handle = 0; - if (pthread_create (&handle, 0, threadEntryProc, userData) == 0) + if (pthread_create (&handle, 0, threadEntryProc, this) == 0) { pthread_detach (handle); - return (void*) handle; + threadHandle_ = (void*) handle; + threadId_ = (ThreadID) threadHandle_; } - - return 0; } -void juce_killThread (void* handle) +void Thread::closeThreadHandle() { - if (handle != 0) - pthread_cancel ((pthread_t) handle); + threadId_ = 0; + threadHandle_ = 0; } -void juce_setCurrentThreadName (const String& /*name*/) +void Thread::killThread() +{ + if (threadHandle_ != 0) + pthread_cancel ((pthread_t) threadHandle_); +} + +void Thread::setCurrentThreadName (const String& /*name*/) { } -bool juce_setThreadPriority (void* handle, int priority) +bool Thread::setThreadPriority (void* handle, int priority) { struct sched_param param; int policy; diff --git a/src/native/linux/juce_linux_Windowing.cpp b/src/native/linux/juce_linux_Windowing.cpp index 77013bc9cd..b7eb6fb434 100644 --- a/src/native/linux/juce_linux_Windowing.cpp +++ b/src/native/linux/juce_linux_Windowing.cpp @@ -677,6 +677,63 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XBitmapImage); }; +namespace PixmapHelpers +{ + Pixmap createColourPixmapFromImage (Display* display, const Image& image) + { + ScopedXLock xlock; + + const int width = image.getWidth(); + const int height = image.getHeight(); + HeapBlock colour (width * height); + int index = 0; + + for (int y = 0; y < height; ++y) + for (int x = 0; x < width; ++x) + colour[index++] = image.getPixelAt (x, y).getARGB(); + + XImage* ximage = XCreateImage (display, CopyFromParent, 24, ZPixmap, + 0, reinterpret_cast (colour.getData()), + width, height, 32, 0); + + Pixmap pixmap = XCreatePixmap (display, DefaultRootWindow (display), + width, height, 24); + + GC gc = XCreateGC (display, pixmap, 0, 0); + XPutImage (display, pixmap, gc, ximage, 0, 0, 0, 0, width, height); + XFreeGC (display, gc); + + return pixmap; + } + + Pixmap createMaskPixmapFromImage (Display* display, const Image& image) + { + ScopedXLock xlock; + + const int width = image.getWidth(); + const int height = image.getHeight(); + const int stride = (width + 7) >> 3; + HeapBlock mask; + mask.calloc (stride * height); + const bool msbfirst = (BitmapBitOrder (display) == MSBFirst); + + for (int y = 0; y < height; ++y) + { + for (int x = 0; x < width; ++x) + { + const char bit = (char) (1 << (msbfirst ? (7 - (x & 7)) : (x & 7))); + const int offset = y * stride + (x >> 3); + + if (image.getPixelAt (x, y).getAlpha() >= 128) + mask[offset] |= bit; + } + } + + return XCreatePixmapFromBitmapData (display, DefaultRootWindow (display), + mask.getData(), width, height, 1, 0, 1); + } +} + //============================================================================== class LinuxComponentPeer : public ComponentPeer @@ -749,17 +806,17 @@ public: void setTitle (const String& title) { - setWindowTitle (windowH, title); - } + XTextProperty nameProperty; + char* strings[] = { const_cast (title.toUTF8()) }; + ScopedXLock xlock; - void setPosition (int x, int y) - { - setBounds (x, y, ww, wh, false); - } + if (XStringListToTextProperty (strings, 1, &nameProperty)) + { + XSetWMName (display, windowH, &nameProperty); + XSetWMIconName (display, windowH, &nameProperty); - void setSize (int w, int h) - { - setBounds (wx, wy, w, h, false); + XFree (nameProperty.value); + } } void setBounds (int x, int y, int w, int h, bool isNowFullScreen) @@ -807,8 +864,10 @@ public: } } - const Rectangle getBounds() const { return Rectangle (wx, wy, ww, wh); } - const Point getScreenPosition() const { return Point (wx, wy); } + void setPosition (int x, int y) { setBounds (x, y, ww, wh, false); } + void setSize (int w, int h) { setBounds (wx, wy, w, h, false); } + const Rectangle getBounds() const { return Rectangle (wx, wy, ww, wh); } + const Point getScreenPosition() const { return Point (wx, wy); } const Point localToGlobal (const Point& relativePosition) { @@ -1084,60 +1143,6 @@ public: repainter->performAnyPendingRepaintsNow(); } - static Pixmap juce_createColourPixmapFromImage (Display* display, const Image& image) - { - ScopedXLock xlock; - - const int width = image.getWidth(); - const int height = image.getHeight(); - HeapBlock colour (width * height); - int index = 0; - - for (int y = 0; y < height; ++y) - for (int x = 0; x < width; ++x) - colour[index++] = image.getPixelAt (x, y).getARGB(); - - XImage* ximage = XCreateImage (display, CopyFromParent, 24, ZPixmap, - 0, reinterpret_cast (colour.getData()), - width, height, 32, 0); - - Pixmap pixmap = XCreatePixmap (display, DefaultRootWindow (display), - width, height, 24); - - GC gc = XCreateGC (display, pixmap, 0, 0); - XPutImage (display, pixmap, gc, ximage, 0, 0, 0, 0, width, height); - XFreeGC (display, gc); - - return pixmap; - } - - static Pixmap juce_createMaskPixmapFromImage (Display* display, const Image& image) - { - ScopedXLock xlock; - - const int width = image.getWidth(); - const int height = image.getHeight(); - const int stride = (width + 7) >> 3; - HeapBlock mask; - mask.calloc (stride * height); - const bool msbfirst = (BitmapBitOrder (display) == MSBFirst); - - for (int y = 0; y < height; ++y) - { - for (int x = 0; x < width; ++x) - { - const char bit = (char) (1 << (msbfirst ? (7 - (x & 7)) : (x & 7))); - const int offset = y * stride + (x >> 3); - - if (image.getPixelAt (x, y).getAlpha() >= 128) - mask[offset] |= bit; - } - } - - return XCreatePixmapFromBitmapData (display, DefaultRootWindow (display), - mask.getData(), width, height, 1, 0, 1); - } - void setIcon (const Image& newIcon) { const int dataSize = newIcon.getWidth() * newIcon.getHeight() + 2; @@ -1165,8 +1170,8 @@ public: wmHints = XAllocWMHints(); wmHints->flags |= IconPixmapHint | IconMaskHint; - wmHints->icon_pixmap = juce_createColourPixmapFromImage (display, newIcon); - wmHints->icon_mask = juce_createMaskPixmapFromImage (display, newIcon); + wmHints->icon_pixmap = PixmapHelpers::createColourPixmapFromImage (display, newIcon); + wmHints->icon_mask = PixmapHelpers::createMaskPixmapFromImage (display, newIcon); XSetWMHints (display, windowH, wmHints); XFree (wmHints); @@ -1203,315 +1208,22 @@ public: { switch (event->xany.type) { - case 2: // 'KeyPress' - { - char utf8 [64] = { 0 }; - juce_wchar unicodeChar = 0; - int keyCode = 0; - bool keyDownChange = false; - KeySym sym; - - { - ScopedXLock xlock; - XKeyEvent* const keyEvent = (XKeyEvent*) &event->xkey; - updateKeyStates (keyEvent->keycode, true); - - const char* oldLocale = ::setlocale (LC_ALL, 0); - ::setlocale (LC_ALL, ""); - XLookupString (keyEvent, utf8, sizeof (utf8), &sym, 0); - ::setlocale (LC_ALL, oldLocale); - - unicodeChar = String::fromUTF8 (utf8, sizeof (utf8) - 1) [0]; - keyCode = (int) unicodeChar; - - if (keyCode < 0x20) - keyCode = XKeycodeToKeysym (display, keyEvent->keycode, currentModifiers.isShiftDown() ? 1 : 0); - - keyDownChange = (sym != NoSymbol) && ! updateKeyModifiersFromSym (sym, true); - } - - const ModifierKeys oldMods (currentModifiers); - bool keyPressed = false; - - if ((sym & 0xff00) == 0xff00) - { - switch (sym) // Translate keypad - { - case XK_KP_Divide: keyCode = XK_slash; break; - case XK_KP_Multiply: keyCode = XK_asterisk; break; - case XK_KP_Subtract: keyCode = XK_hyphen; break; - case XK_KP_Add: keyCode = XK_plus; break; - case XK_KP_Enter: keyCode = XK_Return; break; - case XK_KP_Decimal: keyCode = Keys::numLock ? XK_period : XK_Delete; break; - case XK_KP_0: keyCode = Keys::numLock ? XK_0 : XK_Insert; break; - case XK_KP_1: keyCode = Keys::numLock ? XK_1 : XK_End; break; - case XK_KP_2: keyCode = Keys::numLock ? XK_2 : XK_Down; break; - case XK_KP_3: keyCode = Keys::numLock ? XK_3 : XK_Page_Down; break; - case XK_KP_4: keyCode = Keys::numLock ? XK_4 : XK_Left; break; - case XK_KP_5: keyCode = XK_5; break; - case XK_KP_6: keyCode = Keys::numLock ? XK_6 : XK_Right; break; - case XK_KP_7: keyCode = Keys::numLock ? XK_7 : XK_Home; break; - case XK_KP_8: keyCode = Keys::numLock ? XK_8 : XK_Up; break; - case XK_KP_9: keyCode = Keys::numLock ? XK_9 : XK_Page_Up; break; - default: break; - } - - switch (sym) - { - case XK_Left: - case XK_Right: - case XK_Up: - case XK_Down: - case XK_Page_Up: - case XK_Page_Down: - case XK_End: - case XK_Home: - case XK_Delete: - case XK_Insert: - keyPressed = true; - keyCode = (sym & 0xff) | Keys::extendedKeyModifier; - break; - case XK_Tab: - case XK_Return: - case XK_Escape: - case XK_BackSpace: - keyPressed = true; - keyCode &= 0xff; - break; - default: - { - if (sym >= XK_F1 && sym <= XK_F16) - { - keyPressed = true; - keyCode = (sym & 0xff) | Keys::extendedKeyModifier; - } - break; - } - } - } - - if (utf8[0] != 0 || ((sym & 0xff00) == 0 && sym >= 8)) - keyPressed = true; - - if (oldMods != currentModifiers) - handleModifierKeysChange(); - - if (keyDownChange) - handleKeyUpOrDown (true); - - if (keyPressed) - handleKeyPress (keyCode, unicodeChar); - - break; - } - - case KeyRelease: - { - const XKeyEvent* const keyEvent = (const XKeyEvent*) &event->xkey; - updateKeyStates (keyEvent->keycode, false); - KeySym sym; - - { - ScopedXLock xlock; - sym = XKeycodeToKeysym (display, keyEvent->keycode, 0); - } - - const ModifierKeys oldMods (currentModifiers); - const bool keyDownChange = (sym != NoSymbol) && ! updateKeyModifiersFromSym (sym, false); - - if (oldMods != currentModifiers) - handleModifierKeysChange(); - - if (keyDownChange) - handleKeyUpOrDown (false); - - break; - } - - case ButtonPress: - { - const XButtonPressedEvent* const buttonPressEvent = (const XButtonPressedEvent*) &event->xbutton; - updateKeyModifiers (buttonPressEvent->state); - - bool buttonMsg = false; - const int map = pointerMap [buttonPressEvent->button - Button1]; - - if (map == Keys::WheelUp || map == Keys::WheelDown) - { - handleMouseWheel (0, Point (buttonPressEvent->x, buttonPressEvent->y), - getEventTime (buttonPressEvent->time), 0, map == Keys::WheelDown ? -84.0f : 84.0f); - } - if (map == Keys::LeftButton) - { - currentModifiers = currentModifiers.withFlags (ModifierKeys::leftButtonModifier); - buttonMsg = true; - } - else if (map == Keys::RightButton) - { - currentModifiers = currentModifiers.withFlags (ModifierKeys::rightButtonModifier); - buttonMsg = true; - } - else if (map == Keys::MiddleButton) - { - currentModifiers = currentModifiers.withFlags (ModifierKeys::middleButtonModifier); - buttonMsg = true; - } - - if (buttonMsg) - { - toFront (true); - - handleMouseEvent (0, Point (buttonPressEvent->x, buttonPressEvent->y), currentModifiers, - getEventTime (buttonPressEvent->time)); - } - - clearLastMousePos(); - break; - } - - case ButtonRelease: - { - const XButtonReleasedEvent* const buttonRelEvent = (const XButtonReleasedEvent*) &event->xbutton; - updateKeyModifiers (buttonRelEvent->state); - - const int map = pointerMap [buttonRelEvent->button - Button1]; - - if (map == Keys::LeftButton) - currentModifiers = currentModifiers.withoutFlags (ModifierKeys::leftButtonModifier); - else if (map == Keys::RightButton) - currentModifiers = currentModifiers.withoutFlags (ModifierKeys::rightButtonModifier); - else if (map == Keys::MiddleButton) - currentModifiers = currentModifiers.withoutFlags (ModifierKeys::middleButtonModifier); - - handleMouseEvent (0, Point (buttonRelEvent->x, buttonRelEvent->y), currentModifiers, - getEventTime (buttonRelEvent->time)); - - clearLastMousePos(); - break; - } - - case MotionNotify: - { - const XPointerMovedEvent* const movedEvent = (const XPointerMovedEvent*) &event->xmotion; - updateKeyModifiers (movedEvent->state); - - const Point mousePos (Desktop::getMousePosition()); - - if (lastMousePos != mousePos) - { - lastMousePos = mousePos; - - if (parentWindow != 0 && (styleFlags & windowHasTitleBar) == 0) - { - Window wRoot = 0, wParent = 0; - - { - ScopedXLock xlock; - unsigned int numChildren; - Window* wChild = 0; - XQueryTree (display, windowH, &wRoot, &wParent, &wChild, &numChildren); - } - - if (wParent != 0 - && wParent != windowH - && wParent != wRoot) - { - parentWindow = wParent; - updateBounds(); - } - else - { - parentWindow = 0; - } - } - - handleMouseEvent (0, mousePos - getScreenPosition(), currentModifiers, getEventTime (movedEvent->time)); - } - - break; - } - - case EnterNotify: - { - clearLastMousePos(); - const XEnterWindowEvent* const enterEvent = (const XEnterWindowEvent*) &event->xcrossing; - - if (! currentModifiers.isAnyMouseButtonDown()) - { - updateKeyModifiers (enterEvent->state); - handleMouseEvent (0, Point (enterEvent->x, enterEvent->y), currentModifiers, getEventTime (enterEvent->time)); - } - - break; - } - - case LeaveNotify: - { - const XLeaveWindowEvent* const leaveEvent = (const XLeaveWindowEvent*) &event->xcrossing; - - // Suppress the normal leave if we've got a pointer grab, or if - // it's a bogus one caused by clicking a mouse button when running - // in a Window manager - if (((! currentModifiers.isAnyMouseButtonDown()) && leaveEvent->mode == NotifyNormal) - || leaveEvent->mode == NotifyUngrab) - { - updateKeyModifiers (leaveEvent->state); - handleMouseEvent (0, Point (leaveEvent->x, leaveEvent->y), currentModifiers, getEventTime (leaveEvent->time)); - } - - break; - } - - case FocusIn: - { - isActiveApplication = true; - if (isFocused()) - handleFocusGain(); - - break; - } - - case FocusOut: - { - isActiveApplication = false; - if (! isFocused()) - handleFocusLoss(); - - break; - } - - case Expose: - { - // Batch together all pending expose events - XExposeEvent* exposeEvent = (XExposeEvent*) &event->xexpose; - XEvent nextEvent; - ScopedXLock xlock; - - if (exposeEvent->window != windowH) - { - Window child; - XTranslateCoordinates (display, exposeEvent->window, windowH, - exposeEvent->x, exposeEvent->y, &exposeEvent->x, &exposeEvent->y, - &child); - } - - repaint (Rectangle (exposeEvent->x, exposeEvent->y, - exposeEvent->width, exposeEvent->height)); - - while (XEventsQueued (display, QueuedAfterFlush) > 0) - { - XPeekEvent (display, (XEvent*) &nextEvent); - if (nextEvent.type != Expose || nextEvent.xany.window != event->xany.window) - break; - - XNextEvent (display, (XEvent*) &nextEvent); - XExposeEvent* nextExposeEvent = (XExposeEvent*) &nextEvent.xexpose; - repaint (Rectangle (nextExposeEvent->x, nextExposeEvent->y, - nextExposeEvent->width, nextExposeEvent->height)); - } - - break; - } + case 2: /* KeyPress */ handleKeyPressEvent ((XKeyEvent*) &event->xkey); break; + case KeyRelease: handleKeyReleaseEvent ((const XKeyEvent*) &event->xkey); break; + case ButtonPress: handleButtonPressEvent ((const XButtonPressedEvent*) &event->xbutton); break; + case ButtonRelease: handleButtonReleaseEvent ((const XButtonReleasedEvent*) &event->xbutton); break; + case MotionNotify: handleMotionNotifyEvent ((const XPointerMovedEvent*) &event->xmotion); break; + case EnterNotify: handleEnterNotifyEvent ((const XEnterWindowEvent*) &event->xcrossing); break; + case LeaveNotify: handleLeaveNotifyEvent ((const XLeaveWindowEvent*) &event->xcrossing); break; + case FocusIn: handleFocusInEvent(); break; + case FocusOut: handleFocusOutEvent(); break; + case Expose: handleExposeEvent ((XExposeEvent*) &event->xexpose); break; + case MappingNotify: handleMappingNotify ((XMappingEvent*) &event->xmapping); break; + case ClientMessage: handleClientMessageEvent ((XClientMessageEvent*) &event->xclient, event); break; + case SelectionNotify: handleDragAndDropSelection (event); break; + case ConfigureNotify: handleConfigureNotifyEvent ((XConfigureEvent*) &event->xconfigure); break; + case ReparentNotify: handleReparentNotifyEvent(); break; + case GravityNotify: handleGravityNotify(); break; case CirculateNotify: case CreateNotify: @@ -1519,63 +1231,6 @@ public: // Think we can ignore these break; - case ConfigureNotify: - { - updateBounds(); - updateBorderSize(); - handleMovedOrResized(); - - // if the native title bar is dragged, need to tell any active menus, etc. - if ((styleFlags & windowHasTitleBar) != 0 - && component->isCurrentlyBlockedByAnotherModalComponent()) - { - Component* const currentModalComp = Component::getCurrentlyModalComponent(); - - if (currentModalComp != 0) - currentModalComp->inputAttemptWhenModal(); - } - - XConfigureEvent* const confEvent = (XConfigureEvent*) &event->xconfigure; - - if (confEvent->window == windowH - && confEvent->above != 0 - && isFrontWindow()) - { - handleBroughtToFront(); - } - - break; - } - - case ReparentNotify: - { - parentWindow = 0; - Window wRoot = 0; - Window* wChild = 0; - unsigned int numChildren; - - { - ScopedXLock xlock; - XQueryTree (display, windowH, &wRoot, &parentWindow, &wChild, &numChildren); - } - - if (parentWindow == windowH || parentWindow == wRoot) - parentWindow = 0; - - updateBounds(); - updateBorderSize(); - handleMovedOrResized(); - break; - } - - case GravityNotify: - { - updateBounds(); - updateBorderSize(); - handleMovedOrResized(); - break; - } - case MapNotify: mapped = true; handleBroughtToFront(); @@ -1585,103 +1240,419 @@ public: mapped = false; break; - case MappingNotify: - { - XMappingEvent* mappingEvent = (XMappingEvent*) &event->xmapping; - - if (mappingEvent->request != MappingPointer) - { - // Deal with modifier/keyboard mapping - ScopedXLock xlock; - XRefreshKeyboardMapping (mappingEvent); - updateModifierMappings(); - } - - break; - } - - case ClientMessage: - { - const XClientMessageEvent* const clientMsg = (const XClientMessageEvent*) &event->xclient; - - if (clientMsg->message_type == Atoms::Protocols && clientMsg->format == 32) - { - const Atom atom = (Atom) clientMsg->data.l[0]; - - if (atom == Atoms::ProtocolList [Atoms::PING]) - { - Window root = RootWindow (display, DefaultScreen (display)); - - event->xclient.window = root; - - XSendEvent (display, root, False, NoEventMask, event); - XFlush (display); - } - else if (atom == Atoms::ProtocolList [Atoms::TAKE_FOCUS]) - { - XWindowAttributes atts; - - ScopedXLock xlock; - if (clientMsg->window != 0 - && XGetWindowAttributes (display, clientMsg->window, &atts)) - { - if (atts.map_state == IsViewable) - XSetInputFocus (display, clientMsg->window, RevertToParent, clientMsg->data.l[1]); - } - } - else if (atom == Atoms::ProtocolList [Atoms::DELETE_WINDOW]) - { - handleUserClosingWindow(); - } - } - else if (clientMsg->message_type == Atoms::XdndEnter) - { - handleDragAndDropEnter (clientMsg); - } - else if (clientMsg->message_type == Atoms::XdndLeave) - { - resetDragAndDrop(); - } - else if (clientMsg->message_type == Atoms::XdndPosition) - { - handleDragAndDropPosition (clientMsg); - } - else if (clientMsg->message_type == Atoms::XdndDrop) - { - handleDragAndDropDrop (clientMsg); - } - else if (clientMsg->message_type == Atoms::XdndStatus) - { - handleDragAndDropStatus (clientMsg); - } - else if (clientMsg->message_type == Atoms::XdndFinished) - { - resetDragAndDrop(); - } - - break; - } - - case SelectionNotify: - handleDragAndDropSelection (event); - break; - case SelectionClear: case SelectionRequest: break; default: -#if JUCE_USE_XSHM - { - ScopedXLock xlock; - if (event->xany.type == XShmGetEventBase (display)) - repainter->notifyPaintCompleted(); - } -#endif + #if JUCE_USE_XSHM + { + ScopedXLock xlock; + if (event->xany.type == XShmGetEventBase (display)) + repainter->notifyPaintCompleted(); + } + #endif break; } } + void handleKeyPressEvent (XKeyEvent* const keyEvent) + { + char utf8 [64] = { 0 }; + juce_wchar unicodeChar = 0; + int keyCode = 0; + bool keyDownChange = false; + KeySym sym; + + { + ScopedXLock xlock; + updateKeyStates (keyEvent->keycode, true); + + const char* oldLocale = ::setlocale (LC_ALL, 0); + ::setlocale (LC_ALL, ""); + XLookupString (keyEvent, utf8, sizeof (utf8), &sym, 0); + ::setlocale (LC_ALL, oldLocale); + + unicodeChar = String::fromUTF8 (utf8, sizeof (utf8) - 1) [0]; + keyCode = (int) unicodeChar; + + if (keyCode < 0x20) + keyCode = XKeycodeToKeysym (display, keyEvent->keycode, currentModifiers.isShiftDown() ? 1 : 0); + + keyDownChange = (sym != NoSymbol) && ! updateKeyModifiersFromSym (sym, true); + } + + const ModifierKeys oldMods (currentModifiers); + bool keyPressed = false; + + if ((sym & 0xff00) == 0xff00) + { + switch (sym) // Translate keypad + { + case XK_KP_Divide: keyCode = XK_slash; break; + case XK_KP_Multiply: keyCode = XK_asterisk; break; + case XK_KP_Subtract: keyCode = XK_hyphen; break; + case XK_KP_Add: keyCode = XK_plus; break; + case XK_KP_Enter: keyCode = XK_Return; break; + case XK_KP_Decimal: keyCode = Keys::numLock ? XK_period : XK_Delete; break; + case XK_KP_0: keyCode = Keys::numLock ? XK_0 : XK_Insert; break; + case XK_KP_1: keyCode = Keys::numLock ? XK_1 : XK_End; break; + case XK_KP_2: keyCode = Keys::numLock ? XK_2 : XK_Down; break; + case XK_KP_3: keyCode = Keys::numLock ? XK_3 : XK_Page_Down; break; + case XK_KP_4: keyCode = Keys::numLock ? XK_4 : XK_Left; break; + case XK_KP_5: keyCode = XK_5; break; + case XK_KP_6: keyCode = Keys::numLock ? XK_6 : XK_Right; break; + case XK_KP_7: keyCode = Keys::numLock ? XK_7 : XK_Home; break; + case XK_KP_8: keyCode = Keys::numLock ? XK_8 : XK_Up; break; + case XK_KP_9: keyCode = Keys::numLock ? XK_9 : XK_Page_Up; break; + default: break; + } + + switch (sym) + { + case XK_Left: + case XK_Right: + case XK_Up: + case XK_Down: + case XK_Page_Up: + case XK_Page_Down: + case XK_End: + case XK_Home: + case XK_Delete: + case XK_Insert: + keyPressed = true; + keyCode = (sym & 0xff) | Keys::extendedKeyModifier; + break; + + case XK_Tab: + case XK_Return: + case XK_Escape: + case XK_BackSpace: + keyPressed = true; + keyCode &= 0xff; + break; + + default: + if (sym >= XK_F1 && sym <= XK_F16) + { + keyPressed = true; + keyCode = (sym & 0xff) | Keys::extendedKeyModifier; + } + break; + } + } + + if (utf8[0] != 0 || ((sym & 0xff00) == 0 && sym >= 8)) + keyPressed = true; + + if (oldMods != currentModifiers) + handleModifierKeysChange(); + + if (keyDownChange) + handleKeyUpOrDown (true); + + if (keyPressed) + handleKeyPress (keyCode, unicodeChar); + } + + void handleKeyReleaseEvent (const XKeyEvent* const keyEvent) + { + updateKeyStates (keyEvent->keycode, false); + KeySym sym; + + { + ScopedXLock xlock; + sym = XKeycodeToKeysym (display, keyEvent->keycode, 0); + } + + const ModifierKeys oldMods (currentModifiers); + const bool keyDownChange = (sym != NoSymbol) && ! updateKeyModifiersFromSym (sym, false); + + if (oldMods != currentModifiers) + handleModifierKeysChange(); + + if (keyDownChange) + handleKeyUpOrDown (false); + } + + void handleButtonPressEvent (const XButtonPressedEvent* const buttonPressEvent) + { + updateKeyModifiers (buttonPressEvent->state); + + bool buttonMsg = false; + const int map = pointerMap [buttonPressEvent->button - Button1]; + + if (map == Keys::WheelUp || map == Keys::WheelDown) + { + handleMouseWheel (0, Point (buttonPressEvent->x, buttonPressEvent->y), + getEventTime (buttonPressEvent->time), 0, map == Keys::WheelDown ? -84.0f : 84.0f); + } + if (map == Keys::LeftButton) + { + currentModifiers = currentModifiers.withFlags (ModifierKeys::leftButtonModifier); + buttonMsg = true; + } + else if (map == Keys::RightButton) + { + currentModifiers = currentModifiers.withFlags (ModifierKeys::rightButtonModifier); + buttonMsg = true; + } + else if (map == Keys::MiddleButton) + { + currentModifiers = currentModifiers.withFlags (ModifierKeys::middleButtonModifier); + buttonMsg = true; + } + + if (buttonMsg) + { + toFront (true); + + handleMouseEvent (0, Point (buttonPressEvent->x, buttonPressEvent->y), currentModifiers, + getEventTime (buttonPressEvent->time)); + } + + clearLastMousePos(); + } + + void handleButtonReleaseEvent (const XButtonReleasedEvent* const buttonRelEvent) + { + updateKeyModifiers (buttonRelEvent->state); + const int map = pointerMap [buttonRelEvent->button - Button1]; + + if (map == Keys::LeftButton) currentModifiers = currentModifiers.withoutFlags (ModifierKeys::leftButtonModifier); + else if (map == Keys::RightButton) currentModifiers = currentModifiers.withoutFlags (ModifierKeys::rightButtonModifier); + else if (map == Keys::MiddleButton) currentModifiers = currentModifiers.withoutFlags (ModifierKeys::middleButtonModifier); + + handleMouseEvent (0, Point (buttonRelEvent->x, buttonRelEvent->y), currentModifiers, + getEventTime (buttonRelEvent->time)); + + clearLastMousePos(); + } + + void handleMotionNotifyEvent (const XPointerMovedEvent* const movedEvent) + { + updateKeyModifiers (movedEvent->state); + const Point mousePos (Desktop::getMousePosition()); + + if (lastMousePos != mousePos) + { + lastMousePos = mousePos; + + if (parentWindow != 0 && (styleFlags & windowHasTitleBar) == 0) + { + Window wRoot = 0, wParent = 0; + + { + ScopedXLock xlock; + unsigned int numChildren; + Window* wChild = 0; + XQueryTree (display, windowH, &wRoot, &wParent, &wChild, &numChildren); + } + + if (wParent != 0 + && wParent != windowH + && wParent != wRoot) + { + parentWindow = wParent; + updateBounds(); + } + else + { + parentWindow = 0; + } + } + + handleMouseEvent (0, mousePos - getScreenPosition(), currentModifiers, getEventTime (movedEvent->time)); + } + } + + void handleEnterNotifyEvent (const XEnterWindowEvent* const enterEvent) + { + clearLastMousePos(); + + if (! currentModifiers.isAnyMouseButtonDown()) + { + updateKeyModifiers (enterEvent->state); + handleMouseEvent (0, Point (enterEvent->x, enterEvent->y), currentModifiers, getEventTime (enterEvent->time)); + } + } + + void handleLeaveNotifyEvent (const XLeaveWindowEvent* const leaveEvent) + { + // Suppress the normal leave if we've got a pointer grab, or if + // it's a bogus one caused by clicking a mouse button when running + // in a Window manager + if (((! currentModifiers.isAnyMouseButtonDown()) && leaveEvent->mode == NotifyNormal) + || leaveEvent->mode == NotifyUngrab) + { + updateKeyModifiers (leaveEvent->state); + handleMouseEvent (0, Point (leaveEvent->x, leaveEvent->y), currentModifiers, getEventTime (leaveEvent->time)); + } + } + + void handleFocusInEvent() + { + isActiveApplication = true; + if (isFocused()) + handleFocusGain(); + } + + void handleFocusOutEvent() + { + isActiveApplication = false; + if (! isFocused()) + handleFocusLoss(); + } + + void handleExposeEvent (XExposeEvent* exposeEvent) + { + // Batch together all pending expose events + XEvent nextEvent; + ScopedXLock xlock; + + if (exposeEvent->window != windowH) + { + Window child; + XTranslateCoordinates (display, exposeEvent->window, windowH, + exposeEvent->x, exposeEvent->y, &exposeEvent->x, &exposeEvent->y, + &child); + } + + repaint (Rectangle (exposeEvent->x, exposeEvent->y, + exposeEvent->width, exposeEvent->height)); + + while (XEventsQueued (display, QueuedAfterFlush) > 0) + { + XPeekEvent (display, (XEvent*) &nextEvent); + if (nextEvent.type != Expose || nextEvent.xany.window != exposeEvent->window) + break; + + XNextEvent (display, (XEvent*) &nextEvent); + XExposeEvent* nextExposeEvent = (XExposeEvent*) &nextEvent.xexpose; + repaint (Rectangle (nextExposeEvent->x, nextExposeEvent->y, + nextExposeEvent->width, nextExposeEvent->height)); + } + } + + void handleConfigureNotifyEvent (XConfigureEvent* const confEvent) + { + updateBounds(); + updateBorderSize(); + handleMovedOrResized(); + + // if the native title bar is dragged, need to tell any active menus, etc. + if ((styleFlags & windowHasTitleBar) != 0 + && component->isCurrentlyBlockedByAnotherModalComponent()) + { + Component* const currentModalComp = Component::getCurrentlyModalComponent(); + + if (currentModalComp != 0) + currentModalComp->inputAttemptWhenModal(); + } + + if (confEvent->window == windowH + && confEvent->above != 0 + && isFrontWindow()) + { + handleBroughtToFront(); + } + } + + void handleReparentNotifyEvent() + { + parentWindow = 0; + Window wRoot = 0; + Window* wChild = 0; + unsigned int numChildren; + + { + ScopedXLock xlock; + XQueryTree (display, windowH, &wRoot, &parentWindow, &wChild, &numChildren); + } + + if (parentWindow == windowH || parentWindow == wRoot) + parentWindow = 0; + + handleGravityNotify(); + } + + void handleGravityNotify() + { + updateBounds(); + updateBorderSize(); + handleMovedOrResized(); + } + + void handleMappingNotify (XMappingEvent* const mappingEvent) + { + if (mappingEvent->request != MappingPointer) + { + // Deal with modifier/keyboard mapping + ScopedXLock xlock; + XRefreshKeyboardMapping (mappingEvent); + updateModifierMappings(); + } + } + + void handleClientMessageEvent (XClientMessageEvent* const clientMsg, XEvent* event) + { + if (clientMsg->message_type == Atoms::Protocols && clientMsg->format == 32) + { + const Atom atom = (Atom) clientMsg->data.l[0]; + + if (atom == Atoms::ProtocolList [Atoms::PING]) + { + Window root = RootWindow (display, DefaultScreen (display)); + + clientMsg->window = root; + + XSendEvent (display, root, False, NoEventMask, event); + XFlush (display); + } + else if (atom == Atoms::ProtocolList [Atoms::TAKE_FOCUS]) + { + XWindowAttributes atts; + + ScopedXLock xlock; + if (clientMsg->window != 0 + && XGetWindowAttributes (display, clientMsg->window, &atts)) + { + if (atts.map_state == IsViewable) + XSetInputFocus (display, clientMsg->window, RevertToParent, clientMsg->data.l[1]); + } + } + else if (atom == Atoms::ProtocolList [Atoms::DELETE_WINDOW]) + { + handleUserClosingWindow(); + } + } + else if (clientMsg->message_type == Atoms::XdndEnter) + { + handleDragAndDropEnter (clientMsg); + } + else if (clientMsg->message_type == Atoms::XdndLeave) + { + resetDragAndDrop(); + } + else if (clientMsg->message_type == Atoms::XdndPosition) + { + handleDragAndDropPosition (clientMsg); + } + else if (clientMsg->message_type == Atoms::XdndDrop) + { + handleDragAndDropDrop (clientMsg); + } + else if (clientMsg->message_type == Atoms::XdndStatus) + { + handleDragAndDropStatus (clientMsg); + } + else if (clientMsg->message_type == Atoms::XdndFinished) + { + resetDragAndDrop(); + } + } + + //============================================================================== void showMouseCursor (Cursor cursor) throw() { ScopedXLock xlock; @@ -1763,7 +1734,7 @@ private: : peer (peer_), lastTimeImageUsed (0) { -#if JUCE_USE_XSHM + #if JUCE_USE_XSHM shmCompletedDrawing = true; useARGBImagesForRendering = XSHMHelpers::isShmAvailable(); @@ -1780,19 +1751,15 @@ private: useARGBImagesForRendering = (testImage->bits_per_pixel == 32); XDestroyImage (testImage); } -#endif - } - - ~LinuxRepaintManager() - { + #endif } void timerCallback() { -#if JUCE_USE_XSHM + #if JUCE_USE_XSHM if (! shmCompletedDrawing) return; -#endif + #endif if (! regionsNeedingRepaint.isEmpty()) { stopTimer(); @@ -1815,13 +1782,13 @@ private: void performAnyPendingRepaintsNow() { -#if JUCE_USE_XSHM + #if JUCE_USE_XSHM if (! shmCompletedDrawing) { startTimer (repaintTimerPeriod); return; } -#endif + #endif peer->clearMaskedRegion(); @@ -1834,12 +1801,12 @@ private: if (image.isNull() || image.getWidth() < totalArea.getWidth() || image.getHeight() < totalArea.getHeight()) { -#if JUCE_USE_XSHM + #if JUCE_USE_XSHM image = Image (new XBitmapImage (useARGBImagesForRendering ? Image::ARGB : Image::RGB, -#else + #else image = Image (new XBitmapImage (Image::RGB, -#endif + #endif (totalArea.getWidth() + 31) & ~31, (totalArea.getHeight() + 31) & ~31, false, peer->depth, peer->visual)); @@ -1866,9 +1833,9 @@ private: for (RectangleList::Iterator i (originalRepaintRegion); i.next();) { -#if JUCE_USE_XSHM + #if JUCE_USE_XSHM shmCompletedDrawing = false; -#endif + #endif const Rectangle& r = *i.getRectangle(); static_cast (image.getSharedImage()) @@ -1882,9 +1849,9 @@ private: startTimer (repaintTimerPeriod); } -#if JUCE_USE_XSHM + #if JUCE_USE_XSHM void notifyPaintCompleted() { shmCompletedDrawing = true; } -#endif + #endif private: enum { repaintTimerPeriod = 1000 / 100 }; @@ -1894,9 +1861,9 @@ private: uint32 lastTimeImageUsed; RectangleList regionsNeedingRepaint; -#if JUCE_USE_XSHM + #if JUCE_USE_XSHM bool useARGBImagesForRendering, shmCompletedDrawing; -#endif + #endif JUCE_DECLARE_NON_COPYABLE (LinuxRepaintManager); }; @@ -2224,8 +2191,7 @@ private: else addWindowButtons (windowH); - // Set window name - setWindowTitle (windowH, getComponent()->getName()); + setTitle (getComponent()->getName()); // Associate the PID, allowing to be shut down when something goes wrong unsigned long pid = getpid(); @@ -2321,21 +2287,6 @@ private: return eventTimeOffset + thisMessageTime; } - static void setWindowTitle (Window xwin, const String& title) - { - XTextProperty nameProperty; - char* strings[] = { const_cast (title.toUTF8()) }; - ScopedXLock xlock; - - if (XStringListToTextProperty (strings, 1, &nameProperty)) - { - XSetWMName (display, xwin, &nameProperty); - XSetWMIconName (display, xwin, &nameProperty); - - XFree (nameProperty.value); - } - } - void updateBorderSize() { if ((styleFlags & windowHasTitleBar) == 0) @@ -2743,7 +2694,7 @@ void juce_updateMultiMonitorInfo (Array >& monitorCoords, const if (display == 0) return; -#if JUCE_USE_XINERAMA + #if JUCE_USE_XINERAMA int major_opcode, first_event, first_error; ScopedXLock xlock; @@ -2800,7 +2751,7 @@ void juce_updateMultiMonitorInfo (Array >& monitorCoords, const } if (monitorCoords.size() == 0) -#endif + #endif { Atom hints = XInternAtom (display, "_NET_WORKAREA", True); @@ -2925,7 +2876,7 @@ void* MouseCursor::createMouseCursorFromImage (const Image& image, int hotspotX, const unsigned int imageW = image.getWidth(); const unsigned int imageH = image.getHeight(); -#if JUCE_USE_XCURSOR + #if JUCE_USE_XCURSOR { typedef XcursorBool (*tXcursorSupportsARGB) (Display*); typedef XcursorImage* (*tXcursorImageCreate) (int, int); @@ -2979,7 +2930,7 @@ void* MouseCursor::createMouseCursorFromImage (const Image& image, int hotspotX, } } } -#endif + #endif Window root = RootWindow (display, DefaultScreen (display)); unsigned int cursorW, cursorH; diff --git a/src/native/windows/juce_win32_SystemStats.cpp b/src/native/windows/juce_win32_SystemStats.cpp index e9162bcc9b..a10fc7a400 100644 --- a/src/native/windows/juce_win32_SystemStats.cpp +++ b/src/native/windows/juce_win32_SystemStats.cpp @@ -27,8 +27,6 @@ // compiled on its own). #if JUCE_INCLUDED_FILE -extern void juce_initialiseThreadEvents(); - //============================================================================== void Logger::outputDebugString (const String& text) @@ -115,8 +113,6 @@ const String SystemStats::getCpuVendor() //============================================================================== void SystemStats::initialiseStats() { - juce_initialiseThreadEvents(); - cpuFlags.hasMMX = IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE) != 0; cpuFlags.hasSSE = IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0; cpuFlags.hasSSE2 = IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0; diff --git a/src/native/windows/juce_win32_Threads.cpp b/src/native/windows/juce_win32_Threads.cpp index 65db86bf61..3d1f11fdf1 100644 --- a/src/native/windows/juce_win32_Threads.cpp +++ b/src/native/windows/juce_win32_Threads.cpp @@ -118,10 +118,10 @@ void JUCE_API juce_threadEntryPoint (void*); static unsigned int __stdcall threadEntryProc (void* userData) { -#if ! JUCE_ONLY_BUILD_CORE_LIBRARY + #if ! JUCE_ONLY_BUILD_CORE_LIBRARY AttachThreadInput (GetWindowThreadProcessId (juce_messageWindowHandle, 0), GetCurrentThreadId(), TRUE); -#endif + #endif juce_threadEntryPoint (userData); @@ -129,31 +129,34 @@ static unsigned int __stdcall threadEntryProc (void* userData) return 0; } -void juce_CloseThreadHandle (void* handle) +void Thread::launchThread() { - CloseHandle ((HANDLE) handle); + unsigned int newThreadId; + threadHandle_ = (void*) _beginthreadex (0, 0, &threadEntryProc, this, 0, &newThreadId); + threadId_ = (ThreadID) newThreadId; } -void* juce_createThread (void* userData) +void Thread::closeThreadHandle() { - unsigned int threadId; - return (void*) _beginthreadex (0, 0, &threadEntryProc, userData, 0, &threadId); + CloseHandle ((HANDLE) threadHandle_); + threadId_ = 0; + threadHandle_ = 0; } -void juce_killThread (void* handle) +void Thread::killThread() { - if (handle != 0) + if (threadHandle_ != 0) { -#if JUCE_DEBUG + #if JUCE_DEBUG OutputDebugString (_T("** Warning - Forced thread termination **\n")); -#endif - TerminateThread (handle, 0); + #endif + TerminateThread (threadHandle_, 0); } } -void juce_setCurrentThreadName (const String& name) +void Thread::setCurrentThreadName (const String& name) { -#if JUCE_DEBUG && JUCE_MSVC + #if JUCE_DEBUG && JUCE_MSVC struct { DWORD dwType; @@ -173,9 +176,9 @@ void juce_setCurrentThreadName (const String& name) } __except (EXCEPTION_CONTINUE_EXECUTION) {} -#else + #else (void) name; -#endif + #endif } Thread::ThreadID Thread::getCurrentThreadId() @@ -183,8 +186,7 @@ Thread::ThreadID Thread::getCurrentThreadId() return (ThreadID) (pointer_sized_int) GetCurrentThreadId(); } -// priority 1 to 10 where 5=normal, 1=low -bool juce_setThreadPriority (void* threadHandle, int priority) +bool Thread::setThreadPriority (void* handle, int priority) { int pri = THREAD_PRIORITY_TIME_CRITICAL; @@ -195,10 +197,10 @@ bool juce_setThreadPriority (void* threadHandle, int priority) else if (priority < 9) pri = THREAD_PRIORITY_ABOVE_NORMAL; else if (priority < 10) pri = THREAD_PRIORITY_HIGHEST; - if (threadHandle == 0) - threadHandle = GetCurrentThread(); + if (handle == 0) + handle = GetCurrentThread(); - return SetThreadPriority (threadHandle, pri) != FALSE; + return SetThreadPriority (handle, pri) != FALSE; } void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) @@ -206,22 +208,23 @@ void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) SetThreadAffinityMask (GetCurrentThread(), affinityMask); } -static HANDLE sleepEvent = 0; - -void juce_initialiseThreadEvents() +//============================================================================== +struct SleepEvent { - if (sleepEvent == 0) -#if JUCE_DEBUG - sleepEvent = CreateEvent (0, 0, 0, _T("Juce Sleep Event")); -#else - sleepEvent = CreateEvent (0, 0, 0, 0); -#endif -} + SleepEvent() + : handle (CreateEvent (0, 0, 0, + #if JUCE_DEBUG + _T("Juce Sleep Event"))) + #else + 0)) + #endif + { + } -void Thread::yield() -{ - Sleep (0); -} + HANDLE handle; +}; + +static SleepEvent sleepEvent; void JUCE_CALLTYPE Thread::sleep (const int millisecs) { @@ -231,15 +234,18 @@ void JUCE_CALLTYPE Thread::sleep (const int millisecs) } else { - jassert (sleepEvent != 0); - // unlike Sleep() this is guaranteed to return to the current thread after // the time expires, so we'll use this for short waits, which are more likely // to need to be accurate - WaitForSingleObject (sleepEvent, millisecs); + WaitForSingleObject (sleepEvent.handle, millisecs); } } +void Thread::yield() +{ + Sleep (0); +} + //============================================================================== static int lastProcessPriority = -1; diff --git a/src/threads/juce_Thread.cpp b/src/threads/juce_Thread.cpp index 57fbe7173b..33ff5ed1b8 100644 --- a/src/threads/juce_Thread.cpp +++ b/src/threads/juce_Thread.cpp @@ -32,60 +32,119 @@ BEGIN_JUCE_NAMESPACE #include "../core/juce_Time.h" -// these functions are implemented in the platform-specific code. -void* juce_createThread (void* userData); -void juce_killThread (void* handle); -bool juce_setThreadPriority (void* handle, int priority); -void juce_setCurrentThreadName (const String& name); -#if JUCE_WINDOWS -void juce_CloseThreadHandle (void* handle); -#endif +//============================================================================== +class RunningThreadsList +{ +public: + RunningThreadsList() + { + } + + void add (Thread* const thread) + { + const ScopedLock sl (lock); + jassert (! threads.contains (thread)); + threads.add (thread); + } + + void remove (Thread* const thread) + { + const ScopedLock sl (lock); + jassert (threads.contains (thread)); + threads.removeValue (thread); + } + + int size() const throw() + { + return threads.size(); + } + + Thread* getThreadWithID (const Thread::ThreadID targetID) const throw() + { + const ScopedLock sl (lock); + + for (int i = threads.size(); --i >= 0;) + { + Thread* const t = threads.getUnchecked(i); + + if (t->getThreadId() == targetID) + return t; + } + + return 0; + } + + void stopAll (const int timeOutMilliseconds) + { + signalAllThreadsToStop(); + + for (;;) + { + Thread* firstThread = getFirstThread(); + + if (firstThread != 0) + firstThread->stopThread (timeOutMilliseconds); + else + break; + } + } + + static RunningThreadsList& getInstance() + { + static RunningThreadsList runningThreads; + return runningThreads; + } + +private: + Array threads; + CriticalSection lock; + + void signalAllThreadsToStop() + { + const ScopedLock sl (lock); + + for (int i = threads.size(); --i >= 0;) + threads.getUnchecked(i)->signalThreadShouldExit(); + } + + Thread* getFirstThread() const + { + const ScopedLock sl (lock); + return threads.getFirst(); + } +}; //============================================================================== -void Thread::threadEntryPoint (Thread* const thread) +void Thread::threadEntryPoint() { - { - const ScopedLock sl (runningThreadsLock); - runningThreads.add (thread); - } + RunningThreadsList::getInstance().add (this); JUCE_TRY { - thread->threadId_ = Thread::getCurrentThreadId(); + jassert (getCurrentThreadId() == threadId_); - if (thread->threadName_.isNotEmpty()) - juce_setCurrentThreadName (thread->threadName_); + if (threadName_.isNotEmpty()) + setCurrentThreadName (threadName_); - if (thread->startSuspensionEvent_.wait (10000)) + if (startSuspensionEvent_.wait (10000)) { - if (thread->affinityMask_ != 0) - setCurrentThreadAffinityMask (thread->affinityMask_); + if (affinityMask_ != 0) + setCurrentThreadAffinityMask (affinityMask_); - thread->run(); + run(); } } JUCE_CATCH_ALL_ASSERT - { - const ScopedLock sl (runningThreadsLock); - - jassert (runningThreads.contains (thread)); - runningThreads.removeValue (thread); - } - -#if JUCE_WINDOWS - juce_CloseThreadHandle (thread->threadHandle_); -#endif - - thread->threadHandle_ = 0; - thread->threadId_ = 0; + RunningThreadsList::getInstance().remove (this); + closeThreadHandle(); } // used to wrap the incoming call from the platform-specific code void JUCE_API juce_threadEntryPoint (void* userData) { - Thread::threadEntryPoint (static_cast (userData)); + static_cast (userData)->threadEntryPoint(); } @@ -93,8 +152,8 @@ void JUCE_API juce_threadEntryPoint (void* userData) Thread::Thread (const String& threadName) : threadName_ (threadName), threadHandle_ (0), - threadPriority_ (5), threadId_ (0), + threadPriority_ (5), affinityMask_ (0), threadShouldExit_ (false) { @@ -103,8 +162,8 @@ Thread::Thread (const String& threadName) Thread::~Thread() { /* If your thread class's destructor has been called without first stopping the thread, that - means that this partially destructed object is still performing some work - and that's not - unlikely to be a safe approach to take! + means that this partially destructed object is still performing some work - and that's + probably a Bad Thing! To avoid this type of nastiness, always make sure you call stopThread() before or during your subclass's destructor. @@ -123,8 +182,8 @@ void Thread::startThread() if (threadHandle_ == 0) { - threadHandle_ = juce_createThread (this); - juce_setThreadPriority (threadHandle_, threadPriority_); + launchThread(); + setThreadPriority (threadHandle_, threadPriority_); startSuspensionEvent_.signal(); } } @@ -192,18 +251,16 @@ void Thread::stopThread (const int timeOutMilliseconds) if (isThreadRunning()) { - // very bad karma if this point is reached, as - // there are bound to be locks and events left in - // silly states when a thread is killed by force.. + // very bad karma if this point is reached, as there are bound to be + // locks and events left in silly states when a thread is killed by force.. jassertfalse; Logger::writeToLog ("!! killing thread by force !!"); - juce_killThread (threadHandle_); + killThread(); + + RunningThreadsList::getInstance().remove (this); threadHandle_ = 0; threadId_ = 0; - - const ScopedLock sl2 (runningThreadsLock); - runningThreads.removeValue (this); } } } @@ -213,17 +270,18 @@ bool Thread::setPriority (const int priority) { const ScopedLock sl (startStopLock); - const bool worked = juce_setThreadPriority (threadHandle_, priority); - - if (worked) + if (setThreadPriority (threadHandle_, priority)) + { threadPriority_ = priority; + return true; + } - return worked; + return false; } bool Thread::setCurrentThreadPriority (const int priority) { - return juce_setThreadPriority (0, priority); + return setThreadPriority (0, priority); } void Thread::setAffinityMask (const uint32 affinityMask) @@ -245,53 +303,18 @@ void Thread::notify() const //============================================================================== int Thread::getNumRunningThreads() { - return runningThreads.size(); + return RunningThreadsList::getInstance().size(); } Thread* Thread::getCurrentThread() { - const ThreadID thisId = getCurrentThreadId(); - - const ScopedLock sl (runningThreadsLock); - - for (int i = runningThreads.size(); --i >= 0;) - { - Thread* const t = runningThreads.getUnchecked(i); - - if (t->threadId_ == thisId) - return t; - } - - return 0; + return RunningThreadsList::getInstance().getThreadWithID (getCurrentThreadId()); } void Thread::stopAllThreads (const int timeOutMilliseconds) { - { - const ScopedLock sl (runningThreadsLock); - - for (int i = runningThreads.size(); --i >= 0;) - runningThreads.getUnchecked(i)->signalThreadShouldExit(); - } - - for (;;) - { - Thread* firstThread; - - { - const ScopedLock sl (runningThreadsLock); - firstThread = runningThreads.getFirst(); - } - - if (firstThread == 0) - break; - - firstThread->stopThread (timeOutMilliseconds); - } + RunningThreadsList::getInstance().stopAll (timeOutMilliseconds); } -Array Thread::runningThreads; -CriticalSection Thread::runningThreadsLock; - END_JUCE_NAMESPACE diff --git a/src/threads/juce_Thread.h b/src/threads/juce_Thread.h index 27410c5319..35d3ddcb67 100644 --- a/src/threads/juce_Thread.h +++ b/src/threads/juce_Thread.h @@ -276,18 +276,22 @@ private: //============================================================================== const String threadName_; void* volatile threadHandle_; + ThreadID threadId_; CriticalSection startStopLock; WaitableEvent startSuspensionEvent_, defaultEvent_; - int threadPriority_; - ThreadID threadId_; uint32 affinityMask_; bool volatile threadShouldExit_; + friend class MessageManager; friend void JUCE_API juce_threadEntryPoint (void*); - static void threadEntryPoint (Thread* thread); - static Array runningThreads; - static CriticalSection runningThreadsLock; + + void launchThread(); + void closeThreadHandle(); + void killThread(); + void threadEntryPoint(); + static void setCurrentThreadName (const String& name); + static bool setThreadPriority (void* handle, int priority); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Thread); };