| @@ -150,8 +150,6 @@ | |||
| #include "../src/threads/juce_Thread.cpp" | |||
| #include "../src/threads/juce_ThreadPool.cpp" | |||
| #include "../src/threads/juce_TimeSliceThread.cpp" | |||
| #include "../src/utilities/juce_DeletedAtShutdown.cpp" | |||
| #include "../src/utilities/juce_UnitTest.cpp" | |||
| #endif | |||
| #if JUCE_BUILD_MISC | |||
| @@ -166,6 +164,8 @@ | |||
| #include "../src/utilities/juce_FileBasedDocument.cpp" | |||
| #include "../src/utilities/juce_RecentlyOpenedFilesList.cpp" | |||
| #include "../src/utilities/juce_UndoManager.cpp" | |||
| #include "../src/utilities/juce_UnitTest.cpp" | |||
| #include "../src/utilities/juce_DeletedAtShutdown.cpp" | |||
| #include "../src/audio/audio_file_formats/juce_AiffAudioFormat.cpp" | |||
| #include "../src/audio/audio_file_formats/juce_AudioFormat.cpp" | |||
| #include "../src/audio/audio_file_formats/juce_AudioFormatReader.cpp" | |||
| @@ -209,11 +209,13 @@ private: | |||
| for (int i = 0; i < files.size(); ++i) | |||
| out << " ../" << escapeSpaces (files.getReference(i).toUnixStyle()) << "\\" << newLine; | |||
| String cFlags ("-fsigned-char"); | |||
| out << newLine | |||
| << "ifeq ($(CONFIG),Debug)" << newLine | |||
| << " LOCAL_CFLAGS +=" << createPreprocessorDefs (true) << newLine | |||
| << " LOCAL_CFLAGS += -g " << cFlags << createPreprocessorDefs (true) << newLine | |||
| << "else" << newLine | |||
| << " LOCAL_CFLAGS +=" << createPreprocessorDefs (false) << newLine | |||
| << " LOCAL_CFLAGS += " << cFlags << createPreprocessorDefs (false) << newLine | |||
| << "endif" << newLine | |||
| << newLine | |||
| << "include $(BUILD_SHARED_LIBRARY)" << newLine; | |||
| @@ -2245,6 +2245,10 @@ private: | |||
| #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 | |||
| #endif | |||
| #elif JUCE_ANDROID | |||
| #define JUCE_ATOMICS_ANDROID 1 // Android atomic functions | |||
| #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 | |||
| #elif JUCE_GCC | |||
| #define JUCE_ATOMICS_GCC 1 // GCC with intrinsics | |||
| @@ -2306,8 +2310,8 @@ inline Type Atomic<Type>::get() const throw() | |||
| #elif JUCE_ATOMICS_WINDOWS | |||
| return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchangeAdd ((volatile long*) &value, (long) 0)) | |||
| : castFrom64Bit ((int64) juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0)); | |||
| #elif JUCE_ANDROID | |||
| return castFrom32Bit (__atomic_cmpxchg (castTo32Bit (value), castTo32Bit (value), (volatile int*) &value)); | |||
| #elif JUCE_ATOMICS_ANDROID | |||
| return value; | |||
| #elif JUCE_ATOMICS_GCC | |||
| return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0)) | |||
| : castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0)); | |||
| @@ -2317,7 +2321,7 @@ inline Type Atomic<Type>::get() const throw() | |||
| template <typename Type> | |||
| inline Type Atomic<Type>::exchange (const Type newValue) throw() | |||
| { | |||
| #if JUCE_ANDROID | |||
| #if JUCE_ATOMICS_ANDROID | |||
| return castFrom32Bit (__atomic_swap (castTo32Bit (newValue), (volatile int*) &value)); | |||
| #elif JUCE_ATOMICS_MAC || JUCE_ATOMICS_GCC | |||
| Type currentVal = value; | |||
| @@ -2338,7 +2342,7 @@ inline Type Atomic<Type>::operator+= (const Type amountToAdd) throw() | |||
| #elif JUCE_ATOMICS_WINDOWS | |||
| return sizeof (Type) == 4 ? (Type) (juce_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd) | |||
| : (Type) (juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd); | |||
| #elif JUCE_ANDROID | |||
| #elif JUCE_ATOMICS_ANDROID | |||
| for (;;) | |||
| { | |||
| const Type oldValue (value); | |||
| @@ -2366,7 +2370,7 @@ inline Type Atomic<Type>::operator++() throw() | |||
| #elif JUCE_ATOMICS_WINDOWS | |||
| return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value) | |||
| : (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value); | |||
| #elif JUCE_ANDROID | |||
| #elif JUCE_ATOMICS_ANDROID | |||
| return (Type) __atomic_inc ((volatile int*) &value); | |||
| #elif JUCE_ATOMICS_GCC | |||
| return (Type) __sync_add_and_fetch (&value, 1); | |||
| @@ -2382,7 +2386,7 @@ inline Type Atomic<Type>::operator--() throw() | |||
| #elif JUCE_ATOMICS_WINDOWS | |||
| return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value) | |||
| : (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value); | |||
| #elif JUCE_ANDROID | |||
| #elif JUCE_ATOMICS_ANDROID | |||
| return (Type) __atomic_dec ((volatile int*) &value); | |||
| #elif JUCE_ATOMICS_GCC | |||
| return (Type) __sync_add_and_fetch (&value, -1); | |||
| @@ -2395,8 +2399,10 @@ inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type val | |||
| #if JUCE_ATOMICS_MAC | |||
| return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) | |||
| : OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); | |||
| #elif JUCE_ATOMICS_WINDOWS || JUCE_ANDROID | |||
| #elif JUCE_ATOMICS_WINDOWS | |||
| return compareAndSetValue (newValue, valueToCompare) == valueToCompare; | |||
| #elif JUCE_ATOMICS_ANDROID | |||
| return __atomic_cmpxchg (castTo32Bit (valueToCompare), castTo32Bit (newValue), (volatile int*) &value) == 0; | |||
| #elif JUCE_ATOMICS_GCC | |||
| return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)) | |||
| : __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)); | |||
| @@ -2406,8 +2412,8 @@ inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type val | |||
| template <typename Type> | |||
| inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type valueToCompare) throw() | |||
| { | |||
| #if JUCE_ATOMICS_MAC | |||
| for (;;) // Annoying workaround for OSX only having a bool CAS operation.. | |||
| #if JUCE_ATOMICS_MAC || JUCE_ATOMICS_ANDROID | |||
| for (;;) // Annoying workaround for only having a bool CAS operation.. | |||
| { | |||
| if (compareAndSetBool (newValue, valueToCompare)) | |||
| return valueToCompare; | |||
| @@ -2420,8 +2426,6 @@ inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type va | |||
| #elif JUCE_ATOMICS_WINDOWS | |||
| return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare))) | |||
| : castFrom64Bit ((int64) juce_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare))); | |||
| #elif JUCE_ANDROID | |||
| return castFrom32Bit (__atomic_cmpxchg (castTo32Bit (valueToCompare), castTo32Bit (newValue), (volatile int*) &value)); | |||
| #elif JUCE_ATOMICS_GCC | |||
| return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))) | |||
| : castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue))); | |||
| @@ -2638,11 +2642,11 @@ public: | |||
| for (;;) | |||
| { | |||
| const int n = *d++; | |||
| const uint32 n = (uint32) (uint8) *d++; | |||
| if ((n & 0x80) != 0) | |||
| { | |||
| int bit = 0x40; | |||
| uint32 bit = 0x40; | |||
| while ((n & bit) != 0) | |||
| { | |||
| @@ -211,6 +211,7 @@ void JUCEApplication::appWillTerminateByForce() | |||
| } | |||
| //============================================================================== | |||
| #if ! JUCE_ANDROID | |||
| int JUCEApplication::main (const String& commandLine) | |||
| { | |||
| ScopedJuceInitialiser_GUI libraryInitialiser; | |||
| @@ -263,5 +264,6 @@ int JUCEApplication::main (int argc, const char* argv[]) | |||
| return JUCEApplication::main (cmd); | |||
| #endif | |||
| } | |||
| #endif | |||
| END_JUCE_NAMESPACE | |||
| @@ -539,7 +539,7 @@ public: | |||
| { | |||
| FSRef fn; | |||
| if (FSPathMakeRef ((UInt8*) filename.toUTF8(), &fn, 0) == noErr) | |||
| if (FSPathMakeRef ((UInt8*) filename.toUTF8().getAddress(), &fn, 0) == noErr) | |||
| { | |||
| resFileId = FSOpenResFile (&fn, fsRdPerm); | |||
| @@ -188,18 +188,28 @@ public: | |||
| expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211); | |||
| expect (ByteOrder::swap ((uint64) literal64bit (0x1122334455667788)) == literal64bit (0x8877665544332211)); | |||
| beginTest ("Atomic types"); | |||
| beginTest ("Atomic int"); | |||
| AtomicTester <int>::testInteger (*this); | |||
| beginTest ("Atomic unsigned int"); | |||
| AtomicTester <unsigned int>::testInteger (*this); | |||
| beginTest ("Atomic int32"); | |||
| AtomicTester <int32>::testInteger (*this); | |||
| beginTest ("Atomic uint32"); | |||
| AtomicTester <uint32>::testInteger (*this); | |||
| beginTest ("Atomic long"); | |||
| AtomicTester <long>::testInteger (*this); | |||
| beginTest ("Atomic void*"); | |||
| AtomicTester <void*>::testInteger (*this); | |||
| beginTest ("Atomic int*"); | |||
| AtomicTester <int*>::testInteger (*this); | |||
| beginTest ("Atomic float"); | |||
| AtomicTester <float>::testFloat (*this); | |||
| #if ! JUCE_64BIT_ATOMICS_UNAVAILABLE // 64-bit intrinsics aren't available on some old platforms | |||
| beginTest ("Atomic int64"); | |||
| AtomicTester <int64>::testInteger (*this); | |||
| beginTest ("Atomic uint64"); | |||
| AtomicTester <uint64>::testInteger (*this); | |||
| beginTest ("Atomic double"); | |||
| AtomicTester <double>::testFloat (*this); | |||
| #endif | |||
| } | |||
| @@ -214,10 +224,15 @@ public: | |||
| { | |||
| Atomic<Type> a, b; | |||
| a.set ((Type) 10); | |||
| test.expect (a.value == (Type) 10); | |||
| test.expect (a.get() == (Type) 10); | |||
| a += (Type) 15; | |||
| test.expect (a.get() == (Type) 25); | |||
| a.memoryBarrier(); | |||
| a -= (Type) 5; | |||
| test.expect (a.get() == (Type) 20); | |||
| ++a; ++a; --a; | |||
| test.expect (a.get() == (Type) 21); | |||
| a.memoryBarrier(); | |||
| testFloat (test); | |||
| @@ -111,9 +111,7 @@ public: | |||
| int randomInt = Random::getSystemRandom().nextInt(); | |||
| int64 randomInt64 = Random::getSystemRandom().nextInt64(); | |||
| double randomDouble = Random::getSystemRandom().nextDouble(); | |||
| String randomString; | |||
| for (int i = 50; --i >= 0;) | |||
| randomString << (juce_wchar) (Random::getSystemRandom().nextInt() & 0xffff); | |||
| String randomString (createRandomWideCharString()); | |||
| MemoryOutputStream mo; | |||
| mo.writeInt (randomInt); | |||
| @@ -129,12 +127,34 @@ public: | |||
| expect (mi.readInt() == randomInt); | |||
| expect (mi.readIntBigEndian() == randomInt); | |||
| expect (mi.readCompressedInt() == randomInt); | |||
| expect (mi.readString() == randomString); | |||
| expectEquals (mi.readString(), randomString); | |||
| expect (mi.readInt64() == randomInt64); | |||
| expect (mi.readInt64BigEndian() == randomInt64); | |||
| expect (mi.readDouble() == randomDouble); | |||
| expect (mi.readDoubleBigEndian() == randomDouble); | |||
| } | |||
| static const String createRandomWideCharString() | |||
| { | |||
| juce_wchar buffer [50]; | |||
| zerostruct (buffer); | |||
| for (int i = 0; i < numElementsInArray (buffer) - 1; ++i) | |||
| { | |||
| if (Random::getSystemRandom().nextBool()) | |||
| { | |||
| do | |||
| { | |||
| buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0x10ffff - 1)); | |||
| } | |||
| while (! CharPointer_UTF16::canRepresent (buffer[i])); | |||
| } | |||
| else | |||
| buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0xff)); | |||
| } | |||
| return buffer; | |||
| } | |||
| }; | |||
| static MemoryStreamTests memoryInputStreamUnitTests; | |||
| @@ -180,6 +180,11 @@ private: | |||
| #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 | |||
| #endif | |||
| //============================================================================== | |||
| #elif JUCE_ANDROID | |||
| #define JUCE_ATOMICS_ANDROID 1 // Android atomic functions | |||
| #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 | |||
| //============================================================================== | |||
| #elif JUCE_GCC | |||
| #define JUCE_ATOMICS_GCC 1 // GCC with intrinsics | |||
| @@ -244,8 +249,8 @@ inline Type Atomic<Type>::get() const throw() | |||
| #elif JUCE_ATOMICS_WINDOWS | |||
| return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchangeAdd ((volatile long*) &value, (long) 0)) | |||
| : castFrom64Bit ((int64) juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0)); | |||
| #elif JUCE_ANDROID | |||
| return castFrom32Bit (__atomic_cmpxchg (castTo32Bit (value), castTo32Bit (value), (volatile int*) &value)); | |||
| #elif JUCE_ATOMICS_ANDROID | |||
| return value; | |||
| #elif JUCE_ATOMICS_GCC | |||
| return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0)) | |||
| : castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0)); | |||
| @@ -255,7 +260,7 @@ inline Type Atomic<Type>::get() const throw() | |||
| template <typename Type> | |||
| inline Type Atomic<Type>::exchange (const Type newValue) throw() | |||
| { | |||
| #if JUCE_ANDROID | |||
| #if JUCE_ATOMICS_ANDROID | |||
| return castFrom32Bit (__atomic_swap (castTo32Bit (newValue), (volatile int*) &value)); | |||
| #elif JUCE_ATOMICS_MAC || JUCE_ATOMICS_GCC | |||
| Type currentVal = value; | |||
| @@ -276,7 +281,7 @@ inline Type Atomic<Type>::operator+= (const Type amountToAdd) throw() | |||
| #elif JUCE_ATOMICS_WINDOWS | |||
| return sizeof (Type) == 4 ? (Type) (juce_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd) | |||
| : (Type) (juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd); | |||
| #elif JUCE_ANDROID | |||
| #elif JUCE_ATOMICS_ANDROID | |||
| for (;;) | |||
| { | |||
| const Type oldValue (value); | |||
| @@ -304,7 +309,7 @@ inline Type Atomic<Type>::operator++() throw() | |||
| #elif JUCE_ATOMICS_WINDOWS | |||
| return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value) | |||
| : (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value); | |||
| #elif JUCE_ANDROID | |||
| #elif JUCE_ATOMICS_ANDROID | |||
| return (Type) __atomic_inc ((volatile int*) &value); | |||
| #elif JUCE_ATOMICS_GCC | |||
| return (Type) __sync_add_and_fetch (&value, 1); | |||
| @@ -320,7 +325,7 @@ inline Type Atomic<Type>::operator--() throw() | |||
| #elif JUCE_ATOMICS_WINDOWS | |||
| return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value) | |||
| : (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value); | |||
| #elif JUCE_ANDROID | |||
| #elif JUCE_ATOMICS_ANDROID | |||
| return (Type) __atomic_dec ((volatile int*) &value); | |||
| #elif JUCE_ATOMICS_GCC | |||
| return (Type) __sync_add_and_fetch (&value, -1); | |||
| @@ -333,8 +338,10 @@ inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type val | |||
| #if JUCE_ATOMICS_MAC | |||
| return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) | |||
| : OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); | |||
| #elif JUCE_ATOMICS_WINDOWS || JUCE_ANDROID | |||
| #elif JUCE_ATOMICS_WINDOWS | |||
| return compareAndSetValue (newValue, valueToCompare) == valueToCompare; | |||
| #elif JUCE_ATOMICS_ANDROID | |||
| return __atomic_cmpxchg (castTo32Bit (valueToCompare), castTo32Bit (newValue), (volatile int*) &value) == 0; | |||
| #elif JUCE_ATOMICS_GCC | |||
| return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)) | |||
| : __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)); | |||
| @@ -344,8 +351,8 @@ inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type val | |||
| template <typename Type> | |||
| inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type valueToCompare) throw() | |||
| { | |||
| #if JUCE_ATOMICS_MAC | |||
| for (;;) // Annoying workaround for OSX only having a bool CAS operation.. | |||
| #if JUCE_ATOMICS_MAC || JUCE_ATOMICS_ANDROID | |||
| for (;;) // Annoying workaround for only having a bool CAS operation.. | |||
| { | |||
| if (compareAndSetBool (newValue, valueToCompare)) | |||
| return valueToCompare; | |||
| @@ -358,8 +365,6 @@ inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type va | |||
| #elif JUCE_ATOMICS_WINDOWS | |||
| return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare))) | |||
| : castFrom64Bit ((int64) juce_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare))); | |||
| #elif JUCE_ANDROID | |||
| return castFrom32Bit (__atomic_cmpxchg (castTo32Bit (valueToCompare), castTo32Bit (newValue), (volatile int*) &value)); | |||
| #elif JUCE_ATOMICS_GCC | |||
| return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))) | |||
| : castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue))); | |||
| @@ -0,0 +1,94 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-10 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| package com.juce; | |||
| import android.content.Context; | |||
| import android.view.*; | |||
| import android.graphics.*; | |||
| //============================================================================== | |||
| public class ComponentPeerView extends View | |||
| { | |||
| public ComponentPeerView (Context context) | |||
| { | |||
| super (context); | |||
| } | |||
| //============================================================================== | |||
| private native void handlePaint (Canvas canvas); | |||
| @Override | |||
| public void draw (Canvas canvas) | |||
| { | |||
| handlePaint (canvas); | |||
| } | |||
| //============================================================================== | |||
| private native void handleMouseDown (float x, float y, long time); | |||
| private native void handleMouseDrag (float x, float y, long time); | |||
| private native void handleMouseUp (float x, float y, long time); | |||
| @Override | |||
| public boolean onTouchEvent (MotionEvent event) | |||
| { | |||
| System.out.println (event.toString()); | |||
| switch (event.getAction()) | |||
| { | |||
| case MotionEvent.ACTION_DOWN: handleMouseDown (event.getX(), event.getY(), event.getEventTime()); return true; | |||
| case MotionEvent.ACTION_MOVE: handleMouseDrag (event.getX(), event.getY(), event.getEventTime()); return true; | |||
| case MotionEvent.ACTION_CANCEL: | |||
| case MotionEvent.ACTION_UP: handleMouseUp (event.getX(), event.getY(), event.getEventTime()); return true; | |||
| default: break; | |||
| } | |||
| return false; | |||
| } | |||
| //============================================================================== | |||
| @Override | |||
| protected void onSizeChanged (int w, int h, int oldw, int oldh) | |||
| { | |||
| } | |||
| @Override | |||
| protected void onLayout (boolean changed, int left, int top, int right, int bottom) | |||
| { | |||
| } | |||
| public void setViewName (String newName) | |||
| { | |||
| } | |||
| public boolean isVisible() | |||
| { | |||
| return true; | |||
| } | |||
| public void setVisible (boolean b) | |||
| { | |||
| } | |||
| } | |||
| @@ -0,0 +1,131 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-10 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| package com.juce; | |||
| import android.app.Activity; | |||
| import android.os.Bundle; | |||
| import android.content.*; | |||
| import android.view.*; | |||
| import com.juce.ComponentPeerView; | |||
| //============================================================================== | |||
| public class JuceAppActivity extends Activity | |||
| { | |||
| //============================================================================== | |||
| static | |||
| { | |||
| System.loadLibrary ("juce_jni"); | |||
| } | |||
| @Override | |||
| public void onCreate (Bundle savedInstanceState) | |||
| { | |||
| super.onCreate (savedInstanceState); | |||
| messageHandler = new android.os.Handler(); | |||
| viewHolder = new ViewHolder (this); | |||
| setContentView (viewHolder); | |||
| WindowManager wm = (WindowManager) getSystemService (WINDOW_SERVICE); | |||
| Display display = wm.getDefaultDisplay(); | |||
| launchApp (getApplicationInfo().publicSourceDir, | |||
| getApplicationInfo().dataDir, | |||
| display.getWidth(), display.getHeight()); | |||
| } | |||
| @Override | |||
| protected void onDestroy() | |||
| { | |||
| quitApp(); | |||
| super.onDestroy(); | |||
| } | |||
| //============================================================================== | |||
| public native void launchApp (String appFile, String appDataDir, | |||
| int screenWidth, int screenHeight); | |||
| public native void quitApp(); | |||
| //============================================================================== | |||
| public static void printToConsole (String s) | |||
| { | |||
| System.out.println (s); | |||
| } | |||
| //============================================================================== | |||
| public native void deliverMessage (long value); | |||
| private android.os.Handler messageHandler; | |||
| public void postMessage (long value) | |||
| { | |||
| messageHandler.post (new MessageCallback (this, value)); | |||
| } | |||
| class MessageCallback implements java.lang.Runnable | |||
| { | |||
| public MessageCallback (JuceAppActivity app_, long value_) | |||
| { | |||
| app = app_; | |||
| value = value_; | |||
| } | |||
| public void run() | |||
| { | |||
| app.deliverMessage (value); | |||
| } | |||
| private JuceAppActivity app; | |||
| private long value; | |||
| } | |||
| //============================================================================== | |||
| private ViewHolder viewHolder; | |||
| public ComponentPeerView createNewView() | |||
| { | |||
| ComponentPeerView v = new ComponentPeerView (this); | |||
| viewHolder.addView (v); | |||
| return v; | |||
| } | |||
| public void deleteView (ComponentPeerView view) | |||
| { | |||
| viewHolder.removeView (view); | |||
| } | |||
| class ViewHolder extends ViewGroup | |||
| { | |||
| public ViewHolder (Context context) | |||
| { | |||
| super (context); | |||
| } | |||
| protected void onLayout (boolean changed, int left, int top, int right, int bottom) | |||
| { | |||
| } | |||
| } | |||
| } | |||
| @@ -108,73 +108,34 @@ const File File::getLinkedTarget() const | |||
| } | |||
| //============================================================================== | |||
| const char* juce_Argv0 = 0; // referenced from juce_Application.cpp | |||
| const File File::getSpecialLocation (const SpecialLocationType type) | |||
| { | |||
| // TODO | |||
| switch (type) | |||
| { | |||
| case userHomeDirectory: | |||
| { | |||
| const char* homeDir = getenv ("HOME"); | |||
| if (homeDir == 0) | |||
| { | |||
| struct passwd* const pw = getpwuid (getuid()); | |||
| if (pw != 0) | |||
| homeDir = pw->pw_dir; | |||
| } | |||
| return File (String::fromUTF8 (homeDir)); | |||
| } | |||
| case userDocumentsDirectory: | |||
| case userMusicDirectory: | |||
| case userMoviesDirectory: | |||
| case userApplicationDataDirectory: | |||
| return File ("~"); | |||
| return File (android.appDataDir); | |||
| case userDesktopDirectory: | |||
| return File ("~/Desktop"); | |||
| case commonApplicationDataDirectory: | |||
| return File ("/var"); | |||
| return File (android.appDataDir); | |||
| case globalApplicationsDirectory: | |||
| return File ("/usr"); | |||
| case tempDirectory: | |||
| { | |||
| File tmp ("/var/tmp"); | |||
| if (! tmp.isDirectory()) | |||
| { | |||
| tmp = "/tmp"; | |||
| if (! tmp.isDirectory()) | |||
| tmp = File::getCurrentWorkingDirectory(); | |||
| } | |||
| return tmp; | |||
| } | |||
| return File ("~/.temp"); | |||
| case invokedExecutableFile: | |||
| if (juce_Argv0 != 0) | |||
| return File (String::fromUTF8 (juce_Argv0)); | |||
| // deliberate fall-through... | |||
| case currentExecutableFile: | |||
| case currentApplicationFile: | |||
| return juce_getExecutableFile(); | |||
| case hostApplicationPath: | |||
| return juce_readlink ("/proc/self/exe", juce_getExecutableFile()); | |||
| return juce_getExecutableFile(); | |||
| default: | |||
| jassertfalse; // unknown type? | |||
| @@ -29,15 +29,13 @@ | |||
| //============================================================================== | |||
| // TODO | |||
| class AndroidLowLevelGraphicsContext : public LowLevelGraphicsContext | |||
| { | |||
| public: | |||
| AndroidLowLevelGraphicsContext (const GlobalRef& canvas_) | |||
| : canvas (canvas_), | |||
| currentState (new SavedState()), | |||
| currentState (new SavedState()) | |||
| { | |||
| paintStack.add (new GlobalRef()); | |||
| setFill (Colours::black); | |||
| } | |||
| @@ -55,7 +53,7 @@ public: | |||
| void addTransform (const AffineTransform& transform) | |||
| { | |||
| canvas.callVoidMethod (android.concat, createMatrix (canvas.getEnv(), transform)); | |||
| canvas.callVoidMethod (android.concat, createMatrix (getEnv(), transform).get()); | |||
| } | |||
| float getScaleFactor() | |||
| @@ -70,7 +68,7 @@ public: | |||
| bool clipToRectangleList (const RectangleList& clipRegion) | |||
| { | |||
| return canvas.callBooleanMethod (android.clipRegion, createRegion (canvas.getEnv(), clipRegion)); | |||
| return canvas.callBooleanMethod (android.clipRegion, createRegion (getEnv(), clipRegion).get()); | |||
| } | |||
| void excludeClipRectangle (const Rectangle<int>& r) | |||
| @@ -79,7 +77,7 @@ public: | |||
| void clipToPath (const Path& path, const AffineTransform& transform) | |||
| { | |||
| (void) canvas.callBooleanMethod (android.clipPath, createPath (canvas.getEnv(), path, transform)); | |||
| (void) canvas.callBooleanMethod (android.clipPath, createPath (getEnv(), path, transform).get()); | |||
| } | |||
| void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) | |||
| @@ -93,20 +91,21 @@ public: | |||
| const Rectangle<int> getClipBounds() const | |||
| { | |||
| jobject rect = canvas.callObjectMethod (android.getClipBounds2); | |||
| JNIEnv* env = getEnv(); | |||
| const LocalRef<jobject> rect (canvas.callObjectMethod (android.getClipBounds2)); | |||
| const int left = canvas.getEnv()->GetIntField (rect, android.rectLeft); | |||
| const int top = canvas.getEnv()->GetIntField (rect, android.rectTop); | |||
| const int right = canvas.getEnv()->GetIntField (rect, android.rectRight); | |||
| const int bottom = canvas.getEnv()->GetIntField (rect, android.rectBottom); | |||
| const int left = env->GetIntField (rect, android.rectLeft); | |||
| const int top = env->GetIntField (rect, android.rectTop); | |||
| const int right = env->GetIntField (rect, android.rectRight); | |||
| const int bottom = env->GetIntField (rect, android.rectBottom); | |||
| return Rectangle<int> (left, top, right - left, bottom - top); | |||
| } | |||
| bool isClipEmpty() const | |||
| { | |||
| return ! canvas.callBooleanMethod (android.getClipBounds, | |||
| canvas.getEnv()->NewObject (android.rectClass, android.rectConstructor, 0, 0, 0, 0)); | |||
| LocalRef<jobject> tempRect (getEnv()->NewObject (android.rectClass, android.rectConstructor, 0, 0, 0, 0)); | |||
| return ! canvas.callBooleanMethod (android.getClipBounds, tempRect.get()); | |||
| } | |||
| //============================================================================== | |||
| @@ -128,13 +127,13 @@ public: | |||
| { | |||
| canvas.callVoidMethod (android.drawRect, | |||
| (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom(), | |||
| getCurrentPaint().get()); | |||
| getCurrentPaint()); | |||
| } | |||
| void fillPath (const Path& path, const AffineTransform& transform) | |||
| { | |||
| canvas.callVoidMethod (android.drawPath, createPath (canvas.getEnv(), path, transform), | |||
| getCurrentPaint().get()); | |||
| canvas.callVoidMethod (android.drawPath, createPath (getEnv(), path, transform).get(), | |||
| getCurrentPaint()); | |||
| } | |||
| void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles) | |||
| @@ -145,17 +144,17 @@ public: | |||
| { | |||
| canvas.callVoidMethod (android.drawLine, line.getStartX(), line.getStartY(), | |||
| line.getEndX(), line.getEndY(), | |||
| getCurrentPaint().get()); | |||
| getCurrentPaint()); | |||
| } | |||
| void drawVerticalLine (int x, float top, float bottom) | |||
| { | |||
| canvas.callVoidMethod (android.drawRect, (float) x, top, x + 1.0f, bottom, getCurrentPaint().get()); | |||
| canvas.callVoidMethod (android.drawRect, (float) x, top, x + 1.0f, bottom, getCurrentPaint()); | |||
| } | |||
| void drawHorizontalLine (int y, float left, float right) | |||
| { | |||
| canvas.callVoidMethod (android.drawRect, left, (float) y, right, y + 1.0f, getCurrentPaint().get()); | |||
| canvas.callVoidMethod (android.drawRect, left, (float) y, right, y + 1.0f, getCurrentPaint()); | |||
| } | |||
| void setFont (const Font& newFont) | |||
| @@ -223,21 +222,26 @@ public: | |||
| fillType = newType; | |||
| } | |||
| jobject getPaint (JNIEnv* env) | |||
| jobject getPaint() | |||
| { | |||
| if (needsUpdate) | |||
| { | |||
| JNIEnv* env = getEnv(); | |||
| if (paint.get() == 0) | |||
| paint = GlobalRef (env, env->NewObject (android.paintClass, android.paintClassConstructor)); | |||
| { | |||
| paint = GlobalRef (env->NewObject (android.paintClass, android.paintClassConstructor)); | |||
| paint.callVoidMethod (android.setAntiAlias, true); | |||
| } | |||
| if (fillType.isColour()) | |||
| { | |||
| paint.callVoidMethod (android.setShader, (jobject) 0); | |||
| paint.callObjectMethod (android.setShader, (jobject) 0); | |||
| paint.callVoidMethod (android.setColor, colourToInt (fillType.colour)); | |||
| } | |||
| else if (fillType.isGradient()) | |||
| { | |||
| const ColourGradient& g = fillType.gradient; | |||
| const ColourGradient& g = *fillType.gradient; | |||
| const Point<float> p1 (g.point1); | |||
| const Point<float> p2 (g.point2); | |||
| @@ -251,7 +255,7 @@ public: | |||
| for (int i = 0; i < numColours; ++i) | |||
| { | |||
| colours[i] = g.getColour (i); | |||
| colours[i] = colourToInt (g.getColour (i)); | |||
| positions[i] = (float) g.getColourPosition(i); | |||
| } | |||
| @@ -259,7 +263,7 @@ public: | |||
| env->SetFloatArrayRegion (positionsArray, 0, numColours, positions.getData()); | |||
| } | |||
| jobject tileMode = xxxx | |||
| jobject tileMode = env->GetStaticObjectField (android.shaderTileModeClass, android.clampMode); | |||
| jobject shader; | |||
| if (fillType.gradient->isRadial) | |||
| @@ -269,7 +273,7 @@ public: | |||
| p1.getX(), p1.getY(), | |||
| p1.getDistanceFrom (p2), | |||
| coloursArray, positionsArray, | |||
| tileMode)); | |||
| tileMode); | |||
| } | |||
| else | |||
| { | |||
| @@ -277,14 +281,19 @@ public: | |||
| android.linearGradientConstructor, | |||
| p1.getX(), p1.getY(), p2.getX(), p2.getY(), | |||
| coloursArray, positionsArray, | |||
| tileMode)); | |||
| tileMode); | |||
| } | |||
| env->CallVoidMethod (shader, android.setLocalMatrix, createMatrix (fillType.transform)); | |||
| paint.callVoidMethod (android.setShader, shader); | |||
| env->DeleteLocalRef (coloursArray); | |||
| env->DeleteLocalRef (positionsArray); | |||
| env->CallVoidMethod (shader, android.setLocalMatrix, createMatrix (env, fillType.transform).get()); | |||
| paint.callObjectMethod (android.setShader, shader); | |||
| env->DeleteLocalRef (shader); | |||
| } | |||
| else | |||
| {x | |||
| { | |||
| } | |||
| } | |||
| @@ -304,9 +313,12 @@ private: | |||
| ScopedPointer <SavedState> currentState; | |||
| OwnedArray <SavedState> stateStack; | |||
| GlobalRef& getCurrentPaint() throw() { return *paintStack.getUnchecked (paintStack.size() - 1); } | |||
| jobject getCurrentPaint() const | |||
| { | |||
| return currentState->getPaint(); | |||
| } | |||
| static jobject createPath (JNIEnv* env, const Path& path) | |||
| static const LocalRef<jobject> createPath (JNIEnv* env, const Path& path) | |||
| { | |||
| jobject p = env->NewObject (android.pathClass, android.pathClassConstructor); | |||
| @@ -325,10 +337,10 @@ private: | |||
| } | |||
| } | |||
| return p; | |||
| return LocalRef<jobject> (p); | |||
| } | |||
| static jobject createPath (JNIEnv* env, const Path& path, const AffineTransform& transform) | |||
| static const LocalRef<jobject> createPath (JNIEnv* env, const Path& path, const AffineTransform& transform) | |||
| { | |||
| if (transform.isIdentity()) | |||
| return createPath (env, path); | |||
| @@ -338,7 +350,7 @@ private: | |||
| return createPath (env, tempPath); | |||
| } | |||
| static jobject createMatrix (JNIEnv* env, const AffineTransform& t) | |||
| static const LocalRef<jobject> createMatrix (JNIEnv* env, const AffineTransform& t) | |||
| { | |||
| jobject m = env->NewObject (android.matrixClass, android.matrixClassConstructor); | |||
| @@ -352,25 +364,25 @@ private: | |||
| env->CallVoidMethod (m, android.setValues, javaArray); | |||
| env->DeleteLocalRef (javaArray); | |||
| return m; | |||
| return LocalRef<jobject> (m); | |||
| } | |||
| static jobject createRect (JNIEnv* env, const Rectangle<int>& r) | |||
| static const LocalRef<jobject> createRect (JNIEnv* env, const Rectangle<int>& r) | |||
| { | |||
| return env->NewObject (android.rectClass, android.rectConstructor, | |||
| r.getX(), r.getY(), r.getRight(), r.getBottom()); | |||
| return LocalRef<jobject> (env->NewObject (android.rectClass, android.rectConstructor, | |||
| r.getX(), r.getY(), r.getRight(), r.getBottom())); | |||
| } | |||
| static jobject createRegion (JNIEnv* env, const RectangleList& list) | |||
| static const LocalRef<jobject> createRegion (JNIEnv* env, const RectangleList& list) | |||
| { | |||
| jobject region = env->NewObject (android.regionClass, android.regionConstructor); | |||
| const int numRects = list.getNumRectangles(); | |||
| for (int i = 0; i < numRects; ++i) | |||
| env->CallVoidMethod (region, android.regionUnion, createRect (env, list.getRectangle(i))); | |||
| env->CallVoidMethod (region, android.regionUnion, createRect (env, list.getRectangle(i)).get()); | |||
| return region; | |||
| return LocalRef<jobject> (region); | |||
| } | |||
| static int colourToInt (const Colour& col) throw() | |||
| @@ -61,7 +61,7 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages | |||
| //============================================================================== | |||
| bool juce_postMessageToSystemQueue (Message* message) | |||
| { | |||
| android.activity.callVoidMethod (android.postMessage, (jlong) (pointer_sized_uint) message); | |||
| getEnv()->CallVoidMethod (android.activity, android.postMessage, (jlong) (pointer_sized_uint) message); | |||
| return true; | |||
| } | |||
| @@ -32,9 +32,11 @@ extern JUCE_NAMESPACE::JUCEApplication* juce_CreateApplication(); // (from START | |||
| BEGIN_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| JUCE_JNI_CALLBACK (JuceAppActivity, launchApp, void, (JNIEnv* env, jobject activity, int screenWidth, int screenHeight)) | |||
| JUCE_JNI_CALLBACK (JuceAppActivity, launchApp, void, (JNIEnv* env, jobject activity, | |||
| jstring appFile, jstring appDataDir, | |||
| int screenWidth, int screenHeight)) | |||
| { | |||
| android.initialise (env, activity, screenWidth, screenHeight); | |||
| android.initialise (env, activity, appFile, appDataDir, screenWidth, screenHeight); | |||
| JUCEApplication::createInstance = &juce_CreateApplication; | |||
| @@ -60,8 +62,8 @@ void PlatformUtilities::beep() | |||
| //============================================================================== | |||
| void Logger::outputDebugString (const String& text) | |||
| { | |||
| android.env->CallStaticVoidMethod (android.activityClass, android.printToConsole, | |||
| android.javaString (text)); | |||
| getEnv()->CallStaticVoidMethod (android.activityClass, android.printToConsole, | |||
| javaString (text).get()); | |||
| } | |||
| //============================================================================== | |||
| @@ -107,11 +107,12 @@ BEGIN_JUCE_NAMESPACE | |||
| JAVACLASS (rectClass, "android/graphics/Rect") \ | |||
| JAVACLASS (regionClass, "android/graphics/Region") \ | |||
| JAVACLASS (shaderClass, "android/graphics/Shader") \ | |||
| JAVACLASS (shaderTileModeClass, "android/graphics/Shader$TileMode") \ | |||
| JAVACLASS (linearGradientClass, "android/graphics/LinearGradient") \ | |||
| JAVACLASS (radialGradientClass, "android/graphics/RadialGradient") \ | |||
| //============================================================================== | |||
| #define JUCE_JNI_METHODS(METHOD, STATICMETHOD, FIELD) \ | |||
| #define JUCE_JNI_METHODS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ | |||
| \ | |||
| STATICMETHOD (activityClass, printToConsole, "printToConsole", "(Ljava/lang/String;)V") \ | |||
| METHOD (activityClass, createNewView, "createNewView", "()Lcom/juce/ComponentPeerView;") \ | |||
| @@ -153,8 +154,10 @@ BEGIN_JUCE_NAMESPACE | |||
| METHOD (paintClass, paintClassConstructor, "<init>", "()V") \ | |||
| METHOD (paintClass, setColor, "setColor", "(I)V") \ | |||
| METHOD (paintClass, setShader, "setShader", "(Landroid/graphics/Shader;)Landroid/graphics/Shader;") \ | |||
| METHOD (paintClass, setAntiAlias, "setAntiAlias", "(Z)V") \ | |||
| \ | |||
| METHOD (shaderClass, setLocalMatrix, "setLocalMatrix", "(Landroid/graphics/Matrix;)V") \ | |||
| STATICFIELD (shaderTileModeClass, clampMode, "CLAMP", "Landroid/graphics/Shader$TileMode;") \ | |||
| \ | |||
| METHOD (pathClass, pathClassConstructor, "<init>", "()V") \ | |||
| METHOD (pathClass, moveTo, "moveTo", "(FF)V") \ | |||
| @@ -180,24 +183,116 @@ BEGIN_JUCE_NAMESPACE | |||
| METHOD (regionClass, regionUnion, "union", "(Landroid/graphics/Rect;)Z"); \ | |||
| //============================================================================== | |||
| class ThreadLocalJNIEnvHolder | |||
| { | |||
| public: | |||
| ThreadLocalJNIEnvHolder() | |||
| : jvm (0) | |||
| { | |||
| zeromem (threads, sizeof (threads)); | |||
| zeromem (envs, sizeof (envs)); | |||
| } | |||
| void initialise (JNIEnv* env) | |||
| { | |||
| env->GetJavaVM (&jvm); | |||
| addEnv (env); | |||
| } | |||
| void attach() | |||
| { | |||
| JNIEnv* env = 0; | |||
| jvm->AttachCurrentThread (&env, 0); | |||
| if (env != 0) | |||
| addEnv (env); | |||
| } | |||
| void detach() | |||
| { | |||
| jvm->DetachCurrentThread(); | |||
| const pthread_t thisThread = pthread_self(); | |||
| ScopedLock sl (addRemoveLock); | |||
| for (int i = 0; i < maxThreads; ++i) | |||
| if (threads[i] == thisThread) | |||
| threads[i] = 0; | |||
| } | |||
| JNIEnv* get() const throw() | |||
| { | |||
| const pthread_t thisThread = pthread_self(); | |||
| for (int i = 0; i < maxThreads; ++i) | |||
| if (threads[i] == thisThread) | |||
| return envs[i]; | |||
| return 0; | |||
| } | |||
| enum { maxThreads = 16 }; | |||
| private: | |||
| JavaVM* jvm; | |||
| pthread_t threads [maxThreads]; | |||
| JNIEnv* envs [maxThreads]; | |||
| CriticalSection addRemoveLock; | |||
| void addEnv (JNIEnv* env) | |||
| { | |||
| ScopedLock sl (addRemoveLock); | |||
| if (get() == 0) | |||
| { | |||
| const pthread_t thisThread = pthread_self(); | |||
| for (int i = 0; i < maxThreads; ++i) | |||
| { | |||
| if (threads[i] == 0) | |||
| { | |||
| envs[i] = env; | |||
| threads[i] = thisThread; | |||
| return; | |||
| } | |||
| } | |||
| } | |||
| jassertfalse; // too many threads! | |||
| } | |||
| }; | |||
| static ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder; | |||
| struct AndroidThreadScope | |||
| { | |||
| AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); } | |||
| ~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); } | |||
| }; | |||
| static inline JNIEnv* getEnv() throw() | |||
| { | |||
| return threadLocalJNIEnvHolder.get(); | |||
| } | |||
| //============================================================================== | |||
| class GlobalRef | |||
| { | |||
| public: | |||
| GlobalRef() | |||
| : env (0), obj (0) | |||
| inline GlobalRef() throw() | |||
| : obj (0) | |||
| { | |||
| } | |||
| GlobalRef (JNIEnv* const env_, jobject obj_) | |||
| : env (env_), | |||
| obj (retain (env_, obj_)) | |||
| inline explicit GlobalRef (jobject obj_) | |||
| : obj (retain (obj_)) | |||
| { | |||
| } | |||
| GlobalRef (const GlobalRef& other) | |||
| : env (other.env), | |||
| obj (retain (other.env, other.obj)) | |||
| inline GlobalRef (const GlobalRef& other) | |||
| : obj (retain (other.obj)) | |||
| { | |||
| } | |||
| @@ -206,28 +301,22 @@ public: | |||
| clear(); | |||
| } | |||
| void clear() | |||
| inline void clear() | |||
| { | |||
| if (env != 0) | |||
| { | |||
| env->DeleteGlobalRef (obj); | |||
| env = 0; | |||
| obj = 0; | |||
| } | |||
| if (obj != 0) | |||
| getEnv()->DeleteGlobalRef (obj); | |||
| } | |||
| GlobalRef& operator= (const GlobalRef& other) | |||
| inline GlobalRef& operator= (const GlobalRef& other) | |||
| { | |||
| clear(); | |||
| env = other.env; | |||
| obj = retain (env, other.obj); | |||
| obj = retain (other.obj); | |||
| return *this; | |||
| } | |||
| //============================================================================== | |||
| inline operator jobject() const throw() { return obj; } | |||
| inline jobject get() const throw() { return obj; } | |||
| inline JNIEnv* getEnv() const throw() { return env; } | |||
| //============================================================================== | |||
| #define DECLARE_CALL_TYPE_METHOD(returnType, typeName) \ | |||
| @@ -235,7 +324,7 @@ public: | |||
| { \ | |||
| va_list args; \ | |||
| va_start (args, methodID); \ | |||
| returnType result = env->Call##typeName##MethodV (obj, methodID, args); \ | |||
| returnType result = getEnv()->Call##typeName##MethodV (obj, methodID, args); \ | |||
| va_end (args); \ | |||
| return result; \ | |||
| } | |||
| @@ -255,33 +344,101 @@ public: | |||
| { | |||
| va_list args; | |||
| va_start (args, methodID); | |||
| env->CallVoidMethodV (obj, methodID, args); | |||
| getEnv()->CallVoidMethodV (obj, methodID, args); | |||
| va_end (args); | |||
| } | |||
| private: | |||
| //============================================================================== | |||
| JNIEnv* env; | |||
| jobject obj; | |||
| static jobject retain (JNIEnv* const env, jobject obj_) | |||
| static inline jobject retain (jobject obj_) | |||
| { | |||
| return env == 0 ? 0 : env->NewGlobalRef (obj_); | |||
| return obj_ == 0 ? 0 : getEnv()->NewGlobalRef (obj_); | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| template <typename JavaType> | |||
| class LocalRef | |||
| { | |||
| public: | |||
| explicit inline LocalRef (JavaType obj_) throw() | |||
| : obj (obj_) | |||
| { | |||
| } | |||
| inline LocalRef (const LocalRef& other) throw() | |||
| : obj (retain (other.obj)) | |||
| { | |||
| } | |||
| ~LocalRef() | |||
| { | |||
| if (obj != 0) | |||
| getEnv()->DeleteLocalRef (obj); | |||
| } | |||
| LocalRef& operator= (const LocalRef& other) | |||
| { | |||
| if (obj != other.obj) | |||
| { | |||
| if (obj != 0) | |||
| getEnv()->DeleteLocalRef (obj); | |||
| obj = retain (other.obj); | |||
| } | |||
| return *this; | |||
| } | |||
| inline operator JavaType() const throw() { return obj; } | |||
| inline JavaType get() const throw() { return obj; } | |||
| private: | |||
| JavaType obj; | |||
| static JavaType retain (JavaType obj_) | |||
| { | |||
| return obj_ == 0 ? 0 : (JavaType) getEnv()->NewLocalRef (obj_); | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| static const String juceString (jstring s) | |||
| { | |||
| JNIEnv* env = getEnv(); | |||
| jboolean isCopy; | |||
| const char* const utf8 = env->GetStringUTFChars (s, &isCopy); | |||
| CharPointer_UTF8 utf8CP (utf8); | |||
| const String result (utf8CP); | |||
| env->ReleaseStringUTFChars (s, utf8); | |||
| return result; | |||
| } | |||
| static const LocalRef<jstring> javaString (const String& s) | |||
| { | |||
| return LocalRef<jstring> (getEnv()->NewStringUTF (s.toUTF8())); | |||
| } | |||
| //============================================================================== | |||
| class AndroidJavaCallbacks | |||
| { | |||
| public: | |||
| AndroidJavaCallbacks() : env (0), screenWidth (0), screenHeight (0) | |||
| AndroidJavaCallbacks() : screenWidth (0), screenHeight (0) | |||
| { | |||
| } | |||
| void initialise (JNIEnv* env_, jobject activity_, int screenWidth_, int screenHeight_) | |||
| void initialise (JNIEnv* env, jobject activity_, | |||
| jstring appFile_, jstring appDataDir_, | |||
| int screenWidth_, int screenHeight_) | |||
| { | |||
| env = env_; | |||
| activity = GlobalRef (env, activity_); | |||
| threadLocalJNIEnvHolder.initialise (env); | |||
| activity = GlobalRef (activity_); | |||
| appFile = juceString (appFile_); | |||
| appDataDir = juceString (appDataDir_); | |||
| screenWidth = screenWidth_; | |||
| screenHeight = screenHeight_; | |||
| @@ -300,12 +457,17 @@ public: | |||
| #define CREATE_JNI_FIELD(ownerClass, fieldID, stringName, signature) \ | |||
| fieldID = env->GetFieldID (ownerClass, stringName, signature); \ | |||
| jassert (fieldID != 0); | |||
| JUCE_JNI_METHODS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD); | |||
| #define CREATE_JNI_STATICFIELD(ownerClass, fieldID, stringName, signature) \ | |||
| fieldID = env->GetStaticFieldID (ownerClass, stringName, signature); \ | |||
| jassert (fieldID != 0); | |||
| JUCE_JNI_METHODS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD, CREATE_JNI_STATICFIELD); | |||
| #undef CREATE_JNI_METHOD | |||
| } | |||
| void shutdown() | |||
| { | |||
| JNIEnv* env = getEnv(); | |||
| if (env != 0) | |||
| { | |||
| #define RELEASE_JNI_CLASS(className, path) env->DeleteGlobalRef (className); | |||
| @@ -313,29 +475,12 @@ public: | |||
| #undef RELEASE_JNI_CLASS | |||
| activity.clear(); | |||
| env = 0; | |||
| } | |||
| } | |||
| //============================================================================== | |||
| const String juceString (jstring s) const | |||
| { | |||
| jboolean isCopy; | |||
| const char* const utf8 = env->GetStringUTFChars (s, &isCopy); | |||
| CharPointer_UTF8 utf8CP (utf8); | |||
| const String result (utf8CP); | |||
| env->ReleaseStringUTFChars (s, utf8); | |||
| return result; | |||
| } | |||
| jstring javaString (const String& s) const | |||
| { | |||
| return env->NewStringUTF (s.toUTF8()); | |||
| } | |||
| //============================================================================== | |||
| JNIEnv* env; | |||
| GlobalRef activity; | |||
| String appFile, appDataDir; | |||
| int screenWidth, screenHeight; | |||
| //============================================================================== | |||
| @@ -345,13 +490,12 @@ public: | |||
| #define DECLARE_JNI_METHOD(ownerClass, methodID, stringName, params) jmethodID methodID; | |||
| #define DECLARE_JNI_FIELD(ownerClass, fieldID, stringName, signature) jfieldID fieldID; | |||
| JUCE_JNI_METHODS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD); | |||
| JUCE_JNI_METHODS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD, DECLARE_JNI_FIELD); | |||
| #undef DECLARE_JNI_METHOD | |||
| }; | |||
| static AndroidJavaCallbacks android; | |||
| //============================================================================== | |||
| #define JUCE_INCLUDED_FILE 1 | |||
| @@ -77,8 +77,6 @@ int SystemStats::getCpuSpeedInMegaherz() | |||
| int SystemStats::getMemorySizeInMegabytes() | |||
| { | |||
| // TODO | |||
| struct sysinfo sysi; | |||
| if (sysinfo (&sysi) == 0) | |||
| @@ -125,8 +123,7 @@ void SystemStats::initialiseStats() | |||
| cpuFlags.hasSSE2 = flags.contains ("sse2"); | |||
| cpuFlags.has3DNow = flags.contains ("3dnow"); | |||
| // TODO | |||
| cpuFlags.numCpus = AndroidStatsHelpers::getCpuInfo ("processor").getIntValue() + 1; | |||
| cpuFlags.numCpus = jmax (1, sysconf (_SC_NPROCESSORS_ONLN)); | |||
| } | |||
| void PlatformUtilities::fpuReset() {} | |||
| @@ -27,6 +27,7 @@ | |||
| // compiled on its own). | |||
| #if JUCE_INCLUDED_FILE | |||
| static ModifierKeys currentModifiers; | |||
| //============================================================================== | |||
| class AndroidComponentPeer : public ComponentPeer | |||
| @@ -34,9 +35,9 @@ class AndroidComponentPeer : public ComponentPeer | |||
| public: | |||
| //============================================================================== | |||
| AndroidComponentPeer (Component* const component, const int windowStyleFlags) | |||
| : ComponentPeer (component, windowStyleFlags) | |||
| : ComponentPeer (component, windowStyleFlags), | |||
| view (android.activity.callObjectMethod (android.createNewView)) | |||
| { | |||
| view = GlobalRef (android.env, android.activity.callObjectMethod (android.createNewView)); | |||
| } | |||
| ~AndroidComponentPeer() | |||
| @@ -57,7 +58,7 @@ public: | |||
| void setTitle (const String& title) | |||
| { | |||
| view.callVoidMethod (android.setViewName, android.javaString (title)); | |||
| view.callVoidMethod (android.setViewName, javaString (title).get()); | |||
| } | |||
| void setPosition (int x, int y) | |||
| @@ -87,7 +88,7 @@ public: | |||
| const Point<int> getScreenPosition() const | |||
| { | |||
| JNIEnv* const env = view.getEnv(); | |||
| JNIEnv* const env = getEnv(); | |||
| jintArray pos = env->NewIntArray (2); | |||
| view.callVoidMethod (android.getLocationOnScreen, pos); | |||
| @@ -169,6 +170,26 @@ public: | |||
| // TODO | |||
| } | |||
| //============================================================================== | |||
| void handleMouseDownCallback (float x, float y, int64 time) | |||
| { | |||
| currentModifiers = currentModifiers.withoutMouseButtons(); | |||
| handleMouseEvent (0, Point<int> ((int) x, (int) y), currentModifiers, time); | |||
| currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier); | |||
| handleMouseEvent (0, Point<int> ((int) x, (int) y), currentModifiers, time); | |||
| } | |||
| void handleMouseDragCallback (float x, float y, int64 time) | |||
| { | |||
| handleMouseEvent (0, Point<int> ((int) x, (int) y), currentModifiers, time); | |||
| } | |||
| void handleMouseUpCallback (float x, float y, int64 time) | |||
| { | |||
| currentModifiers = currentModifiers.withoutMouseButtons(); | |||
| handleMouseEvent (0, Point<int> ((int) x, (int) y), currentModifiers, time); | |||
| } | |||
| //============================================================================== | |||
| bool isFocused() const | |||
| { | |||
| @@ -188,7 +209,8 @@ public: | |||
| //============================================================================== | |||
| void handlePaintCallback (JNIEnv* env, jobject canvas) | |||
| { | |||
| AndroidLowLevelGraphicsContext g (GlobalRef (env, canvas)); | |||
| GlobalRef canvasRef (canvas); | |||
| AndroidLowLevelGraphicsContext g (canvasRef); | |||
| handlePaint (g); | |||
| } | |||
| @@ -241,6 +263,12 @@ private: | |||
| JUCE_VIEW_CALLBACK (void, handlePaint, (JNIEnv* env, jobject view, jobject canvas), | |||
| handlePaintCallback (env, canvas)) | |||
| JUCE_VIEW_CALLBACK (void, handleMouseDown, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), | |||
| handleMouseDownCallback ((float) x, (float) y, (int64) time)) | |||
| JUCE_VIEW_CALLBACK (void, handleMouseDrag, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), | |||
| handleMouseDragCallback ((float) x, (float) y, (int64) time)) | |||
| JUCE_VIEW_CALLBACK (void, handleMouseUp, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), | |||
| handleMouseUpCallback ((float) x, (float) y, (int64) time)) | |||
| //============================================================================== | |||
| ComponentPeer* Component::createNewPeer (int styleFlags, void*) | |||
| @@ -294,8 +322,7 @@ void ModifierKeys::updateCurrentModifiers() throw() | |||
| const ModifierKeys ModifierKeys::getCurrentModifiersRealtime() throw() | |||
| { | |||
| // TODO | |||
| return ModifierKeys(); | |||
| return currentModifiers; | |||
| } | |||
| //============================================================================== | |||
| @@ -486,8 +486,7 @@ void FileOutputStream::flushInternal() | |||
| const File juce_getExecutableFile() | |||
| { | |||
| #if JUCE_ANDROID | |||
| // TODO | |||
| return File::nonexistent; | |||
| return File (android.appFile); | |||
| #else | |||
| Dl_info exeInfo; | |||
| dladdr ((void*) juce_getExecutableFile, &exeInfo); // (can't be a const void* on android) | |||
| @@ -707,6 +706,11 @@ void JUCE_API juce_threadEntryPoint (void*); | |||
| void* threadEntryProc (void* userData) | |||
| { | |||
| JUCE_AUTORELEASEPOOL | |||
| #if JUCE_ANDROID | |||
| const AndroidThreadScope androidEnv; | |||
| #endif | |||
| juce_threadEntryPoint (userData); | |||
| return 0; | |||
| } | |||
| @@ -744,7 +748,7 @@ void Thread::killThread() | |||
| void Thread::setCurrentThreadName (const String& name) | |||
| { | |||
| #if JUCE_MAC | |||
| #if JUCE_MAC && defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 | |||
| pthread_setname_np (name.toUTF8()); | |||
| #elif JUCE_LINUX | |||
| prctl (PR_SET_NAME, name.toUTF8().getAddress(), 0, 0, 0); | |||
| @@ -95,6 +95,7 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../common/juce_MidiDataConcatenator.h" | |||
| #undef Point | |||
| #if ! JUCE_ONLY_BUILD_CORE_LIBRARY | |||
| namespace | |||
| { | |||
| template <class RectType> | |||
| @@ -183,6 +184,7 @@ private: | |||
| static_cast <MessageQueue*> (info)->runLoopCallback(); | |||
| } | |||
| }; | |||
| #endif | |||
| //============================================================================== | |||
| #define JUCE_INCLUDED_FILE 1 | |||
| @@ -213,11 +213,11 @@ public: | |||
| for (;;) | |||
| { | |||
| const int n = *d++; | |||
| const uint32 n = (uint32) (uint8) *d++; | |||
| if ((n & 0x80) != 0) | |||
| { | |||
| int bit = 0x40; | |||
| uint32 bit = 0x40; | |||
| while ((n & bit) != 0) | |||
| { | |||
| @@ -2241,7 +2241,7 @@ public: | |||
| { | |||
| buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0x10ffff - 1)); | |||
| } | |||
| while (buffer[i] >= 0xd800 && buffer[i] <= 0xdfff); // (these code-points are illegal in UTF-16) | |||
| while (! CharPointer_UTF16::canRepresent (buffer[i])); | |||
| } | |||
| else | |||
| buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0xff)); | |||
| @@ -161,8 +161,8 @@ void UnitTestRunner::endTest() | |||
| if (r->failures > 0) | |||
| { | |||
| String m ("FAILED!!"); | |||
| m << r->failures << (r->failures == 1 ? "test" : "tests") | |||
| String m ("FAILED!! "); | |||
| m << r->failures << (r->failures == 1 ? " test" : " tests") | |||
| << " failed, out of a total of " << (r->passes + r->failures); | |||
| logMessage (String::empty); | |||