mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-21 01:24:21 +00:00
Minor fixes for mac compilation. Android stuff.
This commit is contained in:
parent
571a2626da
commit
08339c92e2
23 changed files with 1233 additions and 616 deletions
|
|
@ -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;
|
||||
|
|
|
|||
1041
juce_amalgamated.cpp
1041
juce_amalgamated.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -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)));
|
||||
|
|
|
|||
94
src/native/android/java/ComponentPeerView.java
Normal file
94
src/native/android/java/ComponentPeerView.java
Normal file
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
131
src/native/android/java/JuceAppActivity.java
Normal file
131
src/native/android/java/JuceAppActivity.java
Normal file
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue