Browse Source

Update juce

tags/1.9.7
falkTX 10 years ago
parent
commit
500dedf3d5
33 changed files with 757 additions and 79 deletions
  1. +4
    -4
      source/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp
  2. +2
    -2
      source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp
  3. +2
    -1
      source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp
  4. +8
    -0
      source/modules/juce_core/AppConfig.h
  5. +2
    -2
      source/modules/juce_core/javascript/juce_Javascript.cpp
  6. +7
    -0
      source/modules/juce_core/juce_core.cpp
  7. +11
    -0
      source/modules/juce_core/juce_core.h
  8. +12
    -4
      source/modules/juce_core/maths/juce_MathsFunctions.h
  9. +18
    -0
      source/modules/juce_core/memory/juce_Memory.h
  10. +7
    -1
      source/modules/juce_core/native/juce_android_JNIHelpers.h
  11. +472
    -0
      source/modules/juce_core/native/juce_curl_Network.cpp
  12. +70
    -12
      source/modules/juce_core/native/juce_linux_Network.cpp
  13. +1
    -1
      source/modules/juce_core/native/juce_posix_SharedCode.h
  14. +16
    -5
      source/modules/juce_core/native/juce_win32_Files.cpp
  15. +1
    -1
      source/modules/juce_core/system/juce_CompilerSupport.h
  16. +2
    -2
      source/modules/juce_core/system/juce_PlatformDefs.h
  17. +2
    -2
      source/modules/juce_core/zip/juce_ZipFile.cpp
  18. +16
    -10
      source/modules/juce_core/zip/juce_ZipFile.h
  19. +5
    -1
      source/modules/juce_graphics/fonts/juce_Font.h
  20. +2
    -0
      source/modules/juce_gui_basics/application/juce_Application.h
  21. +2
    -2
      source/modules/juce_gui_basics/components/juce_Component.h
  22. +0
    -2
      source/modules/juce_gui_basics/components/juce_Desktop.cpp
  23. +4
    -4
      source/modules/juce_gui_basics/drawables/juce_SVGParser.cpp
  24. +7
    -6
      source/modules/juce_gui_basics/keyboard/juce_TextEditorKeyMapper.h
  25. +6
    -0
      source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp
  26. +15
    -0
      source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h
  27. +3
    -3
      source/modules/juce_gui_basics/menus/juce_PopupMenu.cpp
  28. +1
    -1
      source/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp
  29. +42
    -0
      source/modules/juce_gui_basics/native/juce_linux_Windowing.cpp
  30. +2
    -4
      source/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp
  31. +3
    -0
      source/modules/juce_gui_basics/widgets/juce_TableListBox.h
  32. +11
    -9
      source/modules/juce_gui_basics/windows/juce_AlertWindow.cpp
  33. +1
    -0
      source/modules/juce_gui_basics/windows/juce_AlertWindow.h

+ 4
- 4
source/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp View File

@@ -26,12 +26,12 @@ namespace MidiBufferHelpers
{ {
inline int getEventTime (const void* const d) noexcept inline int getEventTime (const void* const d) noexcept
{ {
return *static_cast<const int32*> (d);
return readUnaligned<int32> (d);
} }
inline uint16 getEventDataSize (const void* const d) noexcept inline uint16 getEventDataSize (const void* const d) noexcept
{ {
return *reinterpret_cast<const uint16*> (static_cast<const char*> (d) + sizeof (int32));
return readUnaligned<uint16> (static_cast<const char*> (d) + sizeof (int32));
} }
inline uint16 getEventTotalSize (const void* const d) noexcept inline uint16 getEventTotalSize (const void* const d) noexcept
@@ -124,8 +124,8 @@ void MidiBuffer::addEvent (const void* const newData, const int maxBytes, const
data.insertMultiple (offset, 0, (int) newItemSize); data.insertMultiple (offset, 0, (int) newItemSize);
uint8* const d = data.begin() + offset; uint8* const d = data.begin() + offset;
*reinterpret_cast<int32*> (d) = sampleNumber;
*reinterpret_cast<uint16*> (d + 4) = (uint16) numBytes;
writeUnaligned<int32> (d, sampleNumber);
writeUnaligned<uint16> (d + 4, static_cast<uint16> (numBytes));
memcpy (d + 6, newData, (size_t) numBytes); memcpy (d + 6, newData, (size_t) numBytes);
} }
} }


+ 2
- 2
source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp View File

@@ -538,10 +538,10 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
{ {
SynthesiserVoice* const voice = voices.getUnchecked (i); SynthesiserVoice* const voice = voices.getUnchecked (i);
jassert (voice->isVoiceActive()); // We wouldn't be here otherwise
if (voice->canPlaySound (soundToPlay)) if (voice->canPlaySound (soundToPlay))
{ {
jassert (voice->isVoiceActive()); // We wouldn't be here otherwise
VoiceAgeSorter sorter; VoiceAgeSorter sorter;
usableVoices.addSorted (sorter, voice); usableVoices.addSorted (sorter, voice);


+ 2
- 1
source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp View File

@@ -977,7 +977,6 @@ bool AudioProcessorGraph::removeNode (const uint32 nodeId)
{ {
if (nodes.getUnchecked(i)->nodeId == nodeId) if (nodes.getUnchecked(i)->nodeId == nodeId)
{ {
nodes.getUnchecked(i)->setParentGraph (nullptr);
nodes.remove (i); nodes.remove (i);
triggerAsyncUpdate(); triggerAsyncUpdate();
@@ -1282,6 +1281,8 @@ void AudioProcessorGraph::setPlayHead (AudioPlayHead* audioPlayHead)
{ {
const ScopedLock sl (getCallbackLock()); const ScopedLock sl (getCallbackLock());
AudioProcessor::setPlayHead (audioPlayHead);
for (int i = 0; i < nodes.size(); ++i) for (int i = 0; i < nodes.size(); ++i)
nodes.getUnchecked(i)->getProcessor()->setPlayHead (audioPlayHead); nodes.getUnchecked(i)->getProcessor()->setPlayHead (audioPlayHead);
} }


+ 8
- 0
source/modules/juce_core/AppConfig.h View File

@@ -63,6 +63,14 @@
*/ */
#define JUCE_INCLUDE_ZLIB_CODE 1 #define JUCE_INCLUDE_ZLIB_CODE 1
/** Config: JUCE_USE_CURL
Enables http/https support via libcurl (Linux only). Enabling this will add an additional
run-time dynmic dependency to libcurl.
If you disable this then https/ssl support will not be available on linux.
*/
#define JUCE_USE_CURL 0
/* Config: JUCE_CATCH_UNHANDLED_EXCEPTIONS /* Config: JUCE_CATCH_UNHANDLED_EXCEPTIONS
If enabled, this will add some exception-catching code to forward unhandled exceptions If enabled, this will add some exception-catching code to forward unhandled exceptions
to your JUCEApplicationBase::unhandledException() callback. to your JUCEApplicationBase::unhandledException() callback.


+ 2
- 2
source/modules/juce_core/javascript/juce_Javascript.cpp View File

@@ -1584,8 +1584,8 @@ struct JavascriptEngine::RootObject : public DynamicObject
static var Math_range (Args a) { return isInt (a, 0) ? var (jlimit (getInt (a, 1), getInt (a, 2), getInt (a, 0))) : var (jlimit (getDouble (a, 1), getDouble (a, 2), getDouble (a, 0))); } static var Math_range (Args a) { return isInt (a, 0) ? var (jlimit (getInt (a, 1), getInt (a, 2), getInt (a, 0))) : var (jlimit (getDouble (a, 1), getDouble (a, 2), getDouble (a, 0))); }
static var Math_min (Args a) { return (isInt (a, 0) && isInt (a, 1)) ? var (jmin (getInt (a, 0), getInt (a, 1))) : var (jmin (getDouble (a, 0), getDouble (a, 1))); } static var Math_min (Args a) { return (isInt (a, 0) && isInt (a, 1)) ? var (jmin (getInt (a, 0), getInt (a, 1))) : var (jmin (getDouble (a, 0), getDouble (a, 1))); }
static var Math_max (Args a) { return (isInt (a, 0) && isInt (a, 1)) ? var (jmax (getInt (a, 0), getInt (a, 1))) : var (jmax (getDouble (a, 0), getDouble (a, 1))); } static var Math_max (Args a) { return (isInt (a, 0) && isInt (a, 1)) ? var (jmax (getInt (a, 0), getInt (a, 1))) : var (jmax (getDouble (a, 0), getDouble (a, 1))); }
static var Math_toDegrees (Args a) { return (180.0 / double_Pi) * getDouble (a, 0); }
static var Math_toRadians (Args a) { return (double_Pi / 180.0) * getDouble (a, 0); }
static var Math_toDegrees (Args a) { return radiansToDegrees (getDouble (a, 0)); }
static var Math_toRadians (Args a) { return degreesToRadians (getDouble (a, 0)); }
static var Math_sin (Args a) { return sin (getDouble (a, 0)); } static var Math_sin (Args a) { return sin (getDouble (a, 0)); }
static var Math_asin (Args a) { return asin (getDouble (a, 0)); } static var Math_asin (Args a) { return asin (getDouble (a, 0)); }
static var Math_cos (Args a) { return cos (getDouble (a, 0)); } static var Math_cos (Args a) { return cos (getDouble (a, 0)); }


+ 7
- 0
source/modules/juce_core/juce_core.cpp View File

@@ -82,6 +82,10 @@
#if JUCE_LINUX #if JUCE_LINUX
#include <langinfo.h> #include <langinfo.h>
#include <ifaddrs.h> #include <ifaddrs.h>
#if JUCE_USE_CURL
#include <curl/curl.h>
#endif
#endif #endif
#include <pwd.h> #include <pwd.h>
@@ -210,6 +214,9 @@ namespace juce
#include "native/juce_linux_CommonFile.cpp" #include "native/juce_linux_CommonFile.cpp"
#include "native/juce_linux_Files.cpp" #include "native/juce_linux_Files.cpp"
#include "native/juce_linux_Network.cpp" #include "native/juce_linux_Network.cpp"
#if JUCE_USE_CURL
#include "native/juce_curl_Network.cpp"
#endif
#include "native/juce_linux_SystemStats.cpp" #include "native/juce_linux_SystemStats.cpp"
#include "native/juce_linux_Threads.cpp" #include "native/juce_linux_Threads.cpp"


+ 11
- 0
source/modules/juce_core/juce_core.h View File

@@ -126,6 +126,17 @@
#define JUCE_ZLIB_INCLUDE_PATH <zlib.h> #define JUCE_ZLIB_INCLUDE_PATH <zlib.h>
#endif #endif
/** Config: JUCE_USE_CURL
Enables http/https support via libcurl (Linux only). Enabling this will add an additional
run-time dynmic dependency to libcurl.
If you disable this then https/ssl support will not be available on linux.
*/
#ifndef JUCE_USE_CURL
#define JUCE_USE_CURL 0
#endif
/* Config: JUCE_CATCH_UNHANDLED_EXCEPTIONS /* Config: JUCE_CATCH_UNHANDLED_EXCEPTIONS
If enabled, this will add some exception-catching code to forward unhandled exceptions If enabled, this will add some exception-catching code to forward unhandled exceptions
to your JUCEApplicationBase::unhandledException() callback. to your JUCEApplicationBase::unhandledException() callback.


+ 12
- 4
source/modules/juce_core/maths/juce_MathsFunctions.h View File

@@ -354,6 +354,15 @@ const double double_Pi = 3.1415926535897932384626433832795;
const float float_Pi = 3.14159265358979323846f; const float float_Pi = 3.14159265358979323846f;
/** Converts an angle in degrees to radians. */
template <typename FloatType>
inline FloatType degreesToRadians (FloatType degrees) noexcept { return degrees * static_cast<FloatType> (double_Pi / 180.0); }
/** Converts an angle in radians to degrees. */
template <typename FloatType>
inline FloatType radiansToDegrees (FloatType radians) noexcept { return radians * static_cast<FloatType> (180.0 / double_Pi); }
//============================================================================== //==============================================================================
/** The isfinite() method seems to vary between platforms, so this is a /** The isfinite() method seems to vary between platforms, so this is a
platform-independent function for it. platform-independent function for it.
@@ -477,16 +486,14 @@ inline int roundFloatToInt (const float value) noexcept
} }
//============================================================================== //==============================================================================
/** Returns true if the specified integer is a power-of-two.
*/
/** Returns true if the specified integer is a power-of-two. */
template <typename IntegerType> template <typename IntegerType>
bool isPowerOfTwo (IntegerType value) bool isPowerOfTwo (IntegerType value)
{ {
return (value & (value - 1)) == 0; return (value & (value - 1)) == 0;
} }
/** Returns the smallest power-of-two which is equal to or greater than the given integer.
*/
/** Returns the smallest power-of-two which is equal to or greater than the given integer. */
inline int nextPowerOfTwo (int n) noexcept inline int nextPowerOfTwo (int n) noexcept
{ {
--n; --n;
@@ -533,6 +540,7 @@ NumericType square (NumericType n) noexcept
return n * n; return n * n;
} }
//============================================================================== //==============================================================================
#if JUCE_INTEL || defined (DOXYGEN) #if JUCE_INTEL || defined (DOXYGEN)
/** This macro can be applied to a float variable to check whether it contains a denormalised /** This macro can be applied to a float variable to check whether it contains a denormalised


+ 18
- 0
source/modules/juce_core/memory/juce_Memory.h View File

@@ -64,6 +64,24 @@ inline int getAddressDifference (Type1* pointer1, Type2* pointer2) noexcept { r
template <class Type> template <class Type>
inline Type* createCopyIfNotNull (const Type* objectToCopy) { return objectToCopy != nullptr ? new Type (*objectToCopy) : nullptr; } inline Type* createCopyIfNotNull (const Type* objectToCopy) { return objectToCopy != nullptr ? new Type (*objectToCopy) : nullptr; }
//==============================================================================
/** A handy function to read un-aligned memory without a performance penalty or bus-error. */
template <typename Type>
inline Type readUnaligned (const void* srcPtr) noexcept
{
Type value;
memcpy (&value, srcPtr, sizeof (Type));
return value;
}
/** A handy function to write un-aligned memory without a performance penalty or bus-error. */
template <typename Type>
inline void writeUnaligned (void* dstPtr, Type value) noexcept
{
memcpy (dstPtr, &value, sizeof(Type));
}
//============================================================================== //==============================================================================
#if JUCE_MAC || JUCE_IOS || DOXYGEN #if JUCE_MAC || JUCE_IOS || DOXYGEN


+ 7
- 1
source/modules/juce_core/native/juce_android_JNIHelpers.h View File

@@ -227,8 +227,14 @@ private:
//============================================================================== //==============================================================================
#if defined (__arm__)
#define JUCE_ARM_SOFT_FLOAT_ABI __attribute__ ((pcs("aapcs")))
#else
#define JUCE_ARM_SOFT_FLOAT_ABI
#endif
#define JUCE_JNI_CALLBACK(className, methodName, returnType, params) \ #define JUCE_JNI_CALLBACK(className, methodName, returnType, params) \
extern "C" __attribute__ ((visibility("default"))) returnType JUCE_JOIN_MACRO (JUCE_JOIN_MACRO (Java_, className), _ ## methodName) params
extern "C" __attribute__ ((visibility("default"))) JUCE_ARM_SOFT_FLOAT_ABI returnType JUCE_JOIN_MACRO (JUCE_JOIN_MACRO (Java_, className), _ ## methodName) params
//============================================================================== //==============================================================================
class AndroidSystem class AndroidSystem


+ 472
- 0
source/modules/juce_core/native/juce_curl_Network.cpp View File

@@ -0,0 +1,472 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
class WebInputStream : public InputStream
{
public:
WebInputStream (const String& address, bool isPost, const MemoryBlock& postData,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers, int timeOutMs, StringPairArray* responseHeaders,
const int maxRedirects)
: multi (nullptr), curl (nullptr), headerList (nullptr), lastError (CURLE_OK),
contentLength (-1), streamPos (0),
finished (false), skipBytes (0),
postBuffer (nullptr), postPosition (0)
{
statusCode = -1;
if (init() && setOptions (address, timeOutMs, (responseHeaders != nullptr),
maxRedirects, headers, isPost, postData.getSize()))
{
connect (responseHeaders, isPost, postData, progressCallback, progressCallbackContext);
}
else
{
cleanup();
}
}
~WebInputStream()
{
cleanup();
}
//==============================================================================
// Input Stream overrides
bool isError() const { return curl == nullptr || lastError != CURLE_OK; }
bool isExhausted() override { return (isError() || finished) && curlBuffer.getSize() == 0; }
int64 getPosition() override { return streamPos; }
int64 getTotalLength() override { return contentLength; }
int read (void* buffer, int bytesToRead) override
{
return readOrSkip (buffer, bytesToRead, false);
}
bool setPosition (int64 wantedPos) override
{
const int amountToSkip = static_cast<int> (wantedPos - getPosition());
if (amountToSkip < 0)
return false;
if (amountToSkip == 0)
return true;
const int actuallySkipped = readOrSkip (nullptr, amountToSkip, true);
return actuallySkipped == amountToSkip;
}
//==============================================================================
int statusCode;
private:
//==============================================================================
bool init()
{
multi = curl_multi_init();
if (multi != nullptr)
{
curl = curl_easy_init();
if (curl != nullptr)
if (curl_multi_add_handle (multi, curl) == CURLM_OK)
return true;
}
cleanup();
return false;
}
void cleanup()
{
if (curl != nullptr)
{
curl_multi_remove_handle (multi, curl);
if (headerList != nullptr)
{
curl_slist_free_all (headerList);
headerList = nullptr;
}
curl_easy_cleanup (curl);
curl = nullptr;
}
if (multi != nullptr)
{
curl_multi_cleanup (multi);
multi = nullptr;
}
}
//==============================================================================
bool setOptions (const String& address, int timeOutMs, bool wantsHeaders,
const int maxRedirects, const String& headers,
bool isPost, size_t postSize)
{
if (curl_easy_setopt (curl, CURLOPT_URL, address.toRawUTF8()) == CURLE_OK
&& curl_easy_setopt (curl, CURLOPT_WRITEDATA, this) == CURLE_OK
&& curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, StaticCurlWrite) == CURLE_OK
&& curl_easy_setopt (curl, CURLOPT_MAXREDIRS, static_cast<long> (maxRedirects)) == CURLE_OK)
{
if (isPost)
{
if (curl_easy_setopt (curl, CURLOPT_READDATA, this) != CURLE_OK
|| curl_easy_setopt (curl, CURLOPT_READFUNCTION, StaticCurlRead) != CURLE_OK)
return false;
if (curl_easy_setopt (curl, CURLOPT_POST, 1) != CURLE_OK
|| curl_easy_setopt (curl, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t> (postSize)) != CURLE_OK)
return false;
}
// do we want to parse the headers
if (wantsHeaders)
{
if (curl_easy_setopt (curl, CURLOPT_HEADERDATA, this) != CURLE_OK
|| curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, StaticCurlHeader) != CURLE_OK)
return false;
}
if (headers.isNotEmpty())
{
const StringArray headerLines = StringArray::fromLines (headers);
// fromLines will always return at least one line if the string is not empty
jassert (headerLines.size() > 0);
headerList = curl_slist_append (headerList, headerLines [0].toRawUTF8());
for (int i = 1; (i < headerLines.size() && headerList != nullptr); ++i)
headerList = curl_slist_append (headerList, headerLines [i].toRawUTF8());
if (headerList == nullptr)
return false;
if (curl_easy_setopt (curl, CURLOPT_HTTPHEADER, headerList) != CURLE_OK)
return false;
}
if (timeOutMs > 0)
{
long timeOutSecs = static_cast<long> (ceil (static_cast<double> (timeOutMs) / 1000.0));
if (curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, timeOutSecs) != CURLE_OK)
return false;
}
return true;
}
return false;
}
void connect (StringPairArray* responseHeaders, bool isPost, const MemoryBlock& postData,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
{
if (isPost)
postBuffer = &postData;
size_t lastPos = static_cast<size_t> (-1);
// step until either: 1) there is an error 2) the transaction is complete
// or 3) data is in the in buffer
while ((! finished) && curlBuffer.getSize() == 0 && curl != nullptr)
{
singleStep();
// call callbacks if this is a post request
if (isPost && progressCallback != nullptr && lastPos != postPosition)
{
lastPos = postPosition;
if (! progressCallback (progressCallbackContext,
static_cast<int> (lastPos),
static_cast<int> (postData.getSize())))
{
// user has decided to abort the transaction
cleanup();
return;
}
}
}
long responseCode;
if (curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &responseCode) == CURLE_OK)
statusCode = static_cast<int> (responseCode);
// parse headers
if (responseHeaders != nullptr)
parseHttpHeaders (*responseHeaders);
// get content length size
double curlLength;
if (curl_easy_getinfo (curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &curlLength) == CURLE_OK)
contentLength = static_cast<int64> (curlLength);
}
void finish()
{
if (curl == nullptr)
return;
for (;;)
{
int cnt = 0;
if (CURLMsg* msg = curl_multi_info_read (multi, &cnt))
{
if (msg->msg == CURLMSG_DONE && msg->easy_handle == curl)
{
lastError = msg->data.result; // this is the error that stopped our process from continuing
break;
}
}
else
{
break;
}
}
finished = true;
}
//==============================================================================
void singleStep()
{
if (curl == nullptr || lastError != CURLE_OK)
return;
fd_set fdread, fdwrite, fdexcep;
int maxfd = -1;
long curl_timeo;
if ((lastError = (int) curl_multi_timeout (multi, &curl_timeo)) != CURLM_OK)
return;
// why 980? see http://curl.haxx.se/libcurl/c/curl_multi_timeout.html
if (curl_timeo < 0)
curl_timeo = 980;
struct timeval tv;
tv.tv_sec = curl_timeo / 1000;
tv.tv_usec = (curl_timeo % 1000) * 1000;
FD_ZERO (&fdread);
FD_ZERO (&fdwrite);
FD_ZERO (&fdexcep);
if ((lastError = (int) curl_multi_fdset (multi, &fdread, &fdwrite, &fdexcep, &maxfd)) != CURLM_OK)
return;
if (maxfd != -1)
{
if (select (maxfd + 1, &fdread, &fdwrite, &fdexcep, &tv) < 0)
{
lastError = -1;
return;
}
}
else
{
// if curl does not return any sockets for to wait on, then the doc says to wait 100 ms
Thread::sleep (100);
}
int still_running = 0;
int curlRet;
while ((curlRet = (int) curl_multi_perform (multi, &still_running)) == CURLM_CALL_MULTI_PERFORM)
{}
if ((lastError = curlRet) != CURLM_OK)
return;
if (still_running <= 0)
finish();
}
int readOrSkip (void* buffer, int bytesToRead, bool skip)
{
if (bytesToRead <= 0)
return 0;
size_t pos = 0;
size_t len = static_cast<size_t> (bytesToRead);
while (len > 0)
{
size_t bufferBytes = curlBuffer.getSize();
bool removeSection = true;
if (bufferBytes == 0)
{
// do not call curl again if we are finished
if (finished || curl == nullptr)
return static_cast<int> (pos);
skipBytes = skip ? len : 0;
singleStep();
// update the amount that was read/skipped from curl
bufferBytes = skip ? len - skipBytes : curlBuffer.getSize();
removeSection = ! skip;
}
// can we copy data from the internal buffer?
if (bufferBytes > 0)
{
size_t max = jmin (len, bufferBytes);
if (! skip)
memcpy (addBytesToPointer (buffer, pos), curlBuffer.getData(), max);
pos += max;
streamPos += static_cast<int64> (max);
len -= max;
if (removeSection)
curlBuffer.removeSection (0, max);
}
}
return static_cast<int> (pos);
}
//==============================================================================
void parseHttpHeaders (StringPairArray& responseHeaders)
{
StringArray headerLines = StringArray::fromLines (curlHeaders);
// ignore the first line as this is the status line
for (int i = 1; i < headerLines.size(); ++i)
{
const String& headersEntry = headerLines[i];
if (headersEntry.isNotEmpty())
{
const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false));
const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false));
const String previousValue (responseHeaders [key]);
responseHeaders.set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
}
}
}
//==============================================================================
// CURL callbacks
size_t curlWriteCallback (char* ptr, size_t size, size_t nmemb)
{
if (curl == nullptr || lastError != CURLE_OK)
return 0;
const size_t len = size * nmemb;
// skip bytes if necessary
size_t max = jmin (skipBytes, len);
skipBytes -= max;
if (len > max)
curlBuffer.append (ptr + max, len - max);
return len;
}
size_t curlReadCallback (char* ptr, size_t size, size_t nmemb)
{
if (curl == nullptr || postBuffer == nullptr || lastError != CURLE_OK)
return 0;
const size_t len = size * nmemb;
size_t max = jmin (postBuffer->getSize() - postPosition, len);
memcpy (ptr, (char*)postBuffer->getData() + postPosition, max);
postPosition += max;
return max;
}
size_t curlHeaderCallback (char* ptr, size_t size, size_t nmemb)
{
if (curl == nullptr || lastError != CURLE_OK)
return 0;
size_t len = size * nmemb;
curlHeaders += String (ptr, len);
return len;
}
//==============================================================================
// Static method wrappers
static size_t StaticCurlWrite (char* ptr, size_t size, size_t nmemb, void* userdata)
{
WebInputStream* wi = reinterpret_cast<WebInputStream*> (userdata);
return wi->curlWriteCallback (ptr, size, nmemb);
}
static size_t StaticCurlRead (char* ptr, size_t size, size_t nmemb, void* userdata)
{
WebInputStream* wi = reinterpret_cast<WebInputStream*> (userdata);
return wi->curlReadCallback (ptr, size, nmemb);
}
static size_t StaticCurlHeader (char* ptr, size_t size, size_t nmemb, void* userdata)
{
WebInputStream* wi = reinterpret_cast<WebInputStream*> (userdata);
return wi->curlHeaderCallback (ptr, size, nmemb);
}
private:
CURLM* multi;
CURL* curl;
struct curl_slist* headerList;
int lastError;
//==============================================================================
// internal buffers and buffer positions
int64 contentLength, streamPos;
MemoryBlock curlBuffer;
String curlHeaders;
bool finished;
size_t skipBytes;
//==============================================================================
// Http POST variables
const MemoryBlock* postBuffer;
size_t postPosition;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
};

+ 70
- 12
source/modules/juce_core/native/juce_linux_Network.cpp View File

@@ -67,8 +67,8 @@ bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& /* targetEma
return false; return false;
} }
//============================================================================== //==============================================================================
#if ! JUCE_USE_CURL
class WebInputStream : public InputStream class WebInputStream : public InputStream
{ {
public: public:
@@ -77,8 +77,9 @@ public:
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders, const String& headers_, int timeOutMs_, StringPairArray* responseHeaders,
const int maxRedirects) const int maxRedirects)
: statusCode (0), socketHandle (-1), levelsOfRedirection (0), : statusCode (0), socketHandle (-1), levelsOfRedirection (0),
address (address_), headers (headers_), postData (postData_), position (0),
finished (false), isPost (isPost_), timeOutMs (timeOutMs_), numRedirectsToFollow (maxRedirects)
address (address_), headers (headers_), postData (postData_), contentLength (-1), position (0),
finished (false), isPost (isPost_), timeOutMs (timeOutMs_), numRedirectsToFollow (maxRedirects),
chunkEnd (0), isChunked (false), readingChunk (false)
{ {
statusCode = createConnection (progressCallback, progressCallbackContext, numRedirectsToFollow); statusCode = createConnection (progressCallback, progressCallbackContext, numRedirectsToFollow);
@@ -104,18 +105,63 @@ public:
bool isError() const { return socketHandle < 0; } bool isError() const { return socketHandle < 0; }
bool isExhausted() override { return finished; } bool isExhausted() override { return finished; }
int64 getPosition() override { return position; } int64 getPosition() override { return position; }
int64 getTotalLength() override
{
//xxx to do
return -1;
}
int64 getTotalLength() override { return contentLength; }
int read (void* buffer, int bytesToRead) override int read (void* buffer, int bytesToRead) override
{ {
if (finished || isError()) if (finished || isError())
return 0; return 0;
if (isChunked && ! readingChunk)
{
if (position >= chunkEnd)
{
const ScopedValueSetter<bool> setter (readingChunk, true, false);
MemoryOutputStream chunkLengthBuffer;
char c = 0;
if (chunkEnd > 0)
{
if (read (&c, 1) != 1 || c != '\r'
|| read (&c, 1) != 1 || c != '\n')
{
finished = true;
return 0;
}
}
while (chunkLengthBuffer.getDataSize() < 512 && ! (finished || isError()))
{
if (read (&c, 1) != 1)
{
finished = true;
return 0;
}
if (c == '\r')
continue;
if (c == '\n')
break;
chunkLengthBuffer.writeByte (c);
}
const int64 chunkSize = chunkLengthBuffer.toString().trimStart().getHexValue64();
if (chunkSize == 0)
{
finished = true;
return 0;
}
chunkEnd += chunkSize;
}
if (bytesToRead > chunkEnd - position)
bytesToRead = chunkEnd - position;
}
fd_set readbits; fd_set readbits;
FD_ZERO (&readbits); FD_ZERO (&readbits);
FD_SET (socketHandle, &readbits); FD_SET (socketHandle, &readbits);
@@ -131,7 +177,9 @@ public:
if (bytesRead == 0) if (bytesRead == 0)
finished = true; finished = true;
position += bytesRead;
if (! readingChunk)
position += bytesRead;
return bytesRead; return bytesRead;
} }
@@ -165,11 +213,13 @@ private:
StringArray headerLines; StringArray headerLines;
String address, headers; String address, headers;
MemoryBlock postData; MemoryBlock postData;
int64 position;
int64 contentLength, position;
bool finished; bool finished;
const bool isPost; const bool isPost;
const int timeOutMs; const int timeOutMs;
const int numRedirectsToFollow; const int numRedirectsToFollow;
int64 chunkEnd;
bool isChunked, readingChunk;
void closeSocket (bool resetLevelsOfRedirection = true) void closeSocket (bool resetLevelsOfRedirection = true)
{ {
@@ -298,6 +348,13 @@ private:
return createConnection (progressCallback, progressCallbackContext, numRedirects); return createConnection (progressCallback, progressCallbackContext, numRedirects);
} }
String contentLengthString (findHeaderItem (headerLines, "Content-Length:"));
if (contentLengthString.isNotEmpty())
contentLength = contentLengthString.getLargeIntValue();
isChunked = (findHeaderItem (headerLines, "Transfer-Encoding:") == "chunked");
return status; return status;
} }
@@ -345,7 +402,7 @@ private:
static void writeHost (MemoryOutputStream& dest, const bool isPost, static void writeHost (MemoryOutputStream& dest, const bool isPost,
const String& path, const String& host, int port) const String& path, const String& host, int port)
{ {
dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.0\r\nHost: " << host;
dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.1\r\nHost: " << host;
/* HTTP spec 14.23 says that the port number must be included in the header if it is not 80 */ /* HTTP spec 14.23 says that the port number must be included in the header if it is not 80 */
if (port != 80) if (port != 80)
@@ -455,3 +512,4 @@ private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
}; };
#endif

+ 1
- 1
source/modules/juce_core/native/juce_posix_SharedCode.h View File

@@ -987,7 +987,7 @@ void JUCE_CALLTYPE Thread::setCurrentThreadAffinityMask (const uint32 affinityMa
if ((affinityMask & (1 << i)) != 0) if ((affinityMask & (1 << i)) != 0)
CPU_SET (i, &affinity); CPU_SET (i, &affinity);
#if (! JUCE_LINUX) || ((__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2004)
#if (! JUCE_ANDROID) && ((! JUCE_LINUX) || ((__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2004))
pthread_setaffinity_np (pthread_self(), sizeof (cpu_set_t), &affinity); pthread_setaffinity_np (pthread_self(), sizeof (cpu_set_t), &affinity);
#else #else
// NB: this call isn't really correct because it sets the affinity of the process, // NB: this call isn't really correct because it sets the affinity of the process,


+ 16
- 5
source/modules/juce_core/native/juce_win32_Files.cpp View File

@@ -795,18 +795,19 @@ public:
connected (false), ownsPipe (createPipe), shouldStop (false) connected (false), ownsPipe (createPipe), shouldStop (false)
{ {
if (createPipe) if (createPipe)
{
pipeH = CreateNamedPipe (filename.toWideCharPointer(), pipeH = CreateNamedPipe (filename.toWideCharPointer(),
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0,
PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, 0); PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, 0);
if (GetLastError() == ERROR_ALREADY_EXISTS)
closePipeHandle();
}
} }
~Pimpl() ~Pimpl()
{ {
disconnectPipe();
if (pipeH != INVALID_HANDLE_VALUE)
CloseHandle (pipeH);
closePipeHandle();
CloseHandle (cancelEvent); CloseHandle (cancelEvent);
} }
@@ -868,6 +869,16 @@ public:
} }
} }
void closePipeHandle()
{
if (pipeH != INVALID_HANDLE_VALUE)
{
disconnectPipe();
CloseHandle (pipeH);
pipeH = INVALID_HANDLE_VALUE;
}
}
int read (void* destBuffer, const int maxBytesToRead, const int timeOutMilliseconds) int read (void* destBuffer, const int maxBytesToRead, const int timeOutMilliseconds)
{ {
while (connect (timeOutMilliseconds)) while (connect (timeOutMilliseconds))


+ 1
- 1
source/modules/juce_core/system/juce_CompilerSupport.h View File

@@ -113,11 +113,11 @@
#if _MSC_VER >= 1800 #if _MSC_VER >= 1800
#define JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS 1 #define JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS 1
#define JUCE_COMPILER_SUPPORTS_VARIADIC_TEMPLATES 1 #define JUCE_COMPILER_SUPPORTS_VARIADIC_TEMPLATES 1
#define JUCE_DELETED_FUNCTION = delete
#endif #endif
#if _MSC_VER >= 1900 #if _MSC_VER >= 1900
#define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1 #define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1
#define JUCE_DELETED_FUNCTION = delete
#endif #endif
#endif #endif


+ 2
- 2
source/modules/juce_core/system/juce_PlatformDefs.h View File

@@ -63,8 +63,8 @@
//============================================================================== //==============================================================================
#if JUCE_IOS || JUCE_LINUX || JUCE_ANDROID || JUCE_PPC #if JUCE_IOS || JUCE_LINUX || JUCE_ANDROID || JUCE_PPC
/** This will try to break into the debugger if the app is currently being debugged. /** This will try to break into the debugger if the app is currently being debugged.
If called by an app that's not being debugged, the behaiour isn't defined - it may crash or not, depending
on the platform.
If called by an app that's not being debugged, the behaviour isn't defined - it may
crash or not, depending on the platform.
@see jassert() @see jassert()
*/ */
#define juce_breakDebugger { ::kill (0, SIGTRAP); } #define juce_breakDebugger { ::kill (0, SIGTRAP); }


+ 2
- 2
source/modules/juce_core/zip/juce_ZipFile.cpp View File

@@ -328,7 +328,7 @@ void ZipFile::sortEntriesByFilename()
//============================================================================== //==============================================================================
void ZipFile::init() void ZipFile::init()
{ {
ScopedPointer <InputStream> toDelete;
ScopedPointer<InputStream> toDelete;
InputStream* in = inputStream; InputStream* in = inputStream;
if (inputSource != nullptr) if (inputSource != nullptr)
@@ -358,7 +358,7 @@ void ZipFile::init()
if (pos + 46 > size) if (pos + 46 > size)
break; break;
const char* const buffer = static_cast <const char*> (headerData.getData()) + pos;
const char* const buffer = static_cast<const char*> (headerData.getData()) + pos;
const int fileNameLen = ByteOrder::littleEndianShort (buffer + 28); const int fileNameLen = ByteOrder::littleEndianShort (buffer + 28);


+ 16
- 10
source/modules/juce_core/zip/juce_ZipFile.h View File

@@ -40,7 +40,7 @@
class JUCE_API ZipFile class JUCE_API ZipFile
{ {
public: public:
/** Creates a ZipFile based for a file. */
/** Creates a ZipFile to read a specific file. */
explicit ZipFile (const File& file); explicit ZipFile (const File& file);
//============================================================================== //==============================================================================
@@ -91,15 +91,12 @@ public:
int getNumEntries() const noexcept; int getNumEntries() const noexcept;
/** Returns a structure that describes one of the entries in the zip file. /** Returns a structure that describes one of the entries in the zip file.
This may return zero if the index is out of range. This may return zero if the index is out of range.
@see ZipFile::ZipEntry @see ZipFile::ZipEntry
*/ */
const ZipEntry* getEntry (int index) const noexcept; const ZipEntry* getEntry (int index) const noexcept;
/** Returns the index of the first entry with a given filename. /** Returns the index of the first entry with a given filename.
This uses a case-sensitive comparison to look for a filename in the This uses a case-sensitive comparison to look for a filename in the
list of entries. It might return -1 if no match is found. list of entries. It might return -1 if no match is found.
@@ -116,8 +113,7 @@ public:
*/ */
const ZipEntry* getEntry (const String& fileName) const noexcept; const ZipEntry* getEntry (const String& fileName) const noexcept;
/** Sorts the list of entries, based on the filename.
*/
/** Sorts the list of entries, based on the filename. */
void sortEntriesByFilename(); void sortEntriesByFilename();
//============================================================================== //==============================================================================
@@ -128,6 +124,11 @@ public:
The stream must not be used after the ZipFile object that created The stream must not be used after the ZipFile object that created
has been deleted. has been deleted.
Note that if the ZipFile was created with a user-supplied InputStream object,
then all the streams which are created by this method will by trying to share
the same source stream, so cannot be safely used on multiple threads! (But if
you create the ZipFile from a File or InputSource, then it is safe to do this).
*/ */
InputStream* createStreamForEntry (int index); InputStream* createStreamForEntry (int index);
@@ -138,6 +139,11 @@ public:
The stream must not be used after the ZipFile object that created The stream must not be used after the ZipFile object that created
has been deleted. has been deleted.
Note that if the ZipFile was created with a user-supplied InputStream object,
then all the streams which are created by this method will by trying to share
the same source stream, so cannot be safely used on multiple threads! (But if
you create the ZipFile from a File or InputSource, then it is safe to do this).
*/ */
InputStream* createStreamForEntry (const ZipEntry& entry); InputStream* createStreamForEntry (const ZipEntry& entry);
@@ -194,7 +200,7 @@ public:
will be stored for this file. will be stored for this file.
*/ */
void addFile (const File& fileToAdd, int compressionLevel, void addFile (const File& fileToAdd, int compressionLevel,
const String& storedPathName = String::empty);
const String& storedPathName = String());
/** Adds a file while should be added to the archive. /** Adds a file while should be added to the archive.
@@ -233,11 +239,11 @@ private:
friend class ZipInputStream; friend class ZipInputStream;
friend class ZipEntryHolder; friend class ZipEntryHolder;
OwnedArray <ZipEntryHolder> entries;
OwnedArray<ZipEntryHolder> entries;
CriticalSection lock; CriticalSection lock;
InputStream* inputStream; InputStream* inputStream;
ScopedPointer <InputStream> streamToDelete;
ScopedPointer <InputSource> inputSource;
ScopedPointer<InputStream> streamToDelete;
ScopedPointer<InputSource> inputSource;
#if JUCE_DEBUG #if JUCE_DEBUG
struct OpenStreamCounter struct OpenStreamCounter


+ 5
- 1
source/modules/juce_graphics/fonts/juce_Font.h View File

@@ -279,8 +279,12 @@ public:
//============================================================================== //==============================================================================
/** Makes the font bold or non-bold. */ /** Makes the font bold or non-bold. */
void setBold (bool shouldBeBold); void setBold (bool shouldBeBold);
/** Returns a copy of this font with the bold attribute set. */
/** Returns a copy of this font with the bold attribute set.
If the font does not have a bold version, this will return the default font.
*/
Font boldened() const; Font boldened() const;
/** Returns true if the font is bold. */ /** Returns true if the font is bold. */
bool isBold() const noexcept; bool isBold() const noexcept;


+ 2
- 0
source/modules/juce_gui_basics/application/juce_Application.h View File

@@ -111,11 +111,13 @@ public:
static JUCEApplication* JUCE_CALLTYPE getInstance() noexcept; static JUCEApplication* JUCE_CALLTYPE getInstance() noexcept;
//============================================================================== //==============================================================================
#if DOXYGEN
/** Returns the application's name. */ /** Returns the application's name. */
virtual const String getApplicationName() = 0; virtual const String getApplicationName() = 0;
/** Returns the application's version number. */ /** Returns the application's version number. */
virtual const String getApplicationVersion() = 0; virtual const String getApplicationVersion() = 0;
#endif
/** Checks whether multiple instances of the app are allowed. /** Checks whether multiple instances of the app are allowed.


+ 2
- 2
source/modules/juce_gui_basics/components/juce_Component.h View File

@@ -443,7 +443,7 @@ public:
/** Changes the component's position and size. /** Changes the component's position and size.
The coordinates are relative to the top-left of the component's parent, or relative The coordinates are relative to the top-left of the component's parent, or relative
to the origin of the screen is the component is on the desktop.
to the origin of the screen if the component is on the desktop.
If this method changes the component's top-left position, it will make a synchronous If this method changes the component's top-left position, it will make a synchronous
call to moved(). If it changes the size, it will also make a call to resized(). call to moved(). If it changes the size, it will also make a call to resized().
@@ -459,7 +459,7 @@ public:
/** Changes the component's position and size. /** Changes the component's position and size.
The coordinates are relative to the top-left of the component's parent, or relative The coordinates are relative to the top-left of the component's parent, or relative
to the origin of the screen is the component is on the desktop.
to the origin of the screen if the component is on the desktop.
If this method changes the component's top-left position, it will make a synchronous If this method changes the component's top-left position, it will make a synchronous
call to moved(). If it changes the size, it will also make a call to resized(). call to moved(). If it changes the size, it will also make a call to resized().


+ 0
- 2
source/modules/juce_gui_basics/components/juce_Desktop.cpp View File

@@ -333,7 +333,6 @@ bool operator!= (const Desktop::Displays::Display& d1, const Desktop::Displays::
void Desktop::Displays::init (Desktop& desktop) void Desktop::Displays::init (Desktop& desktop)
{ {
findDisplays (desktop.getGlobalScaleFactor()); findDisplays (desktop.getGlobalScaleFactor());
jassert (displays.size() > 0);
} }
void Desktop::Displays::refresh() void Desktop::Displays::refresh()
@@ -342,7 +341,6 @@ void Desktop::Displays::refresh()
oldDisplays.swapWith (displays); oldDisplays.swapWith (displays);
init (Desktop::getInstance()); init (Desktop::getInstance());
jassert (displays.size() > 0);
if (oldDisplays != displays) if (oldDisplays != displays)
{ {


+ 4
- 4
source/modules/juce_gui_basics/drawables/juce_SVGParser.cpp View File

@@ -272,7 +272,7 @@ public:
if (parseNextNumber (d, num, false)) if (parseNextNumber (d, num, false))
{ {
const float angle = num.getFloatValue() * (180.0f / float_Pi);
const float angle = degreesToRadians (num.getFloatValue());
if (parseNextNumber (d, num, false)) if (parseNextNumber (d, num, false))
{ {
@@ -1221,15 +1221,15 @@ private:
} }
else if (t.startsWithIgnoreCase ("rotate")) else if (t.startsWithIgnoreCase ("rotate"))
{ {
trans = AffineTransform::rotation (numbers[0] / (180.0f / float_Pi), numbers[1], numbers[2]);
trans = AffineTransform::rotation (degreesToRadians (numbers[0]), numbers[1], numbers[2]);
} }
else if (t.startsWithIgnoreCase ("skewX")) else if (t.startsWithIgnoreCase ("skewX"))
{ {
trans = AffineTransform::shear (std::tan (numbers[0] * (float_Pi / 180.0f)), 0.0f);
trans = AffineTransform::shear (std::tan (degreesToRadians (numbers[0])), 0.0f);
} }
else if (t.startsWithIgnoreCase ("skewY")) else if (t.startsWithIgnoreCase ("skewY"))
{ {
trans = AffineTransform::shear (0.0f, std::tan (numbers[0] * (float_Pi / 180.0f)));
trans = AffineTransform::shear (0.0f, std::tan (degreesToRadians (numbers[0])));
} }
result = trans.followedBy (result); result = trans.followedBy (result);


+ 7
- 6
source/modules/juce_gui_basics/keyboard/juce_TextEditorKeyMapper.h View File

@@ -85,12 +85,6 @@ struct TextEditorKeyMapper
if (key.isKeyCode (KeyPress::pageDownKey)) return target.pageDown (isShiftDown); if (key.isKeyCode (KeyPress::pageDownKey)) return target.pageDown (isShiftDown);
} }
if (numCtrlAltCommandKeys < 2)
{
if (key.isKeyCode (KeyPress::backspaceKey)) return target.deleteBackwards (ctrlOrAltDown);
if (key.isKeyCode (KeyPress::deleteKey)) return target.deleteForwards (ctrlOrAltDown);
}
if (key == KeyPress ('c', ModifierKeys::commandModifier, 0) if (key == KeyPress ('c', ModifierKeys::commandModifier, 0)
|| key == KeyPress (KeyPress::insertKey, ModifierKeys::ctrlModifier, 0)) || key == KeyPress (KeyPress::insertKey, ModifierKeys::ctrlModifier, 0))
return target.copyToClipboard(); return target.copyToClipboard();
@@ -103,6 +97,13 @@ struct TextEditorKeyMapper
|| key == KeyPress (KeyPress::insertKey, ModifierKeys::shiftModifier, 0)) || key == KeyPress (KeyPress::insertKey, ModifierKeys::shiftModifier, 0))
return target.pasteFromClipboard(); return target.pasteFromClipboard();
// NB: checking for delete must happen after the earlier check for shift + delete
if (numCtrlAltCommandKeys < 2)
{
if (key.isKeyCode (KeyPress::backspaceKey)) return target.deleteBackwards (ctrlOrAltDown);
if (key.isKeyCode (KeyPress::deleteKey)) return target.deleteForwards (ctrlOrAltDown);
}
if (key == KeyPress ('a', ModifierKeys::commandModifier, 0)) if (key == KeyPress ('a', ModifierKeys::commandModifier, 0))
return target.selectAll(); return target.selectAll();


+ 6
- 0
source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp View File

@@ -490,6 +490,12 @@ int LookAndFeel_V2::getAlertWindowButtonHeight()
return 28; return 28;
} }
Font LookAndFeel_V2::getAlertWindowTitleFont()
{
Font messageFont = getAlertWindowMessageFont();
return messageFont.withHeight (messageFont.getHeight() * 1.1f).boldened();
}
Font LookAndFeel_V2::getAlertWindowMessageFont() Font LookAndFeel_V2::getAlertWindowMessageFont()
{ {
return Font (15.0f); return Font (15.0f);


+ 15
- 0
source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h View File

@@ -67,7 +67,22 @@ public:
void drawAlertBox (Graphics&, AlertWindow&, const Rectangle<int>& textArea, TextLayout&) override; void drawAlertBox (Graphics&, AlertWindow&, const Rectangle<int>& textArea, TextLayout&) override;
int getAlertBoxWindowFlags() override; int getAlertBoxWindowFlags() override;
int getAlertWindowButtonHeight() override; int getAlertWindowButtonHeight() override;
/** Override this function to supply a custom font for the alert window title.
This default implementation will use a boldened and slightly larger version
of the alert window message font.
@see getAlertWindowMessageFont.
*/
Font getAlertWindowTitleFont() override;
/** Override this function to supply a custom font for the alert window message.
This default implementation will use the default font with height set to 15.0f.
@see getAlertWindowTitleFont
*/
Font getAlertWindowMessageFont() override; Font getAlertWindowMessageFont() override;
Font getAlertWindowFont() override; Font getAlertWindowFont() override;
//============================================================================== //==============================================================================


+ 3
- 3
source/modules/juce_gui_basics/menus/juce_PopupMenu.cpp View File

@@ -1219,7 +1219,7 @@ public:
getLookAndFeel().drawPopupMenuSectionHeader (g, getLocalBounds(), getName()); getLookAndFeel().drawPopupMenuSectionHeader (g, getLocalBounds(), getName());
} }
void getIdealSize (int& idealWidth, int& idealHeight)
void getIdealSize (int& idealWidth, int& idealHeight) override
{ {
getLookAndFeel().getIdealPopupMenuItemSize (getName(), false, -1, idealWidth, idealHeight); getLookAndFeel().getIdealPopupMenuItemSize (getName(), false, -1, idealWidth, idealHeight);
idealHeight += idealHeight / 2; idealHeight += idealHeight / 2;
@@ -1698,9 +1698,9 @@ void PopupMenu::CustomComponent::setHighlighted (bool shouldBeHighlighted)
void PopupMenu::CustomComponent::triggerMenuItem() void PopupMenu::CustomComponent::triggerMenuItem()
{ {
if (HelperClasses::ItemComponent* const mic = dynamic_cast<HelperClasses::ItemComponent*> (getParentComponent()))
if (HelperClasses::ItemComponent* const mic = findParentComponentOfClass<HelperClasses::ItemComponent>())
{ {
if (HelperClasses::MenuWindow* const pmw = dynamic_cast<HelperClasses::MenuWindow*> (mic->getParentComponent()))
if (HelperClasses::MenuWindow* const pmw = mic->findParentComponentOfClass<HelperClasses::MenuWindow>())
{ {
pmw->dismissMenu (&mic->itemInfo); pmw->dismissMenu (&mic->itemInfo);
} }


+ 1
- 1
source/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp View File

@@ -135,7 +135,7 @@ static void addZenityArgs (StringArray& args, String& separator,
tokens.addTokens (filters, ";,|", "\""); tokens.addTokens (filters, ";,|", "\"");
for (int i = 0; i < tokens.size(); ++i) for (int i = 0; i < tokens.size(); ++i)
args.add ("--file-filter='" + tokens[i] + "'");
args.add ("--file-filter=" + tokens[i]);
} }
if (file.isDirectory()) if (file.isDirectory())


+ 42
- 0
source/modules/juce_gui_basics/native/juce_linux_Windowing.cpp View File

@@ -1881,6 +1881,9 @@ public:
{ {
if (LinuxComponentPeer* const otherPeer = dynamic_cast<LinuxComponentPeer*> (other)) if (LinuxComponentPeer* const otherPeer = dynamic_cast<LinuxComponentPeer*> (other))
{ {
if (otherPeer->styleFlags & windowIsTemporary)
return;
setMinimised (false); setMinimised (false);
Window newStack[] = { otherPeer->windowH, windowH }; Window newStack[] = { otherPeer->windowH, windowH };
@@ -2320,6 +2323,10 @@ public:
XEvent nextEvent; XEvent nextEvent;
ScopedXLock xlock; ScopedXLock xlock;
// if we have opengl contexts then just repaint them all
// regardless if this is really necessary
repaintOpenGLContexts ();
if (exposeEvent.window != windowH) if (exposeEvent.window != windowH)
{ {
Window child; Window child;
@@ -2509,6 +2516,28 @@ public:
return currentScaleFactor; return currentScaleFactor;
} }
//===============================================================================
void addOpenGLRepaintListener (Component* dummy)
{
if (dummy != nullptr)
glRepaintListeners.addIfNotAlreadyThere (dummy);
}
void removeOpenGLRepaintListener (Component* dummy)
{
if (dummy != nullptr)
glRepaintListeners.removeAllInstancesOf (dummy);
}
void repaintOpenGLContexts()
{
for (int i = 0; i < glRepaintListeners.size(); ++i)
{
if (Component* c = glRepaintListeners [i])
c->handleCommandMessage (0);
}
}
//============================================================================== //==============================================================================
bool dontRepaint; bool dontRepaint;
@@ -2668,6 +2697,7 @@ private:
BorderSize<int> windowBorder; BorderSize<int> windowBorder;
bool isAlwaysOnTop; bool isAlwaysOnTop;
double currentScaleFactor; double currentScaleFactor;
Array<Component*> glRepaintListeners;
enum { KeyPressEventType = 2 }; enum { KeyPressEventType = 2 };
struct MotifWmHints struct MotifWmHints
@@ -4125,6 +4155,18 @@ Rectangle<int> juce_LinuxScaledToPhysicalBounds(ComponentPeer* peer, const Recta
return retval; return retval;
} }
void juce_LinuxAddRepaintListener (ComponentPeer* peer, Component* dummy)
{
if (LinuxComponentPeer* linuxPeer = dynamic_cast<LinuxComponentPeer*> (peer))
linuxPeer->addOpenGLRepaintListener (dummy);
}
void juce_LinuxRemoveRepaintListener (ComponentPeer* peer, Component* dummy)
{
if (LinuxComponentPeer* linuxPeer = dynamic_cast<LinuxComponentPeer*> (peer))
linuxPeer->removeOpenGLRepaintListener (dummy);
}
//============================================================================== //==============================================================================
#if JUCE_MODAL_LOOPS_PERMITTED #if JUCE_MODAL_LOOPS_PERMITTED
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType, void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType,


+ 2
- 4
source/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp View File

@@ -218,8 +218,6 @@ void FileChooser::showPlatformDialog (Array<File>& results, const String& title_
info.customComponent->enterModalState(); info.customComponent->enterModalState();
} }
const StringRef separatorTokens (";,|");
const size_t filterSpaceNumChars = 2048; const size_t filterSpaceNumChars = 2048;
HeapBlock<WCHAR> filters; HeapBlock<WCHAR> filters;
filters.calloc (filterSpaceNumChars); filters.calloc (filterSpaceNumChars);
@@ -228,7 +226,7 @@ void FileChooser::showPlatformDialog (Array<File>& results, const String& title_
((filterSpaceNumChars - 1) * sizeof (WCHAR) - bytesWritten)); ((filterSpaceNumChars - 1) * sizeof (WCHAR) - bytesWritten));
for (int i = 0; i < filterSpaceNumChars; ++i) for (int i = 0; i < filterSpaceNumChars; ++i)
if (separatorTokens.text.indexOf ((juce_wchar) filters[i]) >= 0)
if (filters[i] == '|')
filters[i] = 0; filters[i] = 0;
OPENFILENAMEW of = { 0 }; OPENFILENAMEW of = { 0 };
@@ -255,7 +253,7 @@ void FileChooser::showPlatformDialog (Array<File>& results, const String& title_
if (isSaveDialogue) if (isSaveDialogue)
{ {
StringArray tokens; StringArray tokens;
tokens.addTokens (filter, separatorTokens, "\"'");
tokens.addTokens (filter, ";,", "\"'");
tokens.trim(); tokens.trim();
tokens.removeEmptyStrings(); tokens.removeEmptyStrings();


+ 3
- 0
source/modules/juce_gui_basics/widgets/juce_TableListBox.h View File

@@ -56,6 +56,9 @@ public:
The graphics context has its origin at the row's top-left, and your method The graphics context has its origin at the row's top-left, and your method
should fill the area specified by the width and height parameters. should fill the area specified by the width and height parameters.
Note that the rowNumber value may be greater than the number of rows in your
list, so be careful that you don't assume it's less than getNumRows().
*/ */
virtual void paintRowBackground (Graphics&, virtual void paintRowBackground (Graphics&,
int rowNumber, int rowNumber,


+ 11
- 9
source/modules/juce_gui_basics/windows/juce_AlertWindow.cpp View File

@@ -343,22 +343,24 @@ void AlertWindow::updateLayout (const bool onlyIncreaseSize)
const int titleH = 24; const int titleH = 24;
const int iconWidth = 80; const int iconWidth = 80;
const Font font (getLookAndFeel().getAlertWindowMessageFont());
LookAndFeel& lookAndFeel = getLookAndFeel();
const int wid = jmax (font.getStringWidth (text),
font.getStringWidth (getName()));
const Font messageFont (lookAndFeel.getAlertWindowMessageFont());
const int sw = (int) std::sqrt (font.getHeight() * wid);
const int wid = jmax (messageFont.getStringWidth (text),
messageFont.getStringWidth (getName()));
const int sw = (int) std::sqrt (messageFont.getHeight() * wid);
int w = jmin (300 + sw * 2, (int) (getParentWidth() * 0.7f)); int w = jmin (300 + sw * 2, (int) (getParentWidth() * 0.7f));
const int edgeGap = 10; const int edgeGap = 10;
const int labelHeight = 18; const int labelHeight = 18;
int iconSpace = 0; int iconSpace = 0;
AttributedString attributedText; AttributedString attributedText;
attributedText.append (getName(), font.withHeight (font.getHeight() * 1.1f).boldened());
attributedText.append (getName(), lookAndFeel.getAlertWindowTitleFont());
if (text.isNotEmpty()) if (text.isNotEmpty())
attributedText.append ("\n\n" + text, font);
attributedText.append ("\n\n" + text, messageFont);
attributedText.setColour (findColour (textColourId)); attributedText.setColour (findColour (textColourId));
@@ -383,18 +385,18 @@ void AlertWindow::updateLayout (const bool onlyIncreaseSize)
int buttonW = 40; int buttonW = 40;
for (int i = 0; i < buttons.size(); ++i) for (int i = 0; i < buttons.size(); ++i)
buttonW += 16 + buttons.getUnchecked(i)->getWidth();
buttonW += 16 + buttons.getUnchecked (i)->getWidth();
w = jmax (buttonW, w); w = jmax (buttonW, w);
h += (textBoxes.size() + comboBoxes.size() + progressBars.size()) * 50; h += (textBoxes.size() + comboBoxes.size() + progressBars.size()) * 50;
if (buttons.size() > 0) if (buttons.size() > 0)
h += 20 + buttons.getUnchecked(0)->getHeight();
h += 20 + buttons.getUnchecked (0)->getHeight();
for (int i = customComps.size(); --i >= 0;) for (int i = customComps.size(); --i >= 0;)
{ {
Component* c = customComps.getUnchecked(i);
Component* c = customComps.getUnchecked (i);
w = jmax (w, (c->getWidth() * 100) / 80); w = jmax (w, (c->getWidth() * 100) / 80);
h += 10 + c->getHeight(); h += 10 + c->getHeight();


+ 1
- 0
source/modules/juce_gui_basics/windows/juce_AlertWindow.h View File

@@ -437,6 +437,7 @@ public:
virtual int getAlertWindowButtonHeight() = 0; virtual int getAlertWindowButtonHeight() = 0;
virtual Font getAlertWindowTitleFont() = 0;
virtual Font getAlertWindowMessageFont() = 0; virtual Font getAlertWindowMessageFont() = 0;
virtual Font getAlertWindowFont() = 0; virtual Font getAlertWindowFont() = 0;
}; };


Loading…
Cancel
Save